diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c800a8..ca91c06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,14 +5,31 @@ if(MINGW) find_package(MinGW REQUIRED) endif() set(LIB 1) +set(LIBPROJECT 1) +set(PULT 1) set(USB 1) set(ICU 1) set(CRYPT 1) set(FFTW 1) -set(LIBPROJECT 1) set(PIP_LIBRARY pip) set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io" "console" "math" "code" "geo") set(PIP_INCLUDES) + +if (LIB) + if (WIN32) + set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) + else () + if(APPLE) + set(CMAKE_INSTALL_PREFIX /usr/local) + else() + set(CMAKE_INSTALL_PREFIX /usr) + endif() + endif () + message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") +else () + message(STATUS "Install to local \"bin\"") +endif () + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") foreach(F ${PIP_FOLDERS}) @@ -24,17 +41,21 @@ if(WIN32) set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}/pip") endif() -set(LIST_LIBS pip qad_utils qad_widgets qad_application qad_blockview qad_graphic qad_sql_table piqt cd_utils qcd_utils kx_utils piqt_utils touch_widgets qglview) -#set(LIST_LIBS pip) -foreach(L ${LIST_LIBS}) - add_subdirectory(${L}) - include_directories(${L}) -endforeach(L) +set(QAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/qad) + +add_subdirectory(pip) +add_subdirectory(qad) +set(_DIRS piqt piqt_utils cd_utils qcd_utils) +foreach(_D ${_DIRS}) + include_directories(${_D}) + add_subdirectory(${_D}) +endforeach(_D) if(WIN32) get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) foreach(PIP_LT ${PIP_LIBS_TARGETS}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pip/lib${PIP_LT}.dll" DESTINATION ${QTDIR}) endforeach() - install(FILES "FindMinGW.cmake" DESTINATION ${CMAKE_ROOT}/Modules) + set(CMAKES "FindMinGW.cmake" "QtProject.cmake") + install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules) endif() diff --git a/FindMinGW.cmake b/FindMinGW.cmake index a796fb7..c0c60dc 100644 --- a/FindMinGW.cmake +++ b/FindMinGW.cmake @@ -5,7 +5,7 @@ if(${MINGW}) find_path(MINGW_INCLUDE windows.h PATHS - EVN INCLUDE + ENV INCLUDE ${MINGW_DIR} ${MINGW_DIR}/i686-w64-mingw32 ${MINGW_DIR}/x86_64-w64-mingw32 @@ -15,8 +15,8 @@ if(${MINGW}) #if(NOT ${MINGW_INCLUDE}) MINGW_INCLUDE = ${MINGW_DIR}/include find_library(MINGW_LIB m HINTS ${MINGW_BIN}/../lib ${MINGW_INCLUDE}/../lib) get_filename_component(MINGW_LIB ${MINGW_LIB} PATH) - message(STATUS "Find MinGW binary path = ${MINGW_BIN}") - message(STATUS "Find MinGW include path = ${MINGW_INCLUDE}") - message(STATUS "Find MinGW library path = ${MINGW_LIB}") + message(STATUS "Found MinGW binary path = ${MINGW_BIN}") + message(STATUS "Found MinGW include path = ${MINGW_INCLUDE}") + message(STATUS "Found MinGW library path = ${MINGW_LIB}") endif() endif(${MINGW}) diff --git a/QtProject.cmake b/QtProject.cmake new file mode 100644 index 0000000..43c4e64 --- /dev/null +++ b/QtProject.cmake @@ -0,0 +1,30 @@ +set(QTVERSION 4) +find_package(Qt${QTVERSION} REQUIRED) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES}) + +macro(qt_project NAME _TYPE _LIBS _H_OUT _CPP_OUT) + project(${NAME}) + find_package(Qt4 REQUIRED) + include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES}) + file(GLOB ${_H_OUT} "./*.h") + file(GLOB CPPS "./*.cpp") + file(GLOB UIS "./*.ui") + file(GLOB RES "./*.qrc") + qt4_wrap_ui(CUIS ${UIS}) + qt4_wrap_cpp(CMOCS ${${_H_OUT}} OPTIONS -nw) + qt4_add_resources(CRES ${RES}) + set(${_CPP_OUT} ${CPPS}) + list(APPEND ${_CPP_OUT} ${CUIS}) + list(APPEND ${_CPP_OUT} ${CMOCS}) + list(APPEND ${_CPP_OUT} ${CRES}) + if ("_${_TYPE}" STREQUAL "_EXE") + add_executable(${PROJECT_NAME} ${${_H_OUT}} ${${_CPP_OUT}}) + else() + if ("_${_TYPE}" STREQUAL "_LIB") + add_library(${PROJECT_NAME} SHARED ${${_H_OUT}} ${${_CPP_OUT}}) + else() + message(FATAL_ERROR "You must specify \"EXE\" ot \"LIB\" by second argument of \"qt_project()\"!") + endif() + endif() + target_link_libraries(${PROJECT_NAME} ${_LIBS}) +endmacro() diff --git a/SDKMacros.cmake b/SDKMacros.cmake new file mode 100644 index 0000000..9ff3bbc --- /dev/null +++ b/SDKMacros.cmake @@ -0,0 +1,22 @@ + +macro(sdk_install _DIR _TARGET _H_FILES) + if (LIB) + if (WIN32) + if (NOT _H_FILES STREQUAL "") + #message("HFILES ${_H_FILES}") + install(FILES ${_H_FILES} DESTINATION ${MINGW_INCLUDE}/${_DIR}) + endif() + install(TARGETS ${_TARGET} DESTINATION ${MINGW_LIB}) + install(TARGETS ${_TARGET} DESTINATION ${MINGW_BIN}) + get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) + install(TARGETS ${_TARGET} DESTINATION ${QTDIR}) + else () + if (NOT _H_FILES STREQUAL "") + install(FILES ${_H_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${_DIR}) + endif() + install(TARGETS ${_TARGET} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) + endif () + else () + install(TARGETS ${_TARGET} DESTINATION bin) + endif () +endmacro() diff --git a/cd_utils/CMakeLists.txt b/cd_utils/CMakeLists.txt index 81d6422..7a0e8f5 100644 --- a/cd_utils/CMakeLists.txt +++ b/cd_utils/CMakeLists.txt @@ -7,7 +7,6 @@ if (MINGW) find_package(MinGW REQUIRED) endif() include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${PIP_INCLUDES}) -set(PULT_NAME "cd_pult") option(LIB "System install" 1) option(DEBUG "Build with -g3" 0) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") @@ -28,23 +27,7 @@ target_link_libraries(${PROJECT_NAME} ${PIP_LIBRARY}) add_executable(cdutilstest "cdutilstest.cpp" "cdtest.h") target_link_libraries(cdutilstest ${PIP_LIBRARY} ${PROJECT_NAME}) - if (LIB) - if (WIN32) - set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) - install(FILES ${HDRS_UTILS} DESTINATION ${MINGW_INCLUDE}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN}) - else () - if(APPLE) - set(CMAKE_INSTALL_PREFIX /usr/local) - else() - set(CMAKE_INSTALL_PREFIX /usr) - endif() - install(FILES ${HDRS_UTILS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) - install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) - endif () - message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") -else () - install(TARGETS ${PROJECT_NAME} DESTINATION bin) - message(STATUS "Install to local \"bin\"") +if (LIB) + include(SDKMacros) + sdk_install("" "${PROJECT_NAME}" "${HDRS_UTILS}") endif () diff --git a/make_libs.bat b/make_libs.bat index b1a56bf..2f95771 100644 --- a/make_libs.bat +++ b/make_libs.bat @@ -1,3 +1,3 @@ @echo off mkdir ../libs_build_win -cd ../libs_build_win && cmake_mgw ../libs && cmake_mgw ../libs && make install -j8 && cd ../libs && pause +cd ../libs_build_win && cmake_mgw ../libs && make install -j8 && cd ../libs && pause diff --git a/piqt/CMakeLists.txt b/piqt/CMakeLists.txt index 05adae8..c615ad8 100644 --- a/piqt/CMakeLists.txt +++ b/piqt/CMakeLists.txt @@ -1,41 +1,13 @@ project(piqt) cmake_minimum_required(VERSION 2.6) -option(LIB "System install" 0) -find_package(Qt4 REQUIRED) -if(LIBPROJECT) - include(PIPMacros) -else() +if(NOT LIBPROJECT) find_package(PIP REQUIRED) endif() -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${PIP_INCLUDES} ${QT_INCLUDES}) -file(GLOB HDRS "*.h") -file(GLOB CPPS "*.cpp") -if(DEFINED ENV{QNX_HOST}) - add_library(${PROJECT_NAME} STATIC ${CPPS}) -else() - add_library(${PROJECT_NAME} SHARED ${CPPS}) -endif() -set(LIBS ${QT_QTCORE_LIBRARY} ${PIP_LIBRARY} qad_utils) -target_link_libraries(${PROJECT_NAME} ${LIBS}) -if(LIB) - if(WIN32) - set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) - install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN}) - get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) - install(TARGETS ${PROJECT_NAME} DESTINATION ${QTDIR}) - else() - if(APPLE) - set(CMAKE_INSTALL_PREFIX /usr/local) - else() - set(CMAKE_INSTALL_PREFIX /usr) - endif() - install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) - install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) - endif() - message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") -else() - install(TARGETS ${PROJECT_NAME} DESTINATION bin) - message(STATUS "Install to local \"bin\"") +find_package(QAD REQUIRED) +include_directories(${PIP_INCLUDES} ${QAD_INCLUDES}) +set(LIBS ${PIP_LIBRARY} ${QAD_UTILS_LIBRARY}) +qt_project(${PROJECT_NAME} "LIB" "${LIBS}" H CPP) +if(LIBPROJECT) + include(SDKMacros) + sdk_install("" "${PROJECT_NAME}" "${H}") endif() diff --git a/piqt_utils/CMakeLists.txt b/piqt_utils/CMakeLists.txt index 077d298..3efaefc 100644 --- a/piqt_utils/CMakeLists.txt +++ b/piqt_utils/CMakeLists.txt @@ -3,21 +3,22 @@ cmake_minimum_required(VERSION 2.6) if(MINGW) find_package(MinGW REQUIRED) endif() -find_package(Qt4 REQUIRED) -if(LIBPROJECT) - include(PIPMacros) -else() - find_package(PIP REQUIRED) -endif() -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${PIP_INCLUDES} ${QT_INCLUDES}) option(LIB "System install" 0) option(DEBUG "Build with -g3" 0) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") if(DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") endif() -set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${PIP_LIBRARY} qad_widgets qad_utils qad_blockview) +if(LIBPROJECT) + include(PIPMacros) + include(SDKMacros) +else() + find_package(PIP REQUIRED) +endif() +find_package(QAD REQUIRED) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES} ${PIP_INCLUDES} ${QAD_INCLUDES}) pip_code_model(CCM "../pip/src_main/io/piiodevice.h" "../pip/src_main/io/pipacketextractor.h" OPTIONS "-DPIP_EXPORT" "-Es") +set(LIBS ${QAD_WIDGETS_LIBRARY} ${QAD_UTILS_LIBRARY} ${QAD_BLOCKVIEW_LIBRARY} ${PIP_LIBRARY}) #message(STATUS "pip_code_model for iodevice = ${CCM}") #message(STATUS "pip_INCLUDES = ${PIP_INCLUDES}") file(GLOB CPPS_UTILS "piqt_*.cpp") @@ -58,29 +59,31 @@ if (NOT DEFINED ENV{QNX_HOST}) add_executable(piconnectionedit "piconnedit_main.cpp" ${RESS}) target_link_libraries(piconnectionedit ${LIBS} ${PROJECT_NAME}) endif() -if(LIB) - if(WIN32) - set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) - install(FILES ${HDRS_UTILS} DESTINATION ${MINGW_INCLUDE}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN}) - get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) - install(TARGETS ${PROJECT_NAME} DESTINATION ${QTDIR}) - else() - if(APPLE) - set(CMAKE_INSTALL_PREFIX /usr/local) - else() - set(CMAKE_INSTALL_PREFIX /usr) - endif() - install(FILES ${HDRS_UTILS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) - install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) - endif() - message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") -else() - install(TARGETS ${PROJECT_NAME} DESTINATION bin) - message(STATUS "Install to local \"bin\"") -endif() -if(NOT DEFINED ENV{QNX_HOST}) - install(TARGETS pidumper DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - install(TARGETS piconnectionedit DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) -endif() +set(_TARGETS ${PROJECT_NAME} pidumper piconnectionedit) +sdk_install("" "${TARGETS}" "${HDRS_UTILS}") +#if(LIB) +# if(WIN32) +# set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) +# install(FILES ${HDRS_UTILS} DESTINATION ${MINGW_INCLUDE}) +# install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB}) +# install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN}) +# get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) +# install(TARGETS ${PROJECT_NAME} DESTINATION ${QTDIR}) +# else() +# if(APPLE) +# set(CMAKE_INSTALL_PREFIX /usr/local) +# else() +# set(CMAKE_INSTALL_PREFIX /usr) +# endif() +# install(FILES ${HDRS_UTILS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) +# install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) +# endif() +# message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") +#else() +# install(TARGETS ${PROJECT_NAME} DESTINATION bin) +# message(STATUS "Install to local \"bin\"") +#endif() +#if(NOT DEFINED ENV{QNX_HOST}) +# install(TARGETS pidumper DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +# install(TARGETS piconnectionedit DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +#endif() diff --git a/qad/CMakeLists.txt b/qad/CMakeLists.txt new file mode 100644 index 0000000..74e33ba --- /dev/null +++ b/qad/CMakeLists.txt @@ -0,0 +1,72 @@ +project(qad) +cmake_minimum_required(VERSION 2.6) +include(../SDKMacros.cmake) +include(../QtProject.cmake) +find_package(OpenGL REQUIRED) +if (MINGW) + find_package(MinGW REQUIRED) +endif() +#include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES}) +option(LIB "System install" 0) +option(DEBUG "Build with -g3" 0) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") +if (DEBUG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") +endif () +#set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES} qad_widgets qad_utils) +if (NOT LIBPROJECT) + if (LIB) + if (WIN32) + set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) + else () + if(APPLE) + set(CMAKE_INSTALL_PREFIX /usr/local) + else() + set(CMAKE_INSTALL_PREFIX /usr) + endif() + endif () + message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") + else () + message(STATUS "Install to local \"bin\"") + endif () +endif() +set(CMAKES "FindQAD.cmake") +install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules) + +macro(qad_install _TARGET _H_FILES) + sdk_install(qad "${_TARGET}" "${_H_FILES}") +endmacro() + +macro(qad_plugin NAME _LIBS) + project(qad_${NAME}_plugin) + include_directories("..") + set(LIBS ${_${NAME}_LIBS} qad_${NAME} "${_LIBS}") + #message(${_${NAME}_PLUGIN_LIBS}) + add_definitions(-DQT_PLUGIN) + add_definitions(-DQT_NO_DEBUG) + add_definitions(-DQT_SHARED) + add_definitions(-DQDESIGNER_EXPORT_WIDGETS) + file(GLOB PMOCS "./*.h") + file(GLOB PCPPS "./*.cpp") + qt4_wrap_cpp(PCMOCS ${PMOCS} OPTIONS -nw) + add_library(${PROJECT_NAME} SHARED ${PCMOCS} ${PCPPS} ${PMOCS}) + target_link_libraries(${PROJECT_NAME} ${LIBS} ${QT_QTDESIGNER_LIBRARY}) + install(TARGETS ${PROJECT_NAME} DESTINATION ${QT_PLUGINS_DIR}/designer) +endmacro() + +macro(qad_project NAME _LIBS) + qt_project(qad_${NAME} "LIB" "${_LIBS}" _H _CPP) + message(STATUS "Building ${PROJECT_NAME}") + qad_install(${PROJECT_NAME} "${_H}") + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin") + set(_${NAME}_PLUGIN_LIBS "${_LIBS}") + add_subdirectory(plugin) + endif() +endmacro() + +set(DIRS utils widgets application blockview graphic sql_table touch_widgets) +foreach(D ${DIRS}) + include_directories(${D}) + add_subdirectory(${D}) +endforeach(D) + diff --git a/qad/FindQAD.cmake b/qad/FindQAD.cmake new file mode 100644 index 0000000..c393515 --- /dev/null +++ b/qad/FindQAD.cmake @@ -0,0 +1,31 @@ +include(QtProject) +set(_SEARCH_DIR) +if(WIN32) + find_package(MinGW REQUIRED) + set(_SEARCH_DIR ${MINGW_LIB}) + set(QAD_INCLUDES ${MINGW_INCLUDE}/qad) +else() + set(_DIR_ "/usr") + if(APPLE) + set(_DIR_ "/usr/local") + endif() + set(_SEARCH_DIR ${_DIR_}/lib/) + set(QAD_INCLUDES ${_DIR_}/include/qad) +endif() +set(_QAD_LIBS utils widgets application blockview graphic sql_table touch_widgets) +if(LIBPROJECT) + set(QAD_INCLUDES) +endif() +foreach(_Q ${_QAD_LIBS}) + string(TOUPPER ${_Q} _QU) + if(LIBPROJECT) + set(QAD_${_QU}_LIBRARY qad_${_Q}) + list(APPEND QAD_INCLUDES ${QAD_DIR}/${_Q}) + else() + find_library(QAD_${_QU}_LIBRARY qad_${_Q} ${_SEARCH_DIR}) + endif() + #message(STATUS "Library ${_Q} (${_QU}) -> ${QAD_${_QU}_LIBRARY} found in ${_SEARCH_DIR}") +endforeach() +if(NOT LIBPROJECT) + message(STATUS "Found QAD") +endif() diff --git a/qad/QADConfig.cmake b/qad/QADConfig.cmake new file mode 100644 index 0000000..b80e857 --- /dev/null +++ b/qad/QADConfig.cmake @@ -0,0 +1 @@ +include(${QAD_DIR}/FindQAD.cmake) diff --git a/qad/application/CMakeLists.txt b/qad/application/CMakeLists.txt new file mode 100644 index 0000000..72e9256 --- /dev/null +++ b/qad/application/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} qad_widgets) +qad_project(application "${LIBS}") diff --git a/qad/application/edockwidget.cpp b/qad/application/edockwidget.cpp new file mode 100644 index 0000000..7bca8f5 --- /dev/null +++ b/qad/application/edockwidget.cpp @@ -0,0 +1,51 @@ +#include "edockwidget.h" +#include + + +void EDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features) { + btn_dock->setVisible(features.testFlag(DockWidgetFloatable)); + btn_hide->setVisible(features.testFlag(DockWidgetClosable)); + QDockWidget::setFeatures(features); +} + + +void EDockWidget::init() { + header = new QFrame(); + header->setFrameShape(QFrame::StyledPanel); + QBoxLayout * lay = new QBoxLayout(features().testFlag(QDockWidget::DockWidgetVerticalTitleBar) ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); + lay->setContentsMargins(2, 2, 2, 2); + lay->setSpacing(2); + lbl_icon = new QLabel(); + lbl_icon->setPixmap(windowIcon().pixmap(QSize(24, 24))); + lbl_icon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + lbl_title = new QLabel(windowTitle()); + lbl_title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + btn_dock = new QToolButton(); + //btn_dock->setIconSize(QSize(16, 16)); + int btn_wh = style()->pixelMetric(QStyle::PM_SmallIconSize); + QSize icon_size(btn_wh, btn_wh); + btn_wh += 2 * style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this); + QSize btn_size(btn_wh, btn_wh); + btn_dock->setIcon(style()->standardIcon(QStyle::SP_TitleBarNormalButton)); + btn_dock->setIconSize(icon_size); + btn_dock->setFixedSize(btn_size); + btn_dock->setAutoRaise(true); + btn_dock->setFocusPolicy(Qt::NoFocus); + btn_dock->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + btn_hide = new QToolButton(); + //btn_hide->setIconSize(QSize(16, 16)); + btn_hide->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton)); + btn_hide->setIconSize(icon_size); + btn_hide->setFixedSize(btn_size); + btn_hide->setAutoRaise(true); + btn_hide->setFocusPolicy(Qt::NoFocus); + btn_hide->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(btn_dock, SIGNAL(clicked(bool)), this, SLOT(dockClicked())); + connect(btn_hide, SIGNAL(clicked(bool)), this, SLOT(hide())); + lay->addWidget(lbl_icon); + lay->addWidget(lbl_title); + lay->addWidget(btn_dock); + lay->addWidget(btn_hide); + header->setLayout(lay); + setTitleBarWidget(header); +} diff --git a/qad/application/edockwidget.h b/qad/application/edockwidget.h new file mode 100644 index 0000000..cdf2501 --- /dev/null +++ b/qad/application/edockwidget.h @@ -0,0 +1,37 @@ +#ifndef EDOCKWIDGET_H +#define EDOCKWIDGET_H + +#include +#include +#include +#include +#include +#include +#include + + +class EDockWidget: public QDockWidget +{ + Q_OBJECT +public: + explicit EDockWidget(const QString & title, QWidget * parent = 0, Qt::WindowFlags flags = 0): QDockWidget(title, parent, flags) {init();} + explicit EDockWidget(QWidget * parent = 0, Qt::WindowFlags flags = 0): QDockWidget(parent, flags) {init();} + ~EDockWidget() {delete btn_hide; delete btn_dock; delete lbl_title; delete lbl_icon; delete header;} + + void setFeatures(QDockWidget::DockWidgetFeatures features); + void setWindowTitle(const QString & title) {lbl_title->setText(title); QDockWidget::setWindowTitle(title);} + void setWindowIcon(const QIcon & icon) {lbl_icon->setPixmap(icon.pixmap(QSize(24, 24))); QDockWidget::setWindowIcon(icon);} + +private: + void init(); + + QFrame * header; + QLabel * lbl_title, * lbl_icon; + QToolButton * btn_hide, * btn_dock; + +private slots: + void dockClicked() {setFloating(!isFloating());} + +}; + +#endif // EDOCKWIDGET_H diff --git a/qad/application/emainwindow.cpp b/qad/application/emainwindow.cpp new file mode 100644 index 0000000..030a67f --- /dev/null +++ b/qad/application/emainwindow.cpp @@ -0,0 +1,333 @@ +/* + Peri4 Paint + Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "emainwindow.h" +#include +#include +#include + + +EMainWindow::EMainWindow(QWidget * parent): QMainWindow(parent), action_show_all_tools(this), action_hide_all_tools(this), +action_show_all_docks(this), action_hide_all_docks(this), first_show(true) { + qRegisterMetaType("Qt::DockWidgetArea"); + action_show_all_tools.setText(trUtf8("Show all")); + action_show_all_docks.setText(trUtf8("Show all")); + action_hide_all_tools.setText(trUtf8("Hide all")); + action_hide_all_docks.setText(trUtf8("Hide all")); + action_show_all_tools.setIcon(QIcon(":/icons/layer-visible-on.png")); + action_show_all_docks.setIcon(QIcon(":/icons/layer-visible-on.png")); + action_hide_all_tools.setIcon(QIcon(":/icons/layer-visible-off.png")); + action_hide_all_docks.setIcon(QIcon(":/icons/layer-visible-off.png")); + setChanged(false); + initMenus(); + tid = startTimer(200); +} + + +EMainWindow::~EMainWindow() { + saveSession(); +} + + +void EMainWindow::showEvent(QShowEvent * e) { + QWidget::showEvent(e); + initMenus(); + if (!first_show) return; + first_show = false; + QList docks(findChildren()); + foreach (QDockWidget * d, docks) { + connect(d, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(changedDock())); + connect(d, SIGNAL(topLevelChanged(bool)), this, SLOT(changedDock())); + } + changedDock(); +} + + +void EMainWindow::closeEvent(QCloseEvent * e) { + if (!checkSave()) e->ignore(); +} + + +bool EMainWindow::eventFilter(QObject * o, QEvent * e) { + //qDebug() << o << e; + if (tbars.contains((QTabBar*)o) && e->type() == QEvent::MouseButtonDblClick) { + int tab = ((QTabBar*)o)->tabAt(((QMouseEvent * )e)->pos()); + if (tab >= 0) { + QDockWidget * dock = (QDockWidget * )(((QTabBar*)o)->tabData(tab).toULongLong()); + if (dock != 0) { + dock->setFloating(true); + } + } + } + if (e->type() == QEvent::Show || e->type() == QEvent::Hide || e->type() == QEvent::ChildAdded || e->type() == QEvent::ChildRemoved || e->type() == QEvent::MouseButtonPress) { + if (tbars.contains((QTabBar*)o) || tdocks.contains((QDockWidget*)o)) { + if (e->type() == QEvent::MouseButtonPress) { + if (((QMouseEvent*)e)->button() == Qt::RightButton) { + bool popup = tbars.contains((QTabBar*)o); + if (tdocks.contains((QDockWidget*)o)) + popup = popup || ((QDockWidget*)o)->titleBarWidget()->geometry().contains(((QMouseEvent*)e)->pos()); + if (popup) { + createPopupMenu()->popup(((QMouseEvent*)e)->globalPos()); + return true; + } + } + } + if (e->type() == QEvent::Show || e->type() == QEvent::Hide /*|| e->type() == QEvent::ChildAdded || e->type() == QEvent::ChildRemoved*/) { + //qDebug() << "filter"; + //QMetaObject::invokeMethod(this, "changedDock", Qt::QueuedConnection); + changedDock(); + } + } + } + return QMainWindow::eventFilter(o, e); +} + + +void EMainWindow::timerEvent(QTimerEvent * e) { + if (e->timerId() == tid) { + changedDock(); + return; + } + QMainWindow::timerEvent(e); +} + + +QMenu * EMainWindow::createPopupMenu() { + QMenu * menuPopup = new QMenu; + QWidgetAction * wa; + QLabel * lbl; + QAction * a; + QFont f; + f.setBold(true); + // Toolbars + QList tools = findChildren(); + if (!tools.isEmpty()) { + wa = new QWidgetAction(menuPopup); + lbl = new QLabel(); + lbl->setFrameShape(QFrame::StyledPanel); + lbl->setFrameShadow(QFrame::Sunken); + lbl->setText(trUtf8("Toolbars")); + lbl->setFont(f); + lbl->setAlignment(Qt::AlignCenter); + wa->setDefaultWidget(lbl); + menuPopup->addAction(wa); + foreach (QToolBar * i, tools) { + if (i->property("ribbon").toBool()) continue; + a = new QAction(i->windowTitle(), menuPopup); + a->setCheckable(true); + a->setChecked(!i->isHidden()); + a->setIcon(i->windowIcon()); + connect(a, SIGNAL(toggled(bool)), i, SLOT(setVisible(bool))); + menuPopup->addAction(a); + }; + menuPopup->addSeparator(); + menuPopup->addAction(&action_show_all_tools); + menuPopup->addAction(&action_hide_all_tools); + } + // Docks + QList docks = findChildren(); + if (!docks.isEmpty()) { + wa = new QWidgetAction(menuPopup); + lbl = new QLabel(); + lbl->setFrameShape(QFrame::StyledPanel); + lbl->setFrameShadow(QFrame::Sunken); + lbl->setText(trUtf8("Docks")); + lbl->setFont(f); + lbl->setAlignment(Qt::AlignCenter); + wa->setDefaultWidget(lbl); + menuPopup->addAction(wa); + foreach (QDockWidget * i, docks) { + if (i->property("ribbon").toBool()) continue; + a = new QAction(i->windowTitle(), menuPopup); + a->setCheckable(true); + a->setChecked(!i->isHidden()); + a->setIcon(i->windowIcon()); + connect(a, SIGNAL(toggled(bool)), i, SLOT(setVisible(bool))); + menuPopup->addAction(a); + }; + menuPopup->addSeparator(); + menuPopup->addAction(&action_show_all_docks); + menuPopup->addAction(&action_hide_all_docks); + } + return menuPopup; +} + + +void EMainWindow::initMenus() { + action_show_all_tools.disconnect(); + action_hide_all_tools.disconnect(); + action_show_all_docks.disconnect(); + action_hide_all_docks.disconnect(); + + QList tools = findChildren(); + foreach (QToolBar * i, tools) { + if (i->property("ribbon").toBool()) continue; + i->toggleViewAction()->setIcon(i->windowIcon()); + connect(&action_show_all_tools, SIGNAL(triggered(bool)), i, SLOT(show())); + connect(&action_hide_all_tools, SIGNAL(triggered(bool)), i, SLOT(hide())); + } + + QList docks = findChildren(); + foreach (QDockWidget * i, docks) { + if (i->property("ribbon").toBool()) continue; + i->toggleViewAction()->setIcon(i->windowIcon()); + connect(&action_show_all_docks, SIGNAL(triggered(bool)), i, SLOT(show())); + connect(&action_hide_all_docks, SIGNAL(triggered(bool)), i, SLOT(hide())); + } + + QList actions = findChildren(); + foreach (QAction * i, actions) + i->setIconVisibleInMenu(true); + addActions(actions); +} + + +void EMainWindow::initSession() { + connect(&session, SIGNAL(loading(QPIConfig & )), this, SLOT(sessionLoading(QPIConfig & ))); + connect(&session, SIGNAL(saving(QPIConfig & )), this, SLOT(sessionSaving(QPIConfig & ))); + session.addEntry("EMainWindow", this); +} + + +void EMainWindow::saveSession() { + session.save(); +} + + +void EMainWindow::loadSession() { + session.load(); +} + + +bool EMainWindow::checkSave() { + if (!isWindowModified()) return true; + return saveFile(true); +} + + +void EMainWindow::changedDock() { + if (isHidden()) return; + QList tabs(findChildren()); + QList docks = findChildren(); + QSet docks_tabs; + QDockWidget * dock; +// qDebug() << "### change"; + foreach (QTabBar * t, tabs) { + if (!t->objectName().isEmpty() || t->isHidden()) continue; + if (!tbars.contains(t)) { + tbars << t; + connect(t, SIGNAL(tabCloseRequested(int)), this, SLOT(closeDock(int))); + t->installEventFilter(this); + t->setIconSize(dockTabsIconSIze()); + t->setTabsClosable(true); + } +// qDebug() << "tab" << t << t->count(); + for (int i = 0; i < t->count(); ++i) { + dock = (QDockWidget * )t->tabData(i).toULongLong(); + //qDebug() << i << t->tabData(i); + if (dock == 0) continue; + t->setTabIcon(i, dock->windowIcon()); + docks_tabs << dock; + } + } + + foreach (QDockWidget * d, docks) { + if (d->titleBarWidget() == 0) continue; + QWidget * ctb = d->titleBarWidget(); + if (!d->property("__titleWidget").isValid()) { + d->setProperty("__titleWidget", qulonglong(ctb)); + QWidget * ntb = new QWidget(); + int m = style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin); + ntb->setLayout(new QBoxLayout(QBoxLayout::BottomToTop)); + ntb->layout()->setContentsMargins(m, m, 0, 0); + d->setProperty("__titleEmptyWidget", qulonglong(ntb)); + } + if (!tdocks.contains(d)) { + tdocks << d; +// qDebug() << "connect" << d; +// connect(d, SIGNAL(destroyed(QObject*)), this, SLOT(changedDockClose(QObject*)), Qt::UniqueConnection); + d->installEventFilter(this); + } + //d->titleBarWidget()->setHidden(docks_tabs.contains(d)); + if (tabifiedDockWidgets(d).isEmpty()) { + if (d->titleBarWidget() != (QWidget * )(d->property("__titleWidget").toULongLong())) + d->setTitleBarWidget((QWidget * )(d->property("__titleWidget").toULongLong())); + } else { + if (d->titleBarWidget() != (QWidget * )(d->property("__titleEmptyWidget").toULongLong())) { + d->setTitleBarWidget((QWidget * )(d->property("__titleEmptyWidget").toULongLong())); + d->layout()->setContentsMargins(0, 20, 0, 0); + } + } + } +} + + +//void EMainWindow::changedDockClose(QObject * dock) { +// qDebug() << "changedDockClose" << dock; +// if (!dock) return; +// foreach (QTabBar * t, tbars) { +// for (int i = 0; i < t->count(); ++i) +// if (t->tabData(i).toULongLong() == (qulonglong)dock) { +// t->removeTab(i); +// break; +// } +// } +//} + + +void EMainWindow::closeDock(int index) { + QDockWidget * dock = (QDockWidget * )((QTabBar*)sender())->tabData(index).toULongLong(); + if (dock == 0) return; + dock->close(); +} + + +void EMainWindow::newFile() { + if (!checkSave()) return; + reset(true); + setWindowModified(false); +} + + +void EMainWindow::openFile() { + if (!checkSave()) return; + QString ret = QFileDialog::getOpenFileName(this, trUtf8("Select file to open"), file_name, loadFilter()); + if (ret.isEmpty()) return; + load(ret); +} + + +bool EMainWindow::saveFile(bool ask) { + if (ask) { + int ret = QMessageBox::question(this, windowTitle(), trUtf8("Save changes%1?").arg(!file_name.isEmpty() ? (trUtf8(" in") + " \"" + file_name + "\"") : ""), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save); + if (ret == QMessageBox::Cancel) return false; + if (ret == QMessageBox::Save) return saveFile(); + return true; + } + if (file_name.isEmpty()) return saveAsFile(); + save(file_name); + return true; +} + + +bool EMainWindow::saveAsFile() { + QString ret = QFileDialog::getSaveFileName(this, trUtf8("Select file to save"), file_name, saveFilter()); + if (ret.isEmpty()) return false; + save(ret); + return true; +} diff --git a/qad/application/emainwindow.h b/qad/application/emainwindow.h new file mode 100644 index 0000000..0d235a2 --- /dev/null +++ b/qad/application/emainwindow.h @@ -0,0 +1,109 @@ +#ifndef EMAINWINDOW_H +#define EMAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "session_manager.h" +#include "ribbon.h" + +class UAction: public QAction { + Q_OBJECT +public: + UAction(int ind,const QString & text, QObject * parent): QAction(text, parent) { + index = ind; + connect(this, SIGNAL(triggered()), this, SLOT(triggered())); + connect(this, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + connect(this, SIGNAL(hovered()), this, SLOT(hovered())); + } + UAction(int ind, const QIcon & icon, const QString & text, QObject * parent): QAction(icon, text, parent) { + index = ind; + connect(this, SIGNAL(triggered()), this, SLOT(triggered())); + connect(this, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + connect(this, SIGNAL(hovered()), this, SLOT(hovered())); + } +public slots: + void show() {setVisible(true);} + void hide() {setVisible(false);} + void setCheckedTrue() {setChecked(true);} + void setCheckedFalse() {setChecked(false);} +private: + int index; +private slots: + void triggered() {emit itriggered(this, index);} + void toggled(bool t) {emit itoggled(t, this, index);} + void hovered() {emit ihovered(this);} +signals: + void itriggered(QAction *, int); + void itoggled(bool, QAction *, int); + void ihovered(QAction * action); +}; + + +class EMainWindow: public QMainWindow +{ + Q_OBJECT +public: + EMainWindow(QWidget * parent = 0); + ~EMainWindow(); + + virtual void reset(bool full = false) {} + virtual bool load(const QString & path) {return true;} + virtual bool save(const QString & path) {return true;} + + void addSeparator() {} + +protected: + // Qt`s overloaded + void showEvent(QShowEvent * ); + void closeEvent(QCloseEvent * ); + bool eventFilter(QObject * o, QEvent * e); + void timerEvent(QTimerEvent * e); + QMenu * createPopupMenu(); + + void init(const QString & config) {session.setFile(config); initMenus(); initSession(); loadSession();} + void initMenus(); + void initSession(); + virtual void saveSession(); + virtual void loadSession(); + virtual QSize dockTabsIconSIze() const {return iconSize();} + virtual QString loadFilter() {return "All files(*)";} + virtual QString saveFilter() {return "All files(*)";} + + bool checkSave(); + void setChanged(bool yes = true) {isChanged = yes; setWindowModified(yes);} + + QAction action_show_all_tools, action_hide_all_tools, action_show_all_docks, action_hide_all_docks; + QString file_name, title_src; + QList tbars; + QList tdocks; + SessionManager session; + bool isChanged, first_show; + int tid; + +private slots: + void changedDock(); +// void changedDockClose(QObject * dock); + void closeDock(int index); + virtual void sessionLoading(QPIConfig & conf) {} + virtual void sessionSaving(QPIConfig & conf) {} + +public slots: + void changed() {setChanged(true);} + void newFile(); + void openFile(); + bool saveFile(bool ask = false); + bool saveAsFile(); + +signals: + +}; + +#endif // MAINWINDOW_H diff --git a/qad/application/etabwidget.cpp b/qad/application/etabwidget.cpp new file mode 100644 index 0000000..4da9dc3 --- /dev/null +++ b/qad/application/etabwidget.cpp @@ -0,0 +1,104 @@ +#include "etabwidget.h" + + +ETabWidget::ETabWidget(QWidget* parent): QTabWidget(parent) { + tabBar()->setMouseTracking(true); + tabBar()->installEventFilter(this); +} + + +void ETabWidget::retranslate() { + for (int i = 0; i < buttons.size(); ++i) + buttons[i].toolTip = QApplication::translate("MainWindow", buttons[i].srcToolTip.toUtf8(), 0/*, QCoreApplication::UnicodeUTF8*/); + QList bl = findChildren(); + foreach (QToolButton * i, bl) + i->setToolTip(QApplication::translate("MainWindow", i->property("sourceToolTip").toString().toUtf8(), 0/*, QCoreApplication::UnicodeUTF8*/)); +} + + +int ETabWidget::addTab(QWidget * page, const QIcon & icon, const QString & label) { + int ret = QTabWidget::addTab(page, icon, label); + QWidget * w = new QWidget(); + w->setLayout(new QBoxLayout(QBoxLayout::RightToLeft)); + w->layout()->setContentsMargins(0, 0, 0, 0); + w->layout()->setSpacing(2); + QToolButton * b; + foreach (const TabButton & i, buttons) { + b = new QToolButton(); + b->setToolTip(i.toolTip); + b->setIconSize(QSize(16, 16)); + b->setIcon(i.icon); + //b->setFlat(true); + b->setProperty("sourceToolTip", i.toolTip); + b->setProperty("buttonRole", i.role); + connect(b, SIGNAL(clicked(bool)), this, SLOT(buttonClicked())); + w->layout()->addWidget(b); + b->setVisible(i.visible); + } + tabBar()->setTabButton(ret, QTabBar::RightSide, w); + return ret; +} + + +void ETabWidget::setButtonVisible(int role, bool yes) { + QList bl = findChildren(); + foreach (QToolButton * i, bl) + if (i->property("buttonRole").toInt() == role) + i->setVisible(yes); + QWidget * w; + for (int i = 0; i < buttons.size(); ++i) { + if (buttons[i].role == role) + buttons[i].visible = yes; + w = tabBar()->tabButton(i, QTabBar::RightSide); + if (w != 0) w->adjustSize(); + } + tabBar()->adjustSize(); +} + +/* +void ETabWidget::removeTab(int index) { + tbs.removeAll(qobject_cast(tabBar()->tabButton(index, QTabBar::RightSide)->layout()->itemAt(1)->widget())); + tbs.removeAll(qobject_cast(tabBar()->tabButton(index, QTabBar::RightSide)->layout()->itemAt(0)->widget())); + QTabWidget::removeTab(index); +} +*/ + +bool ETabWidget::eventFilter(QObject * o, QEvent * e) { + static int prev = -1; + if (e->type() == QEvent::MouseMove) { + QTabBar * t = qobject_cast(o); + if (t == 0) return QTabWidget::eventFilter(o, e); + for (int i = 0; i < count(); ++i) + if (t->tabRect(i).contains(((QMouseEvent * )e)->pos())) { + if (i != prev) { + prev = i; + emit tabHovered(i); + } + return QTabWidget::eventFilter(o, e); + } + if (-1 != prev) { + prev = -1; + emit tabHovered(-1); + } + } + if (e->type() == QEvent::Leave) { + if (-1 != prev) { + prev = -1; + emit tabHovered(-1); + } + } + return QTabWidget::eventFilter(o, e); +} + + +void ETabWidget::buttonClicked() { + QToolButton * s = qobject_cast(sender()); + if (s == 0) return; + QWidget * pw = s->parentWidget(); + if (pw == 0) return; + for (int i = 0; i < count(); ++i) + if (tabBar()->tabButton(i, QTabBar::RightSide) == pw) { + emit tabButtonClicked(i, s->property("buttonRole").toInt()); + return; + } +} diff --git a/qad/application/etabwidget.h b/qad/application/etabwidget.h new file mode 100644 index 0000000..ad9f304 --- /dev/null +++ b/qad/application/etabwidget.h @@ -0,0 +1,54 @@ +#ifndef ETABWIDGET_H +#define ETABWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class ETabWidget: public QTabWidget +{ + Q_OBJECT +public: + explicit ETabWidget(QWidget * parent = 0); + + void retranslate(); + void addTabButton(int role, const QIcon & icon, const QString & toolTip = QString()) {buttons << TabButton(role, icon, toolTip);} + int addTab(QWidget * page, const QIcon & icon, const QString & label); + int addTab(QWidget * page, const QString & label) {return addTab(page, QIcon(), label);} + void setButtonVisible(int role, bool yes); + +private: + bool eventFilter(QObject * o, QEvent * e); + void tabInserted(int) {emit countChanged();} + void tabRemoved(int) {emit countChanged();} + + struct TabButton { + TabButton(int r, const QIcon & i, const QString & t) {role = r; icon = i; visible = true; srcToolTip = t; toolTip = QApplication::translate("MainWindow", t.toUtf8(), 0/*, QCoreApplication::UnicodeUTF8*/);} + int role; + bool visible; + QIcon icon; + QString srcToolTip; + QString toolTip; + }; + + QList buttons; + +private slots: + void buttonClicked(); + +signals: + void countChanged(); + void tabHovered(int tab); + void tabButtonClicked(int tab, int role); + +}; + +#endif // ETABWIDGET_H diff --git a/qad/application/historyview.cpp b/qad/application/historyview.cpp new file mode 100644 index 0000000..a0e7c44 --- /dev/null +++ b/qad/application/historyview.cpp @@ -0,0 +1,140 @@ +#include "historyview.h" + + +HistoryView::HistoryView(QWidget* parent): QListWidget(parent) { + setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + setSelectionMode(QAbstractItemView::MultiSelection); + setEditTriggers(NoEditTriggers); + active_ = true; + index = 0; + setLimit(32); + setHistoryColor(palette().color(QPalette::Highlight)); + connect(this, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(itemClicked(QListWidgetItem*))); + connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged())); + registerAction(-1, tr("History cleared"), QImage(":/icons/clear-history.png")); +} + + +HistoryView::~HistoryView() { +} + + +void HistoryView::addEntry(int action, int count_, const QString & suffix) { + if (!active_) return; + int cnt = count(); + for (int i = index; i < cnt; ++i) + if (i >= 0) delete takeItem(index); + addItem(new QListWidgetItem(actions_.value(action).icon, actionText(action, count_) + suffix)); + index = count(); + history_.resize(index); + history_.back() = Entry(action); + checkLimit(); + emit commandRequest(history_.back().command); + scrollToItem(item(index - 1)); + blockSignals(true); + for (int i = 0; i < index; ++i) + item(i)->setSelected(true); + blockSignals(false); + emit redoAvailable(false); + emit undoAvailable((index > 1)); + emit clearAvailable(history_.count() > 1); +} + + +void HistoryView::registerAction(int action, const QString & text, const QImage & icon) { + actions_[action] = HistoryView::Action(action, text, icon); +} + + +QString HistoryView::actionText(int action, int count_) { + return QString(actions_.value(action).text).replace("%count", QString::number(count_)); +} + + +void HistoryView::checkLimit() { + if (count() < limit_ + 1) return; + int c = count() - limit_; + for (int i = 0; i < c; ++i) { + if (i >= index - 1) { + if (count() < 2) break; + delete takeItem(1); + history_.remove(1); + } else { + if (count() < 1) break; + delete takeItem(0); + history_.pop_front(); + index--; + } + } + if (index < 1) index = 1; + if (index > count()) index = count(); +} + + +void HistoryView::itemClicked(QListWidgetItem * item) { + if (!active_) return; + if (index == row(item) + 1) return; + index = row(item) + 1; + //qDebug() << actions[index - 1].command; + emit commandExecute(history_[index - 1].command); + itemSelectionChanged(); +} + + +void HistoryView::itemSelectionChanged() { + if (!active_) return; + if (index < 1) index = 1; + //qDebug() << "changed" << count(); + blockSignals(true); + for (int i = 0; i < index; ++i) + item(i)->setSelected(true); + for (int i = index; i < count(); ++i) + item(i)->setSelected(false); + blockSignals(false); + emit redoAvailable(index < count()); + emit undoAvailable((index > 1)); +} + + +void HistoryView::setLimit(int l) { + limit_ = l; + checkLimit(); + emit redoAvailable(index < count()); + emit undoAvailable((index > 1)); +} + + +void HistoryView::setHistoryColor(const QColor & c) { + color_ = c; + QPalette pal(palette()); + pal.setColor(QPalette::Highlight, color_); + pal.setColor(QPalette::HighlightedText, pal.color(QPalette::Text)); + setPalette(pal); +} + + +void HistoryView::clear(bool silent) { + history_.clear(); + QListWidget::clear(); + if (!silent) addEntry(-1); + emit clearAvailable(false); + emit redoAvailable(index < count()); + emit undoAvailable((index > 1)); +} + + +void HistoryView::undo() { + if (index <= 1) return; + index--; + emit commandExecute(history_[index - 1].command); + itemSelectionChanged(); +} + + +void HistoryView::redo() { + if (index >= count()) return; + index++; + emit commandExecute(history_[index - 1].command); + itemSelectionChanged(); +} diff --git a/qad/application/historyview.h b/qad/application/historyview.h new file mode 100644 index 0000000..6795dc4 --- /dev/null +++ b/qad/application/historyview.h @@ -0,0 +1,74 @@ +#ifndef HISTORYVIEW_H +#define HISTORYVIEW_H + +#include +#include + + +class HistoryView: public QListWidget +{ + Q_OBJECT + Q_PROPERTY(bool active READ isActive WRITE setActive) + Q_PROPERTY(int limit READ limit WRITE setLimit) + Q_PROPERTY(QColor historyColor READ historyColor WRITE setHistoryColor) +public: + explicit HistoryView(QWidget * parent = 0); + ~HistoryView(); + + bool isActive() const {return active_;} + int limit() const {return limit_;} + QColor historyColor() const {return color_;} + + void addEntry(int action, int count = 0, const QString & suffix = QString()); + void registerAction(int action, const QString & text, const QImage & icon = QImage()); + +private: + struct Action { + Action(int i = -1, const QString & t = QString(), const QImage & c = QImage()): id(i), text(t) { + QPixmap px = QPixmap::fromImage(c); + icon.addPixmap(px, QIcon::Active); + icon.addPixmap(px, QIcon::Disabled); + icon.addPixmap(px, QIcon::Normal); + icon.addPixmap(px, QIcon::Selected); + } + int id; + QString text; + QIcon icon; + }; + struct Entry { + Entry(int a = -1, const QByteArray & c = QByteArray()): action(a), command(c) {} + int action; + QByteArray command; + }; + + void checkLimit(); + QString actionText(int action, int count_); + + QMap actions_; + QVector history_; + QColor color_; + bool active_; + int index, limit_; + +public slots: + void setActive(bool yes) {active_ = yes;} + void setLimit(int l); + void setHistoryColor(const QColor & c); + void clear(bool silent = false); + void undo(); + void redo(); + +private slots: + void itemClicked(QListWidgetItem * item); + void itemSelectionChanged(); + +signals: + void undoAvailable(bool); + void redoAvailable(bool); + void clearAvailable(bool); + void commandRequest(QByteArray & s); + void commandExecute(const QByteArray & s); + +}; + +#endif // HISTORYVIEW_H diff --git a/qad/application/lang/qad_application_ru.ts b/qad/application/lang/qad_application_ru.ts new file mode 100644 index 0000000..377960d --- /dev/null +++ b/qad/application/lang/qad_application_ru.ts @@ -0,0 +1,290 @@ + + + + + Graphic + + + Autofit + Автомасштаб + + + + Grid + Сетка + + + + Cursor axis + Плавающие оси + + + + Only expand Y + Только расширять Y + + + + Only expand X + Только расширять X + + + + Border inputs + + + + + Legend + Легенда + + + + Configure ... + Настроить ... + + + + Save image ... + Сохранить изображение ... + + + + Clear + Очистить + + + + Close + Закрыть + + + + Cursor: ( ; ) + Курсор: ( ; ) + + + + + Cursor: + Курсор: + + + + Selection + Выделение + + + + Size + Размер + + + + + Range + Диапазон + + + + + Length + Длина + + + + + Cursor + Курсор + + + + Save Image + Сохранить изображение + + + + y(x) + + + + + Check all + Выбрать все + + + + GraphicConf + + + Graphic parameters + Параметры графика + + + + Appearance + Внешний вид + + + + Border inputs + + + + + Antialiasing + Сглаживание + + + + Status bar + Панель статуса + + + + OpenGL + + + + + Legend + Легенда + + + + Background color: + Цвет фона: + + + + Text color: + Цвет текста: + + + + Graphics + Графики + + + + + Color: + Цвет: + + + + + Style: + Стиль: + + + + Lines width: + Толщина линий: + + + + Points width: + Толщина точек: + + + + Fill: + Заливка: + + + + Grid + Сетка + + + + Width: + Толщина: + + + + Step X: + Шаг X: + + + + Step Y: + Шаг Y: + + + + Auto step + Автоматический шаг + + + + Margins + Поля + + + + + + + + px + пикс + + + + All: + Все: + + + + Right: + Правое: + + + + Left: + Левое: + + + + Bottom: + Нижнее: + + + + Top: + Верхнее: + + + + NoPen + НетЛинии + + + + Solid + Сплошная + + + + Dash + Штриховая + + + + Dot + Пунктирная + + + + Dash-Dot + ШтрихПунктирная + + + + Dash-Dot-Dot + ШтрихПунктирПунктирная + + + diff --git a/qad/application/plugin/CMakeLists.txt b/qad/application/plugin/CMakeLists.txt new file mode 100644 index 0000000..09f97dd --- /dev/null +++ b/qad/application/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(application "") diff --git a/qad/application/plugin/edockwidgetplugin.cpp b/qad/application/plugin/edockwidgetplugin.cpp new file mode 100644 index 0000000..61a5d87 --- /dev/null +++ b/qad/application/plugin/edockwidgetplugin.cpp @@ -0,0 +1,69 @@ +#include "edockwidget.h" +#include "edockwidgetplugin.h" +#include + + +EDockWidgetPlugin::EDockWidgetPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void EDockWidgetPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool EDockWidgetPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * EDockWidgetPlugin::createWidget(QWidget * parent) { + return new EDockWidget(parent); +} + + +QString EDockWidgetPlugin::name() const { + return QLatin1String("EDockWidget"); +} + + +QString EDockWidgetPlugin::group() const { + return QLatin1String("Containers"); +} + + +QIcon EDockWidgetPlugin::icon() const { + return QIcon(":/icons/edockwidget.png"); +} + + +QString EDockWidgetPlugin::toolTip() const { + return QLatin1String(""); +} + + +QString EDockWidgetPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool EDockWidgetPlugin::isContainer() const { + return true; +} + + +QString EDockWidgetPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString EDockWidgetPlugin::includeFile() const { + return QLatin1String("edockwidget.h"); +} + diff --git a/qad/application/plugin/edockwidgetplugin.h b/qad/application/plugin/edockwidgetplugin.h new file mode 100644 index 0000000..fed7ce1 --- /dev/null +++ b/qad/application/plugin/edockwidgetplugin.h @@ -0,0 +1,31 @@ +#ifndef EDOCKWIDGETPLUGIN_H +#define EDOCKWIDGETPLUGIN_H + +#include + +class EDockWidgetPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + EDockWidgetPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif diff --git a/qad/application/plugin/emainwindowplugin.cpp b/qad/application/plugin/emainwindowplugin.cpp new file mode 100644 index 0000000..630d637 --- /dev/null +++ b/qad/application/plugin/emainwindowplugin.cpp @@ -0,0 +1,69 @@ +#include "emainwindow.h" +#include "emainwindowplugin.h" +#include + + +EMainWindowPlugin::EMainWindowPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void EMainWindowPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool EMainWindowPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * EMainWindowPlugin::createWidget(QWidget * parent) { + return new EMainWindow(parent); +} + + +QString EMainWindowPlugin::name() const { + return QLatin1String("EMainWindow"); +} + + +QString EMainWindowPlugin::group() const { + return QLatin1String("Containers"); +} + + +QIcon EMainWindowPlugin::icon() const { + return QIcon(); +} + + +QString EMainWindowPlugin::toolTip() const { + return QLatin1String(""); +} + + +QString EMainWindowPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool EMainWindowPlugin::isContainer() const { + return true; +} + + +QString EMainWindowPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString EMainWindowPlugin::includeFile() const { + return QLatin1String("emainwindow.h"); +} + diff --git a/qad/application/plugin/emainwindowplugin.h b/qad/application/plugin/emainwindowplugin.h new file mode 100644 index 0000000..e6da131 --- /dev/null +++ b/qad/application/plugin/emainwindowplugin.h @@ -0,0 +1,31 @@ +#ifndef EMAINWINDOWPLUGIN_H +#define EMAINWINDOWPLUGIN_H + +#include + +class EMainWindowPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + EMainWindowPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif diff --git a/qad/application/plugin/historyviewplugin.cpp b/qad/application/plugin/historyviewplugin.cpp new file mode 100644 index 0000000..7113e6e --- /dev/null +++ b/qad/application/plugin/historyviewplugin.cpp @@ -0,0 +1,69 @@ +#include "historyview.h" +#include "historyviewplugin.h" +#include + + +HistoryViewPlugin::HistoryViewPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void HistoryViewPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool HistoryViewPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * HistoryViewPlugin::createWidget(QWidget * parent) { + return new HistoryView(parent); +} + + +QString HistoryViewPlugin::name() const { + return QLatin1String("HistoryView"); +} + + +QString HistoryViewPlugin::group() const { + return QLatin1String("Display Widgets"); +} + + +QIcon HistoryViewPlugin::icon() const { + return QIcon(":/icons/historyview.png"); +} + + +QString HistoryViewPlugin::toolTip() const { + return QLatin1String(""); +} + + +QString HistoryViewPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool HistoryViewPlugin::isContainer() const { + return true; +} + + +QString HistoryViewPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString HistoryViewPlugin::includeFile() const { + return QLatin1String("historyview.h"); +} + diff --git a/qad/application/plugin/historyviewplugin.h b/qad/application/plugin/historyviewplugin.h new file mode 100644 index 0000000..b3a2fb0 --- /dev/null +++ b/qad/application/plugin/historyviewplugin.h @@ -0,0 +1,31 @@ +#ifndef HISTORYVIEWPLUGIN_H +#define HISTORYVIEWPLUGIN_H + +#include + +class HistoryViewPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + HistoryViewPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // HISTORYVIEWPLUGIN_H diff --git a/qad/application/plugin/qad_application.cpp b/qad/application/plugin/qad_application.cpp new file mode 100644 index 0000000..cc2e5c0 --- /dev/null +++ b/qad/application/plugin/qad_application.cpp @@ -0,0 +1,19 @@ +#include "edockwidgetplugin.h" +#include "emainwindowplugin.h" +#include "historyviewplugin.h" +#include "qad_application.h" + + +QADApplication::QADApplication(QObject * parent): QObject(parent) { + //m_widgets.append(new EDockWidgetPlugin(this)); + m_widgets.append(new EMainWindowPlugin(this)); + m_widgets.append(new HistoryViewPlugin(this)); +} + + +QList QADApplication::customWidgets() const { + return m_widgets; +} + + +Q_EXPORT_PLUGIN2(qad_graphic_plugin, QADApplication) diff --git a/qad/application/plugin/qad_application.h b/qad/application/plugin/qad_application.h new file mode 100644 index 0000000..7e8dcef --- /dev/null +++ b/qad/application/plugin/qad_application.h @@ -0,0 +1,21 @@ +#ifndef QAD_APPLICATION_H +#define QAD_APPLICATION_H + +#include +#include + +class QADApplication: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit QADApplication(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; + +}; + +#endif // QAD_APPLICATION_H diff --git a/qad/application/qad_application.qrc b/qad/application/qad_application.qrc new file mode 100644 index 0000000..6a82538 --- /dev/null +++ b/qad/application/qad_application.qrc @@ -0,0 +1,33 @@ + + + lang/qad_application_ru.ts + ../icons/dialog-close.png + ../icons/edit-clear.png + ../icons/edit-guides.png + ../icons/view-grid.png + ../icons/zoom-fit-best.png + ../icons/configure.png + ../icons/document-save.png + ../icons/edit-clear-locationbar-rtl.png + ../icons/edit-find.png + ../icons/list-add.png + ../icons/edit-delete.png + ../icons/item.png + ../icons/node-add.png + ../icons/node.png + ../icons/edit-copy.png + ../icons/edit-paste.png + ../icons/expand_s_x.png + ../icons/expand_s_y.png + ../icons/expand_x.png + ../icons/expand_y.png + ../icons/border-line.png + ../icons/legend.png + ../icons/graphic.png + ../icons/edockwidget.png + ../icons/layer-visible-off.png + ../icons/layer-visible-on.png + ../icons/historyview.png + ../icons/clear-history.png + + diff --git a/qad/application/qsingleapplication.cpp b/qad/application/qsingleapplication.cpp new file mode 100644 index 0000000..428c4bb --- /dev/null +++ b/qad/application/qsingleapplication.cpp @@ -0,0 +1,87 @@ +#include +#include "qsingleapplication.h" + + +#define QSA_SHMSIZE 4096 +#define QSA_MSGSIZE (QSA_SHMSIZE - sizeof(quint32) - sizeof(quint32)) + + +QSingleApplication::QSingleApplication(const QString & app_name): QThread() { + shm.setKey(app_name); + exiting = false; + first = !shm.attach(); + if (!first) { + shm.detach(); + first = !shm.attach(); + if (!first) + return; + } + shm.create(QSA_SHMSIZE); + shm.attach(); + shm.lock(); + void * d = shm.data(); + if (d) memset(d, 0, sizeof(quint32)); + shm.unlock(); + start(); + //qDebug() << "start listen"; +} + + +QSingleApplication::~QSingleApplication() { + if (first) { + exiting = true; + quit(); + if (!wait(100)) + terminate(); + } + if (shm.isAttached()) shm.detach(); +} + + +void QSingleApplication::sendMessage(const QByteArray & m) { + //qDebug() << "send message" << first << shm.isAttached(); + if (first || !shm.isAttached()) return; + if (m.size() > int(QSA_MSGSIZE)) { + qDebug() << "[QSingleApplication] Too large message:" << m.size() << ">" << QSA_MSGSIZE; + return; + } + shm.lock(); + quint32 num(0), size = m.size(); + void * d = shm.data(); + if (d) { + memcpy(&num, d, sizeof(quint32)); + num++; + memcpy(d, &num, sizeof(quint32)); + memcpy((((char*)d) + sizeof(quint32)), &size, sizeof(quint32)); + memcpy((((char*)d) + sizeof(quint32) + sizeof(quint32)), m.constData(), size); + } + shm.unlock(); +} + + +void QSingleApplication::run() { + quint32 num(0), pnum(0), size(0); + while (!exiting) { + shm.lock(); + const void * d = shm.constData(); + if (d) { + memcpy(&num, d, sizeof(quint32)); + if (pnum != num) { + pnum = num; + //qDebug() << "new message" << num; + memcpy(&size, (((const char*)d) + sizeof(quint32)), sizeof(quint32)); + if (size <= int(QSA_MSGSIZE)) { + QByteArray msg; + msg.resize(size); + memcpy(msg.data(), (((const char*)d) + sizeof(quint32) + sizeof(quint32)), size); + emit messageReceived(msg); + } else { + qDebug() << "[QSingleApplication] Invalid message size:" << size; + } + } + } + shm.unlock(); + if (exiting) break; + msleep(10); + } +} diff --git a/qad/application/qsingleapplication.h b/qad/application/qsingleapplication.h new file mode 100644 index 0000000..45a83df --- /dev/null +++ b/qad/application/qsingleapplication.h @@ -0,0 +1,30 @@ +#ifndef QSINGLEAPPLICATION_H +#define QSINGLEAPPLICATION_H + +#include +#include + +class QSingleApplication: public QThread +{ + Q_OBJECT +public: + QSingleApplication(const QString & app_name = QString("qapp")); + ~QSingleApplication(); + + bool isFirst() const {return first;} + +private: + void run(); + + QSharedMemory shm; + bool first, exiting; + +public slots: + void sendMessage(const QByteArray & m); + +signals: + void messageReceived(QByteArray); + +}; + +#endif // QSINGLEAPPLICATION_H diff --git a/qad/application/ribbon.cpp b/qad/application/ribbon.cpp new file mode 100644 index 0000000..05990d7 --- /dev/null +++ b/qad/application/ribbon.cpp @@ -0,0 +1,196 @@ +#include "ribbon.h" +#include + + +Ribbon::Ribbon(QMainWindow * parent_): QToolBar() { + delay_e = true; + delay = 1000; + hovered = -1; + setObjectName("ribbon"); + setProperty("ribbon", true); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + parent = parent_; + if (parent_) + parent_->installEventFilter(this); + init(); +} + + +Ribbon::~Ribbon() { +} + + +bool Ribbon::eventFilter(QObject * o, QEvent * e) { + if (o == parent) { + if (e->type() == QEvent::Resize || e->type() == QEvent::WindowActivate) + _resize(); + return QToolBar::eventFilter(o, e); + } + if (e->type() == QEvent::ActionChanged) { + QToolButton * b = qobject_cast((QObject * )o->property("ribbonButton").toLongLong()); + if (b != 0) + b->setEnabled(qobject_cast(o)->isEnabled()); + } + return QToolBar::eventFilter(o, e); +} + + +void Ribbon::timerEvent(QTimerEvent * e) { + if (hovers.value(e->timerId(), -1) == hovered) + tab->setCurrentIndex(hovered); + hovers.remove(e->timerId()); + killTimer(e->timerId()); +} + + +void Ribbon::_resize() { + return; // WARNING + for (int i = 0; i < tab->count(); ++i) { + int h = ((QScrollArea*)(tab->widget(i)))->sizeHint().height(); + if (((QScrollArea*)(tab->widget(i)))->horizontalScrollBar()->isVisible()) + h += ((QScrollArea*)(tab->widget(i)))->horizontalScrollBar()->height(); + ((QScrollArea*)(tab->widget(i)))->setMinimumHeight(h); + } +} + + +void Ribbon::setVisible(bool yes) { + QToolBar::setVisible(yes); + if (parent == 0) return; + if (parent->menuBar() == 0) return; + parent->menuBar()->setVisible(!yes); +} + + +void Ribbon::init() { + if (parent == 0) return; + if (parent->menuBar() == 0) return; + QList lm = parent->menuBar()->actions(), la; + tab = new ETabWidget(); + tab->setObjectName("ribbon_tab_widget"); + connect(tab, SIGNAL(tabHovered(int)), this, SLOT(tabHovered(int))); + connect(tab, SIGNAL(currentChanged(int)), this, SIGNAL(currentTabChanged(int))); + tab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QGroupBox * g; + QBoxLayout * l, * tl; + QToolButton * b; + //tab->setIconSize(QSize(32, 32)); + foreach (QAction * i, lm) { + if (i->menu() == 0) continue; + la = i->menu()->actions(); + tab->addTab(new QWidget(), i->icon(), i->text()); + /*QScrollArea * sa = new QScrollArea(); + sa->setWidget(new QWidget()); + sa->setWidgetResizable(true); + sa->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + sa->setFrameShape(QFrame::NoFrame); + tab->addTab(sa, i->icon(), i->text());*/ + tab->widget(tab->count() - 1)->setProperty("ribbonAction", qlonglong((void * )i)); + i->setIcon(QIcon()); + tl = new QBoxLayout(QBoxLayout::LeftToRight); + tl->setSpacing(2); + tl->setContentsMargins(2, 2, 2, 2); + g = new QGroupBox(); + l = new QBoxLayout(QBoxLayout::LeftToRight); + g->setLayout(l); + l->setSpacing(2); + l->setContentsMargins(2, 2, 2, 2); + foreach (QAction * j, la) { + if (j->isSeparator()) { + if (l->isEmpty()) continue; + tl->addWidget(g); + g = new QGroupBox(); + l = new QBoxLayout(QBoxLayout::LeftToRight); + l->setSpacing(2); + l->setContentsMargins(2, 2, 2, 2); + g->setLayout(l); + continue; + } + if (qobject_cast(j)) { + QWidget * _w = qobject_cast(j)->defaultWidget(); + l->addWidget(_w); + _w->show(); + continue; + } + b = new QToolButton(); + b->setEnabled(j->isEnabled()); + b->setProperty("ribbonAction", qlonglong((void * )j)); + j->setProperty("ribbonButton", qlonglong((void * )b)); + j->installEventFilter(this); + if (j->menu() != 0) { + b->setPopupMode(QToolButton::InstantPopup); + b->setMenu(j->menu()); + } else { + b->setCheckable(j->isCheckable()); + if (b->isCheckable()) { + b->setChecked(j->isChecked()); + connect(b, SIGNAL(toggled(bool)), j, SLOT(setChecked(bool))); + connect(b, SIGNAL(clicked(bool)), j, SIGNAL(triggered(bool))); + connect(j, SIGNAL(toggled(bool)), b, SLOT(setChecked(bool))); + } else + connect(b, SIGNAL(clicked()), j, SLOT(trigger())); + } + //b->setIconSize(QSize(16, 16)); + b->setIcon(j->icon()); + b->setText(j->text()); + //b->setToolTip(j->toolTip()); + //b->addAction(j); + //b->setShortcut(j->shortcut()); + b->setAutoRaise(true); + b->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + buttons << b; + l->addWidget(b); + } + tl->addWidget(g); + tl->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed)); + //sa->widget()->setLayout(tl); + tab->widget(tab->count() - 1)->setLayout(tl); + } + setFloatable(false); + setMovable(false); + scroll_area = new QScrollArea(); + scroll_area->setFrameShape(QFrame::NoFrame); + scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + scroll_area->setWidget(tab); + _resize(); + //addWidget(scroll_area); + addWidget(tab); + parent->addToolBar(Qt::TopToolBarArea, this); + parent->menuBar()->hide(); + tab->setAutoFillBackground(false); +} + + +void Ribbon::retranslate() { + QAction * a; + foreach (QToolButton * i, buttons) { + a = (QAction * )(i->property("ribbonAction").toLongLong()); + if (a == 0) continue; + i->setText(a->text()); + i->setToolTip(a->toolTip()); + //i->setShortcut(a->shortcut()); + } + for (int i = 0; i < tab->count(); ++i) { + a = (QAction * )(tab->widget(i)->property("ribbonAction").toLongLong()); + if (a == 0) continue; + tab->setTabText(i, a->text()); + } + _resize(); +} + + +void Ribbon::setIconSize(const QSize & size) { + foreach (QToolButton * i, buttons) + i->setIconSize(size); + _resize(); +} + + +void Ribbon::setTabIconSize(const QSize & size) { + tab->setIconSize(size); + _resize(); +} diff --git a/qad/application/ribbon.h b/qad/application/ribbon.h new file mode 100644 index 0000000..e59826d --- /dev/null +++ b/qad/application/ribbon.h @@ -0,0 +1,62 @@ +#ifndef RIBBON_H +#define RIBBON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "etabwidget.h" + + +class Ribbon: public QToolBar +{ + Q_OBJECT +public: + explicit Ribbon(QMainWindow * parent = 0); + ~Ribbon(); + + void init(); + void retranslate(); + void setIconSize(const QSize & size); + void setTabIconSize(const QSize & size); + void setButtonStyle(const Qt::ToolButtonStyle & style) {foreach (QToolButton * i, buttons) i->setToolButtonStyle(style);} + void setAutoSwitchEnabled(bool yes) {delay_e = yes;} + void setAutoSwitchDelay(float delay_s) {delay = delay_s * 1000;} + void setCurrentTab(int tab_) {if (tab_ < 0 || tab_ >= tab->count()) return; tab->setCurrentIndex(tab_);} + int currentTab() const {return tab->currentIndex();} + QTabWidget * tabWidget() const {return tab;} + +private: + bool eventFilter(QObject * o, QEvent * e); + void timerEvent(QTimerEvent * e); + void _resize(); + + int hovered, delay; + bool delay_e; + QList buttons; + QMap hovers; + ETabWidget * tab; + QScrollArea * scroll_area; + QMainWindow * parent; + +private slots: + void tabHovered(int tab) {if (!delay_e) return; hovers.clear(); hovered = tab; hovers.insert(startTimer(delay), tab);} + +public slots: + void setVisible(bool yes); + void setHidden(bool yes) {setVisible(!yes);} + void show() {setVisible(true);} + void hide() {setVisible(false);} + +signals: + void currentTabChanged(int); + +}; + +#endif // RIBBON_H diff --git a/qad/blockview/CMakeLists.txt b/qad/blockview/CMakeLists.txt new file mode 100644 index 0000000..9ad84a1 --- /dev/null +++ b/qad/blockview/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} qad_widgets qad_utils) +qad_project(blockview "${LIBS}") diff --git a/qad/blockview/alignedtextitem.cpp b/qad/blockview/alignedtextitem.cpp new file mode 100644 index 0000000..ee7f2b8 --- /dev/null +++ b/qad/blockview/alignedtextitem.cpp @@ -0,0 +1,45 @@ +#include "alignedtextitem.h" +#include +#include + + +AlignedTextItem::AlignedTextItem(QGraphicsItem * parent): QGraphicsItem(parent), text_(this) { + align_ = Qt::AlignTop | Qt::AlignHCenter; + text_.setData(1003, true); + _move(); +} + + +AlignedTextItem::AlignedTextItem(const QString & text, QGraphicsItem * parent): QGraphicsItem(parent), text_(this) { + align_ = Qt::AlignTop | Qt::AlignHCenter; + text_.setData(1003, true); + setText(text); +} + + +QPointF AlignedTextItem::_point(Qt::Alignment a) const { + QRectF br = text_.boundingRect(); + QPointF ret; + switch (Qt::AlignmentFlag(int(align_ & Qt::AlignHorizontal_Mask))) { + case Qt::AlignRight: ret.rx() = br.left(); break; + case Qt::AlignHCenter: ret.rx() = br.center().x(); break; + case Qt::AlignLeft: ret.rx() = br.right(); break; + default: break; + } + switch (Qt::AlignmentFlag(int(align_ & Qt::AlignVertical_Mask))) { + case Qt::AlignBottom: ret.ry() = br.top(); break; + case Qt::AlignVCenter: ret.ry() = br.center().y(); break; + case Qt::AlignTop: ret.ry() = br.bottom(); break; + default: break; + } + return ret; +} + + +void AlignedTextItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { + if (isSelected()) { + painter->setPen(QPen(Qt::DashLine)); + painter->setBrush(Qt::NoBrush); + painter->drawRect(boundingRect()); + } +} diff --git a/qad/blockview/alignedtextitem.h b/qad/blockview/alignedtextitem.h new file mode 100644 index 0000000..89519e0 --- /dev/null +++ b/qad/blockview/alignedtextitem.h @@ -0,0 +1,45 @@ +#ifndef ALIGNEDTEXTITEM_H +#define ALIGNEDTEXTITEM_H + +#include +#include +#include +#include + + +class AlignedTextItem: public QGraphicsItem { +public: + AlignedTextItem(QGraphicsItem * parent = 0); + AlignedTextItem(const QString & text, QGraphicsItem * parent = 0); + + void setText(const QString & t) {text_.setText(t); _move();} + void setFont(const QFont & f) {text_.setFont(f); _move();} + void setPen(const QPen & p) {text_.setPen(p); _move();} + void setBrush(const QBrush & b) {text_.setBrush(b); _move();} + void setAlignment(Qt::Alignment align) {align_ = align; _move();} + + QString text() const {return text_.text();} + QFont font() const {return text_.font();} + QPen pen() const {return text_.pen();} + QBrush brush() const {return text_.brush();} + Qt::Alignment alignment() const {return align_;} + + void clear() {setText(QString());} + + enum {Type = UserType + 0x100}; + +protected: + virtual QRectF boundingRect() const {return text_.boundingRect().translated(text_.pos());} + virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0); + virtual int type() const {return Type;} + + void _move() {text_.setPos(-_point(align_));} + QPointF _point(Qt::Alignment a) const; + + QGraphicsSimpleTextItem text_; + Qt::Alignment align_; + +}; + + +#endif // ALIGNEDTEXTITEM_H diff --git a/qad/blockview/blockbase.cpp b/qad/blockview/blockbase.cpp new file mode 100644 index 0000000..1a2bb13 --- /dev/null +++ b/qad/blockview/blockbase.cpp @@ -0,0 +1,104 @@ +#include "blockbase.h" +#include "alignedtextitem.h" +#include "qvariantedit.h" + + +QDataStream & operator <<(QDataStream & s, const QGraphicsItem * item) { + if (!item) { + s << int(-1); + return s; + } + const QGraphicsRectItem * irect = qgraphicsitem_cast(item); + const QGraphicsEllipseItem * iell = qgraphicsitem_cast(item); + const QGraphicsSimpleTextItem * itext = qgraphicsitem_cast(item); + const AlignedTextItem * iatext = qgraphicsitem_cast(item); + const QGraphicsLineItem * iline = qgraphicsitem_cast(item); + const QGraphicsPathItem * ipath = qgraphicsitem_cast(item); + const QGraphicsPixmapItem * ipixmap = qgraphicsitem_cast(item); + if (irect) { + s << int(0) << (irect->pen()) << (irect->brush()) << (irect->rect()); + } else if (iell) { + s << int(1) << (iell->pen()) << (iell->brush()) << (iell->rect()); + } else if (itext) { + s << int(2) << (itext->pen()) << (itext->brush()) << (itext->font()) << (itext->text()); + } else if (iatext) { + s << int(6) << (iatext->pen()) << (iatext->brush()) << (iatext->font()) << (iatext->text()) << int(iatext->alignment()); + } else if (iline) { + s << int(3) << (iline->pen()) << (iline->line()); + } else if (ipath) { + s << int(4) << (ipath->pen()) << (ipath->path()); + } else if (ipixmap) { + s << int(5) << (ipixmap->pixmap()); + } else { + s << int(-1); + return s; + } + s << (item->pos()) << (item->rotation()) << int(item->flags()); + return s; +} + + +QDataStream & operator >>(QDataStream & s, QGraphicsItem *& item) { + int type_; s >> type_; + if (type_ < 0) { + item = 0; + return s; + } + QGraphicsRectItem * nrect = 0; + QGraphicsEllipseItem * nell = 0; + QGraphicsSimpleTextItem * ntext = 0; + AlignedTextItem * natext = 0; + QGraphicsLineItem * nline = 0; + QGraphicsPathItem * npath = 0; + QGraphicsPixmapItem * npixmap = 0; + item = 0; + switch (type_) { + case 0: + nrect = new QGraphicsRectItem(); item = nrect; + {QPen _v; s >> _v; nrect->setPen(_v);} + {QBrush _v; s >> _v; nrect->setBrush(_v);} + {QRectF _v; s >> _v; nrect->setRect(_v);} + break; + case 1: + nell = new QGraphicsEllipseItem(); item = nell; + {QPen _v; s >> _v; nell->setPen(_v);} + {QBrush _v; s >> _v; nell->setBrush(_v);} + {QRectF _v; s >> _v; nell->setRect(_v);} + break; + case 2: + ntext = new QGraphicsSimpleTextItem(); item = ntext; + {QPen _v; s >> _v; ntext->setPen(_v);} + {QBrush _v; s >> _v; ntext->setBrush(_v);} + {QFont _v; s >> _v; ntext->setFont(_v);} + {QString _v; s >> _v; ntext->setText(_v);} + break; + case 6: + natext = new AlignedTextItem(); item = natext; + {QPen _v; s >> _v; natext->setPen(_v);} + {QBrush _v; s >> _v; natext->setBrush(_v);} + {QFont _v; s >> _v; natext->setFont(_v);} + {QString _v; s >> _v; natext->setText(_v);} + {int _v; s >> _v; natext->setAlignment((Qt::AlignmentFlag)_v);} + break; + case 3: + nline = new QGraphicsLineItem(); item = nline; + {QPen _v; s >> _v; nline->setPen(_v);} + {QLineF _v; s >> _v; nline->setLine(_v);} + break; + case 4: + npath = new QGraphicsPathItem(); item = npath; + {QPen _v; s >> _v; npath->setPen(_v);} + {QPainterPath _v; s >> _v; npath->setPath(_v);} + break; + case 5: + npixmap = new QGraphicsPixmapItem(); item = npixmap; + {QPixmap _v; s >> _v; npixmap->setPixmap(_v);} + break; + } + if (item) { + {QPointF _v; s >> _v; item->setPos(_v);} + {qreal _v; s >> _v; item->setRotation(_v);} + {int _v; s >> _v; item->setFlags((QGraphicsItem::GraphicsItemFlags)_v);} + } + return s; +} diff --git a/qad/blockview/blockbase.h b/qad/blockview/blockbase.h new file mode 100644 index 0000000..7b19ef7 --- /dev/null +++ b/qad/blockview/blockbase.h @@ -0,0 +1,57 @@ +#ifndef BLOCKBASE_H +#define BLOCKBASE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "propertystorage.h" + + +/// data: +/// 1002 - flag for move parent (true) +/// 1003 - flag for visualize selection (true) +/// 1004 - BlockItemPin ("pin") +/// 1005 - BlockBusItem ("connection") +/// 1006 - BlockItem ("item") +/// 1007 - BlockItem selection ("item_selection") +/// 1008 - item is NOT decor, ignore for function decors() (true) +/// 1009 - item is scene decor ("decor") +/// 1010 - BlockItem decor (src text for QGraphicsSimpleTextItem) +/// 1011 - item is BlockItem decor ("decor") +/// 1100 - flag for correct move (true) + + +QDataStream & operator <<(QDataStream & s, const QGraphicsItem * item); +QDataStream & operator >>(QDataStream & s, QGraphicsItem *& item); + + +class BlockItemBase: public QObject +{ + Q_OBJECT + Q_ENUMS(Action) +public: + + enum Action { + BlockAdd = 1, + BlockMove, + BlockRemove, + BlockCopy, + BusAdd, + BusRemove, + BusPointAdd, + BusPointMove, + BusPointRemove, + BusSegmentAdd, + BusSegmentMove, + BusSegmentRemove, + Paste + }; + +}; + +#endif // BLOCKBASE_H diff --git a/qad/blockview/blockbusitem.cpp b/qad/blockview/blockbusitem.cpp new file mode 100644 index 0000000..0dcc423 --- /dev/null +++ b/qad/blockview/blockbusitem.cpp @@ -0,0 +1,733 @@ +#include "blockbusitem.h" + + +BlockBusItem::BlockBusItem(bool temp): QGraphicsObject(), PropertyStorage() { + temp_ = temp; + _init(); + if (!temp) setData(1005, "connection"); + else hide(); +} + + +BlockBusItem::BlockBusItem(const BlockBusItem & other): QGraphicsObject(), PropertyStorage() { + temp_ = false; + _init(); + setData(1005, "connection"); + setPen(other.pen()); + setBrush(other.brush()); + setBusType(other.busType()); + max_ep = other.max_ep; + pol = other.pol; + segments = other.segments; + updateGeometry(); +} + + +void BlockBusItem::_init() { + setBusType(-1); + setAcceptHoverEvents(true); + ph.setColor(Qt::blue); ph.setJoinStyle(Qt::MiterJoin); + bh.setColor(Qt::blue); bh.setStyle(Qt::SolidPattern); + pu = pa = pr = ph; bu = ba = br = bh; + grid_step = 10.; + pu.setWidth(1); + pu.setColor(Qt::black); bu.setColor(Qt::black); + pa.setColor(Qt::darkGreen); ba.setColor(Qt::darkGreen); + pr.setColor(Qt::darkRed); br.setColor(Qt::darkRed); + pn.setColor(Qt::gray); pn.setStyle(Qt::DashLine); + if (temp_) { + pu.setStyle(Qt::DashLine); + pu.setColor(Qt::darkGray); + bu.setColor(Qt::darkGray); + } + setPen(pu); setBrush(bu); + max_ep = 0; + selPoint = selSegment = state_ = -1; + pen_width = 2.; + moved = deleted = mark_in = mark_out = new_segment = mm_cancel = lm_point = false; +} + + +void BlockBusItem::reconnect() { + if (temp_) return; + if (!scene()) return; + if (scene()->views().isEmpty()) return; + QMetaObject::invokeMethod(scene()->views().back(), "reconnectAll"); +} + + +bool BlockBusItem::sceneEvent(QEvent * e) { + if (temp_) return QGraphicsObject::sceneEvent(e); + switch (e->type()) { + case QEvent::GraphicsSceneHoverEnter: hoverEnterEvent((QGraphicsSceneHoverEvent * )e); break; + case QEvent::GraphicsSceneHoverMove: hoverMoveEvent((QGraphicsSceneHoverEvent * )e); break; + case QEvent::GraphicsSceneHoverLeave: hoverLeaveEvent((QGraphicsSceneHoverEvent * )e); break; + case QEvent::GraphicsSceneMousePress: mousePressEvent((QGraphicsSceneMouseEvent * )e); break; + case QEvent::GraphicsSceneMouseMove: mouseMoveEvent((QGraphicsSceneMouseEvent * )e); break; + case QEvent::GraphicsSceneMouseRelease: mouseReleaseEvent((QGraphicsSceneMouseEvent * )e); break; + default: break; + } + return QGraphicsObject::sceneEvent(e); +} + + +int BlockBusItem::addPoint(const QPointF & point, bool update) { + int ei = pol.indexOf(point); + if (ei >= 0) return ei; + if (selSegment < 0 || selSegment >= pol.size() - 1) return -1; + pol << quantize(nearestPointOnLine(pol[segments[selSegment].first], pol[segments[selSegment].second], point), grid_step); + selPoint = pol.size() - 1; + segments << QPair(selPoint, segments[selSegment].second); + segments[selSegment].second = selPoint; + selSegment = -1; + updateGeometry(); + if (scene() != 0 && update) scene()->update(); + return pol.size() - 1; +} + + +int BlockBusItem::segmentPointPair(int point, int * seg) const { + for (int i = 0; i < segments.size(); ++i) { + if (segments[i].first == point) { + if (seg) *seg = i; + return segments[i].second; + } + if (segments[i].second == point) { + if (seg) *seg = i; + return segments[i].first; + } + } + if (seg) *seg = -1; + return -1; +} + + +void BlockBusItem::removePoint(int index) { + if (index < 0 || index > pol.size() - 1) return; + int sc = 0, fs = -1, ss = -1; + for (int i = 0; i < segments.size(); ++i) + if (segments[i].first == index || + segments[i].second == index) { + sc++; + if (fs < 0) fs = i; + else ss = i; + } + int ei(0); + switch (sc) { + case 1: + segments.removeAt(fs); + break; + case 2: + if (segments[ss].first == index) ei = segments[ss].second; + else ei = segments[ss].first; + if (segments[fs].first == index) segments[fs].first = ei; + else segments[fs].second = ei; + segments.removeAt(ss); + break; + default: return; + } + pol.remove(index); + for (int i = 0; i < segments.size(); ++i) { + if (segments[i].first >= index) + segments[i].first--; + if (segments[i].second >= index) + segments[i].second--; + } + selPoint = -1; + checkDelete(); + updateGeometry(); + if (scene() != 0) scene()->update(); +} + + +void BlockBusItem::removeSegment(int index) { + if (index < 0 || index > segments.size() - 1) return; + int pif = segments[index].first, pis = segments[index].second; + if (pif > pis) qSwap(pif, pis); + int scf = 0, scs = 0; + for (int i = 0; i < segments.size(); ++i) { + if (segments[i].first == pif || + segments[i].second == pif) + scf++; + if (segments[i].first == pis || + segments[i].second == pis) + scs++; + } + if (scs <= 2) removePoint(pis); + if (scf <= 2) removePoint(pif); + if (scs <= 2 || scf <= 2) selSegment = -1; + if (scene() != 0) scene()->update(); + +} + + +void BlockBusItem::appendPoint(const QPointF & p) { + pol << p; + if (pol.size() > 1) + segments << QPair(pol.size() - 2, pol.size() - 1); + updateGeometry(); +} + + +void BlockBusItem::clear() { + pol.clear(); + segments.clear(); + updateGeometry(); +} + + +void BlockBusItem::markAsInput() { + mark_in = true; + mark_out = false; +} + + +void BlockBusItem::markAsOutput() { + mark_in = false; + mark_out = true; +} + + +void BlockBusItem::unmark() { + mark_in = mark_out = false; +} + + +void BlockBusItem::simplify(bool full) { + int pcnt = pol.size(); + for (int s = 0; s < segments.size(); ++s) { + if (pol[segments[s].first] != pol[segments[s].second]) continue; + int ti = segments[s].first, fi = segments[s].second; + segments.removeAt(s); + pol.remove(fi); + for (int i = 0; i < segments.size(); ++i) { + if (segments[i].first == fi) segments[i].first = ti; + if (segments[i].second == fi) segments[i].second = ti; + if (segments[i].first > fi) segments[i].first--; + if (segments[i].second > fi) segments[i].second--; + } + } + if (full) { + QList segs; + for (int p = 0; p < pol.size(); ++p) { + if (pointSegmentsCount(p, &segs) != 2) continue; + int s0 = segs[0], s1 = segs[1]; + QPointF cp = pol[p], sp[2]; + for (int i = 0; i < 2; ++i) { + if (segments[segs[i]].first == p) sp[i] = pol[segments[segs[i]].second]; + else sp[i] = pol[segments[segs[i]].first]; + } + QLineF l0(sp[0], cp), l1(cp, sp[1]); + if (qAbs(l0.angle() - l1.angle()) > 0.1) continue; + if (segments[s0].first == p) { + if (segments[s1].first == p) segments[s0].first = segments[s1].second; + else segments[s0].first = segments[s1].first; + } else { + if (segments[s1].first == p) segments[s0].second = segments[s1].second; + else segments[s0].second = segments[s1].first; + } + segments.removeAt(s1); + pol.remove(p); + for (int i = 0; i < segments.size(); ++i) { + if (segments[i].first >= p) segments[i].first--; + if (segments[i].second >= p) segments[i].second--; + } + p = -1; + } + } + if (pcnt == pol.size()) return; + updateGeometry(); + //if (scene()) scene()->update(); +} + + +void BlockBusItem::adjustLine() { +} + + +int BlockBusItem::endpointCount() const { + return endpoints().size(); +} + + + +QList BlockBusItem::connectedBlocks() const { + QList pins = connections_.values(); + QSet ret; + foreach (BlockItemPin * p, pins) + ret << p->parent(); + return ret.toList(); +} + + +QList BlockBusItem::connectedPins() const { + return connections_.values(); +} + + +void BlockBusItem::setBusState(bool state) { + int s = state ? 1 : 0; + if (state_ == s) return; + state_ = s; + update(); +} + + +void BlockBusItem::clearBusState() { + if (state_ == -1) return; + state_ = -1; + update(); +} + + +QByteArray BlockBusItem::save() const { + ChunkStream cs; + cs << cs.chunk(1, busType()) << cs.chunk(2, busName()) << cs.chunk(3, width()) << cs.chunk(4, pen()) + << cs.chunk(5, brush()) << cs.chunk(6, pol) << cs.chunk(7, segments) << cs.chunk(8, props); + return cs.data(); +} + + +void BlockBusItem::load(const QByteArray & data) { + clear(); + if (data.isEmpty()) return; + ChunkStream cs(data); + while (!cs.atEnd()) { + switch (cs.read()) { + case 1: setBusType(cs.getData()); break; + case 2: setBusName(cs.getData()); break; + case 3: setWidth(cs.getData()); break; + case 4: setPen(cs.getData()); break; + case 5: setBrush(cs.getData()); break; + case 6: pol = cs.getData(); break; + case 7: segments = cs.getData > >(); break; + case 8: props = cs.getData >(); break; + } + } + updateGeometry(); +} + + +BlockBusItem * BlockBusItem::copy() const { + return new BlockBusItem(*this); +} + + +void BlockBusItem::saveState() { + segments_s = segments; + ends_ind_s = ends_ind; + ends_s = ends; + pol_s = pol; +} + + +void BlockBusItem::restoreState() { + segments = segments_s; + ends_ind = ends_ind_s; + ends = ends_s; + pol = pol_s; +} + + +void BlockBusItem::updateGeometry() { + ends = endpoints(); + ends_ind.clear(); + for (int e = 0; e < ends.size(); ++e) { + int ce = ends[e]; + for (int s = 0; s < segments.size(); ++s) { + if (segments[s].first == ce) { + ends_ind << QPair(segments[s].first, segments[s].second); + break; + } + if (segments[s].second == ce) { + ends_ind << QPair(segments[s].second, segments[s].first); + break; + } + } + } + reconnect(); + prepareGeometryChange(); +} + + +void BlockBusItem::checkDelete() { + if (pol.size() < 2 || segments.size() < 1) deleteLater(); +} + + +void BlockBusItem::emitAction(BlockItemBase::Action a) { + QMetaObject::invokeMethod(scene()->views().back(), "actionEvent", Q_ARG(BlockItemBase::Action, a), Q_ARG(QList, QList() << this)); + QMetaObject::invokeMethod(scene()->views().back(), "connectionsChanged"); +} + + +QVector BlockBusItem::endpoints() const { + QVector counts(pol.size(), 0), ret; + for (int i = 0; i < segments.size(); ++i) { + counts[segments[i].first]++; + counts[segments[i].second]++; + } + for (int i = 0; i < counts.size(); ++i) { + if (counts[i] == 1) + ret << i; + } + return ret; +} + + +QVector BlockBusItem::endpointLine(int ep, double angle) const { + QVector ret; + int seg = -1; + int np = segmentPointPair(ep, &seg), pp = np; + if (ep < 0 || np < 0) return ret; + if (pol[np] == pol[ep]) return ret; + //QPointF sp = pol[np] - pol[ep]; + QLineF l(pol[ep], pol[np]); + //qDebug() << "first" << l.angle() << angle << (l.angle() != angle); + if (qAbs(l.angle() - angle) > 0.1) return ret; + //qDebug() << "check next" << segments.size(); + for (int i = 0; i < segments.size(); ++i) { + //qDebug() << i << np << pointSegmentsCount(np); + if (np < 0) break; + if (pointSegmentsCount(np) != 2) break; + if (i > 0) { + QLineF l(pol[pp], pol[np]); + //qDebug() << i << l.angle() << angle; + if (qAbs(l.angle() - angle) > 0.1) break; + } + ret << np; + pp = np; + np = neighborSegmentPoint(np, &seg); + } + return ret; + +} + + +int BlockBusItem::pointSegmentsCount(int point, QList * segs) const { + int ret = 0; + if (segs) segs->clear(); + for (int i = 0; i < segments.size(); ++i) + if (segments[i].first == point || segments[i].second == point) { + ret++; + if (segs) segs->append(i); + } + return ret; +} + + +int BlockBusItem::neighborSegmentPoint(int point, int * seg) const { + if (point < 0 || !seg) return -1; + for (int i = 0; i < segments.size(); ++i) { + if (i == *seg) continue; + if (segments[i].first == point) {*seg = i; return segments[i].second;} + if (segments[i].second == point) {*seg = i; return segments[i].first ;} + } + return -1; +} + + +void BlockBusItem::testPoint(QPointF pos, int * sel_point, int * sel_segment) { + for (int i = 0; i < pol.size(); ++i) { + if ((pol[i] - pos).manhattanLength() <= 10.) { // Point + *sel_point = i; + *sel_segment = -1; + return; + } + } + for (int i = 0; i < segments.size(); ++i) { + if (distPointToLine(pol[segments[i].first], pol[segments[i].second], pos) <= 7.) { // Segment + *sel_point = -1; + *sel_segment = i; + return; + } + } + *sel_point = -1; + *sel_segment = -1; +} + + +void BlockBusItem::hoverEnterEvent(QGraphicsSceneHoverEvent * e) { + tt = bus_name + (bus_name.isEmpty() ? "" : "\n\n") + tr("Add point: Ctrl + LeftClick\nRemove point\\segment: Ctrl + RightClick\nNew branch: Shift + LeftClick\nRemove connection: Shift + RightClick"); +} + + +void BlockBusItem::hoverMoveEvent(QGraphicsSceneHoverEvent * e) { + if (temp_) return; + QPointF sp = e->scenePos(); + testPoint(sp, &selPoint, &selSegment); + if (selPoint >= 0 || selSegment >= 0) { + setToolTip(tt); + update(); + return; + } + setToolTip(QString()); + QList il = scene()->items(sp, Qt::ContainsItemBoundingRect, Qt::DescendingOrder), bil; + bil << this; + for (int i = 0; i < il.size(); ++i) { + QGraphicsItem * b = il[i]; + if (b->data(1005) == "connection" && b != this) { + int tp = -1, ts = -1; + ((BlockBusItem*)b)->testPoint(sp, &tp, &ts); + if (tp >= 0 || ts >= 0) { + foreach (QGraphicsItem * b2, bil) + b2->stackBefore(b); + break; + } + bil << b; + } + } + update(); +} + + +void BlockBusItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * e) { + if (temp_) return; + selPoint = selSegment = -1; + setPen(pu); setBrush(bu); + setToolTip(QString()); + update(); + QGraphicsObject::hoverLeaveEvent(e); +} + + +void BlockBusItem::mousePressEvent(QGraphicsSceneMouseEvent * e) { + if (temp_) return; + lp = quantize(e->scenePos(), grid_step); + if (new_segment) { + QMetaObject::invokeMethod(scene()->views().back(), "newBranchCancel"); + } + new_segment = false; + if ((selPoint < 0 || selPoint > pol.size() - 1) && (selSegment < 0)) { + QGraphicsObject::mousePressEvent(e); + return; + } + int btncnt = 0; + if (e->buttons().testFlag(Qt::LeftButton)) btncnt++; + if (e->buttons().testFlag(Qt::RightButton)) btncnt++; + if (e->buttons().testFlag(Qt::MidButton)) btncnt++; + if (btncnt > 0) mm_mods = e->modifiers(); + //qDebug() << "press" << e; + if (btncnt >= 2 && e->button() == Qt::RightButton) { + mm_cancel = true; + moved = false; + QPointF lp = qp - press_pos; + //qDebug() << lp; + if (selPoint >= 0 && selPoint <= pol.size() - 1) + pol[selPoint] += lp; + if (selSegment >= 0 && selSegment <= segments.size() - 1) { + pol[segments[selSegment].first] += lp; + pol[segments[selSegment].second] += lp; + } + moved = true; + prepareGeometryChange(); + return; + } + if (e->modifiers().testFlag(Qt::ShiftModifier)) { + if (e->buttons().testFlag(Qt::LeftButton)) { + if (selSegment >= 0) + press_pos = quantize(nearestPointOnLine(pol[segments[selSegment].first], pol[segments[selSegment].second], e->scenePos()), grid_step); + else { + if (selPoint >= 0) + press_pos = pol[selPoint]; + else + return; + } + if (max_ep >= 2) { + if (endpointCount() >= max_ep) + if (pointSegmentsCount(selPoint) >= 2 || selSegment >= 0) + return; + } + QMetaObject::invokeMethod(scene()->views().back(), "newBranch", Q_ARG(BlockBusItem * , this)); + new_segment = true; + return; + } + if (e->buttons().testFlag(Qt::RightButton)) { + deleteLater(); + } + } + if (e->modifiers().testFlag(Qt::ControlModifier)) { + if (e->buttons().testFlag(Qt::RightButton)) { + if (selPoint >= 0 && selPoint <= pol.size() - 1) { + removePoint(selPoint); + simplify(); + emitAction(BlockItemBase::BusPointRemove); + return; + } + if (selSegment >= 0 && selSegment <= segments.size() - 1) { + removeSegment(selSegment); + simplify(); + emitAction(BlockItemBase::BusSegmentRemove); + return; + } + } + if (e->buttons().testFlag(Qt::LeftButton) && selSegment >= 0) { + if (addPoint(e->scenePos()) >= 0) + emitAction(BlockItemBase::BusPointAdd); + return; + } + } + if (e->modifiers().testFlag(Qt::ShiftModifier)) { + if (e->buttons().testFlag(Qt::RightButton)) { + if (deleted) return; + deleted = true; + } + } +} + + +void BlockBusItem::mouseMoveEvent(QGraphicsSceneMouseEvent * e) { + if (temp_ || mm_cancel) return; + if (((selPoint < 0 || selPoint > pol.size() - 1) && (selSegment < 0)) && !new_segment) { + QGraphicsObject::mouseMoveEvent(e); + return; + } + qp = quantize(e->scenePos(), grid_step); + lp = qp - lp; + if (e->buttons().testFlag(Qt::LeftButton) && mm_mods.testFlag(Qt::ShiftModifier) && new_segment) { + QMetaObject::invokeMethod(scene()->views().back(), "newBranchTrace", Q_ARG(BlockBusItem * , this), Q_ARG(QPointF, e->scenePos())); + return; + } + if (new_segment) { + new_end = qp; + prepareGeometryChange(); + } else { + if (e->buttons().testFlag(Qt::LeftButton)) { + lm_point = selPoint >= 0; + if (selPoint >= 0 && selPoint <= pol.size() - 1) + pol[selPoint] += lp; + if (selSegment >= 0 && selSegment <= segments.size() - 1) { + pol[segments[selSegment].first] += lp; + pol[segments[selSegment].second] += lp; + } + moved = true; + prepareGeometryChange(); + } + } + lp = qp; +} + + +void BlockBusItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * e) { + mm_mods = 0; + int btncnt = 0; + if (e->buttons().testFlag(Qt::LeftButton)) btncnt++; + if (e->buttons().testFlag(Qt::RightButton)) btncnt++; + if (e->buttons().testFlag(Qt::MidButton)) btncnt++; + if (btncnt == 0) mm_cancel = false; + if (new_segment) { + QMetaObject::invokeMethod(scene()->views().back(), "newBranchAccept", Q_ARG(BlockBusItem * , this)); + updateGeometry(); + selPoint = selSegment = -1; + } + if (moved) { + simplify(false); + reconnect(); + emitAction(lm_point ? BlockItemBase::BusPointMove : BlockItemBase::BusSegmentMove); + } + moved = new_segment = false; + QGraphicsObject::mouseReleaseEvent(e); +} + + +void BlockBusItem::paint(QPainter * p, const QStyleOptionGraphicsItem * o, QWidget * w) { + ph.setWidthF(pen_width + 1.); + pu.setWidthF(pen_width); + pa.setWidthF(pen_width); + pr.setWidthF(pen_width); + pn.setWidthF(pen_width); + if (pol.size() < 2) return; + if (selPoint >= 0 || selSegment >= 0) { + p->setPen(pa); + p->setBrush(ba); + } else { + p->setPen(pu); + p->setBrush(bu); + } + //if (mark_in) {p->setPen(pa); p->setBrush(ba);} + //if (mark_out) {p->setPen(pr); p->setBrush(br);} + if (im_bus.isNull()) { + for (int i = 0; i < segments.size(); ++i) { + p->drawLine(pol[segments[i].first], pol[segments[i].second]); + } + } else { + QBrush br; + br.setTextureImage(im_bus); + for (int i = 0; i < segments.size(); ++i) { + QPointF sp(pol[segments[i].first]), ep(pol[segments[i].second]); + QTransform tf; + tf.translate(sp.x(), sp.y()); + tf.rotate(-QLineF(sp, ep).angle()); + tf.translate(0., -im_bus.height() / 2.); + /* + br.setTransform(tf); + p->setPen(QPen(br, im_bus.height(), Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin)); + p->drawLine(sp, ep); + */ + p->save(); + p->setTransform(tf, true); + p->setPen(Qt::NoPen); + p->setBrush(br); + //p->drawLine(QPointF(0., 0.), QPointF(QLineF(sp, ep).length(), 0.)); + p->drawRect(QRectF(0., 0., QLineF(sp, ep).length(), im_bus.height())); + p->restore(); + } + } + if (!im_end.isNull()) { + for (int i = 0; i < ends_ind.size(); ++i) { + QPointF sp = pol[ends_ind[i].first], ep = pol[ends_ind[i].second]; + QTransform tf; + tf.translate(sp.x(), sp.y()); + tf.rotate(-QLineF(sp, ep).angle()); + tf.translate(-pen_width, -im_end.height() / 2.); + p->save(); + p->setTransform(tf, true); + p->drawImage(0, 0, im_end); + p->restore(); + } + } + if (state_ >= 0) { + if (state_ == 0) { + pr.setWidthF(pen_width + 1.); + p->setPen(pr); + } else if (state_ == 1) { + pa.setWidthF(pen_width + 1.); + p->setPen(pa); + } + p->setOpacity(0.5); + for (int i = 0; i < segments.size(); ++i) { + p->drawLine(pol[segments[i].first], pol[segments[i].second]); + } + p->setOpacity(1.); + } + if (!im_bus.isNull() && (selPoint >= 0 || selSegment >= 0)) { + p->setPen(pa); + p->setBrush(ba); + for (int i = 0; i < segments.size(); ++i) { + p->drawLine(pol[segments[i].first], pol[segments[i].second]); + } + } + //if (mark_in) {p->setPen(pa); p->setBrush(ba);} + //if (mark_out) {p->setPen(pr); p->setBrush(br);} + if (selPoint >= 0) { + p->save(); + p->setPen(ph); + p->setBrush(bh); + p->translate(pol[selPoint]); + p->drawEllipse(QPointF(0, 0), 3, 3); + p->restore(); + } + if (selSegment >= 0) { + p->save(); + p->setPen(ph); + p->drawLine(pol[segments[selSegment].first], pol[segments[selSegment].second]); + p->restore(); + } +} + + +QRectF BlockBusItem::boundingRect() const { + QPolygonF p(pol); + p << new_end; + return enlargedRect(p.boundingRect(), 0, 0, 10.f); +} diff --git a/qad/blockview/blockbusitem.h b/qad/blockview/blockbusitem.h new file mode 100644 index 0000000..2552418 --- /dev/null +++ b/qad/blockview/blockbusitem.h @@ -0,0 +1,119 @@ +#ifndef BLOCKBUSITEM_H +#define BLOCKBUSITEM_H + +#include "blockitem.h" + + +class BlockBusItem: public QGraphicsObject, public PropertyStorage { + //Q_OBJECT + Q_INTERFACES(QGraphicsItem) + //Q_PROPERTY(double width READ width WRITE setWidth) + friend class BlockView; +public: + BlockBusItem(bool temp = false); + BlockBusItem(const BlockBusItem & other); + ~BlockBusItem() {;} + + void setGridStep(double gs) {grid_step = gs;} + void setEndpointsNumber(int num) {max_ep = num;} + void setImages(const QImage & bus, const QImage & end = QImage()) {im_bus = bus; im_end = end;} + void setBusType(int type_) {bus_type = type_;} + void setBusName(const QString & name) {bus_name = name;} + int busType() const {return bus_type;} + QString busName() const {return bus_name;} + void appendPoint(const QPointF & p); + void appendPoint(qreal x, qreal y) {appendPoint(QPointF(x, y));} + void testPoint(QPointF pos, int * sel_point, int * sel_segment); + void clear(); + /*void setStart(const QPointF & p) {pol[0] = p; scene()->update();} + void setStart(qreal x, qreal y) {setStart(QPointF(x, y));} + void setFinish(const QPointF & p) {pol[pol.size() - 1] = p; scene()->update();} + void setFinish(qreal x, qreal y) {setFinish(QPointF(x, y));} + void setPoint(int index, const QPointF & p) {pol[index] = p; scene()->update();} + void setPoint(int index, qreal x, qreal y) {setPoint(index, QPointF(x, y));}*/ + void setPen(const QPen & p) {p_ = p; update();} + QPen pen() const {return p_;} + void setBrush(const QBrush & b) {b_ = b; update();} + QBrush brush() const {return b_;} + //void disconnectBrick() {BrickBase::disconnect(brickFrom, portFrom, brickTo, portTo);} + void movePolyline(const QPointF & dp) {pol.translate(dp); prepareGeometryChange();} + void movePoint(int index, const QPointF & dp) {pol[index] += dp; prepareGeometryChange();} + double width() const {return pen_width;} + void setWidth(const double & w) {pen_width = w; update();} + void setColor(const QColor & c) {pu.setColor(c); bu.setColor(c); update();} + int addPoint(const QPointF & point, bool update = true); + int segmentPointPair(int point, int * seg = 0) const; + void removePoint(int index); + void removeSegment(int index); + void markAsInput(); + void markAsOutput(); + void unmark(); + void simplify(bool full = true); + void adjustLine(); + int endpointCount() const; + bool isBusSelected() const {return selSegment >= 0 || selPoint >= 0;} + QList connectedBlocks() const; + QList connectedPins() const; + + void setBusState(bool state); + bool busState() const {return state_ > 0;} + void clearBusState(); + + QByteArray save() const; + void load(const QByteArray & data); + BlockBusItem * copy() const; + + void saveState(); + void restoreState(); + + enum {Type = UserType + 2}; + +protected: + void _init(); + void reconnect(); + void updateGeometry(); + void checkDelete(); + void emitAction(BlockItemBase::Action a); + QVector endpoints() const; + QVector endpointLine(int ep, double angle) const; + int pointSegmentsCount(int point, QList * segs = 0) const; + int neighborSegmentPoint(int point, int * seg) const; + int type() const {return Type;} + QRectF boundingRect() const; + bool sceneEvent(QEvent * e); + void hoverEnterEvent(QGraphicsSceneHoverEvent * e); + void hoverMoveEvent(QGraphicsSceneHoverEvent * e); + void hoverLeaveEvent(QGraphicsSceneHoverEvent * e); + void mousePressEvent(QGraphicsSceneMouseEvent * e); + void mouseMoveEvent(QGraphicsSceneMouseEvent * e); + void mouseReleaseEvent(QGraphicsSceneMouseEvent * e); + void paint(QPainter * p, const QStyleOptionGraphicsItem * o, QWidget * w = 0); + + QPointF lp, new_start, new_end, press_pos, qp; + QPen p_, ph, pu, pa, pr, pn; + QBrush b_, bh, bu, ba, br; + QString tt, bus_name; + QList > segments, ends_ind, segments_s, ends_ind_s; + QMap connections_; + QVector ends, ends_s; + QImage im_bus, im_end; + QPolygonF pol, bpol, pol_s; + Qt::KeyboardModifiers mm_mods; + bool temp_; + double pen_width, grid_step; + int selPoint, selSegment, max_ep, bus_type, state_; + bool moved, deleted, mark_in, mark_out, new_segment, mm_cancel, lm_point; + +}; + + +inline QDataStream & operator <<(QDataStream & s, const BlockBusItem * b) {s << b->save(); return s;} +inline QDataStream & operator >>(QDataStream & s, BlockBusItem *& b) { + QByteArray ba; s >> ba; + b = new BlockBusItem(); + b->load(ba); + return s; +} + + +#endif // BLOCKBUSITEM_H diff --git a/qad/blockview/blockeditor.cpp b/qad/blockview/blockeditor.cpp new file mode 100644 index 0000000..2bd4560 --- /dev/null +++ b/qad/blockview/blockeditor.cpp @@ -0,0 +1,347 @@ +#include "blockeditor.h" +#include "ui_blockeditor.h" +#include "drawtools.h" +#include "blockview.h" +#include +#include +#include +#include +#include + + +BlockEditor::BlockEditor(QWidget *parent) : QWidget(parent), ui(new Ui::BlockEditor) { + init = false; + ui->setupUi(this); + connect(ui->blockView->scene(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + block.setFlags(0); + ui->blockView->addItem(&block); + ui->blockView->viewport()->installEventFilter(this); + DrawTools * drawtools = new DrawTools(ui->blockView); + drawtools->setAlignCompact(true); + connect(drawtools, SIGNAL(itemCreated(QGraphicsItem*)), this, SLOT(addItem(QGraphicsItem*))); + drawtools->textEditCombo()->addItems(QStringList() << "%name" << "%value" << "%id"); + ui->layoutProperties->addWidget(drawtools->propertyWidget()); + ui->actionRemove_items->setEnabled(false); + ui->button_color->setColor(Qt::lightGray); + ui->treePins->setItemDelegateForColumn(1, new PinBusDelegate()); + connect(ui->treePins, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(updateBlock())); + ui->treePins->viewport()->installEventFilter(this); + + QToolBar * bar; + bar = new QToolBar(ui->widgetBar); + bar->setOrientation(Qt::Vertical); + bar->addActions(drawtools->actionsForAdd()); + ui->widgetBar->setMinimumSize(bar->sizeHint()); + + bar = new QToolBar(ui->widgetBarZ); + bar->setOrientation(Qt::Vertical); + bar->addActions(drawtools->actionsForZ()); + bar->addSeparator(); + bar->addActions(QList() << ui->actionRemove_items); + ui->widgetBarZ->setMinimumSize(bar->sizeHint()); + init = true; + on_buttonClear_clicked(); +} + + +BlockEditor::~BlockEditor() { + init = false; + delete ui; +} + + +void BlockEditor::loadModel(const QByteArray &model) { + BlockItem b; + b.loadModel(model); + ui->spin_w->setValue(b.width()); + ui->spin_h->setValue(b.height()); + ui->spin_margin->setValue(b.pinsMargin()); + ui->button_color->setColor(b.color()); + block.loadModel(model); + treePinsClear(); + ui->treePins->blockSignals(true); + QVector pins = block.pins(); + foreach (BlockItemPin * p, pins) { + QTreeWidgetItem * ti = new QTreeWidgetItem(QStringList() << p->text() << QString::number(p->busType())); + ti->setData(0, Qt::UserRole, qulonglong(p)); + ti->setData(0, Qt::UserRole + 1, (int)p->alignment()); + ti->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled); + pin_tli[p->alignment()]->addChild(ti); + } + foreach (QGraphicsItem * i, block.decors()) { + i->setData(1002, false); + i->setData(1100, true); + } + ui->treePins->blockSignals(false); +} + + +QByteArray BlockEditor::saveModel() { + return block.saveModel(); +} + + +void BlockEditor::selectionChanged() { + if (!init) return; + ui->actionRemove_items->setEnabled(!ui->blockView->scene()->selectedItems().isEmpty()); +} + + +void BlockEditor::addItem(QGraphicsItem *item) { + block.addDecor(item); + item->setData(1002, false); + item->setData(1100, true); +} + + +void BlockEditor::updateBlock() { + block.setSize(ui->spin_w->value(), ui->spin_h->value()); + block.setColor(ui->button_color->color()); + block.setPinsMargin(ui->spin_margin->value()); +} + + +void BlockEditor::treePinsClear() { + ui->treePins->blockSignals(true); + ui->treePins->clear(); + QFont bf(font()); bf.setBold(true); + QList al = QList() << Qt::AlignLeft << Qt::AlignRight << Qt::AlignTop << Qt::AlignBottom; + QStringList an = QStringList() << "Left" << "Right" << "Top" << "Bottom"; + pin_tli.clear(); + for (int i = 0; i < al.size(); ++i) { + QTreeWidgetItem * ti = new QTreeWidgetItem(); + ti->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); + ti->setData(0, Qt::UserRole, al[i]); + ti->setText(0, an[i]); + ti->setFont(0, bf); + ui->treePins->addTopLevelItem(ti); + ti->setFirstColumnSpanned(true); + ti->setExpanded(true); + pin_tli[al[i]] = ti; + } + ui->treePins->blockSignals(false); +} + + +bool BlockEditor::eventFilter(QObject *o, QEvent *e) { + if (!init) QWidget::eventFilter(o, e); + if (o == ui->treePins->viewport()) { + if (e->type() == QEvent::Drop) { + QTimer::singleShot(0, this, SLOT(arrangePins())); + } + } + if (o == ui->blockView->viewport()) { + if (e->type() == QEvent::Resize) { + ui->blockView->centerOn(&block); + } + } + return QWidget::eventFilter(o, e); +} + + +void BlockEditor::on_actionRemove_items_triggered() { + QList si = ui->blockView->scene()->selectedItems(); + foreach (QGraphicsItem * i, si) + block.removeDecor(i); +} + + +void BlockEditor::on_buttonSave_clicked() { + QString c = QFileDialog::getSaveFileName(this, "Save block model to file", cur_file, "*.blockmodel"); + if (!c.isEmpty()) { + QFile f(c); + if (f.open(QIODevice::WriteOnly)) { + cur_file = c; + f.write(saveModel()); + } + } +} + + +void BlockEditor::on_buttonLoad_clicked() { + QString c = QFileDialog::getOpenFileName(this, "Save block model to file", cur_file, "*.blockmodel"); + if (!c.isEmpty()) { + QFile f(c); + if (f.open(QIODevice::ReadOnly)) { + cur_file = c; + loadModel(f.readAll()); + } + } +} + + +void BlockEditor::on_buttonClear_clicked() { + BlockItem b; + ui->spin_w->setValue(b.width()); + ui->spin_h->setValue(b.height()); + ui->spin_margin->setValue(b.pinsMargin()); + ui->button_color->setColor(b.color()); + block.loadModel(QByteArray()); + treePinsClear(); +} + + + +void BlockEditor::on_buttonPinAdd_clicked() { + ui->treePins->blockSignals(true); + QTreeWidgetItem * ti = new QTreeWidgetItem(QStringList() << "" << "0"); + ti->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled); + ti->setData(0, Qt::UserRole, qulonglong(block.addPin(Qt::AlignLeft, ti->text(1).toInt(), ti->text(0)))); + ti->setData(0, Qt::UserRole + 1, (int)Qt::AlignLeft); + pin_tli[Qt::AlignLeft]->addChild(ti); + ui->treePins->setCurrentItem(ti); + ui->treePins->blockSignals(false); + updateBlock(); +} + + +void BlockEditor::on_buttonPinDup_clicked() { + QTreeWidgetItem * ci = ui->treePins->currentItem(); + if (ci == 0) return; + ui->treePins->blockSignals(true); + QTreeWidgetItem * ti = ci->clone(); + ti->setText(0, ti->text(0)); + ti->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled); + Qt::Alignment al = (Qt::Alignment)ci->data(0, Qt::UserRole + 1).toInt(); + ti->setData(0, Qt::UserRole, qulonglong(block.addPin(al, ci->text(1).toInt(), ci->text(0)))); + ti->setData(0, Qt::UserRole + 1, (int)al); + pin_tli[al]->addChild(ti); + ui->treePins->setCurrentItem(ti); + ui->treePins->blockSignals(false); +} + + +void BlockEditor::on_buttonPinDelete_clicked() { + ui->treePins->blockSignals(true); + QList si = ui->treePins->selectedItems(); + foreach (QTreeWidgetItem * i, si) { + if (!i->parent()) continue; + block.removePin((BlockItemPin*)(i->data(0, Qt::UserRole).toLongLong())); + delete i; + } + ui->treePins->blockSignals(false); +} + + +void BlockEditor::on_buttonPinClear_clicked() { + treePinsClear(); + block.clearPins(); +} + + +void BlockEditor::on_treePins_itemChanged(QTreeWidgetItem * item, int column) { + if (!item) return; + BlockItemPin * pin = (BlockItemPin*)item->data(0, Qt::UserRole).toULongLong(); + if (!pin) return; + switch (column) { + case 0: + ui->treePins->blockSignals(true); + item->setText(0, item->text(0)); + pin->setText(item->text(0)); + ui->treePins->blockSignals(false); + break; + case 1: pin->setBusType(item->text(1).toInt()); break; + }; +} + + + +void BlockEditor::arrangePins() { + QVector pins = block.pins(); +// block.clearPins(); + QList tli = pin_tli.values(); + foreach (QTreeWidgetItem * ti, tli) { + for (int i = 0; i < ti->childCount(); ++i) { + foreach (BlockItemPin * p, pins) + if (p == (BlockItemPin*)(ti->child(i)->data(0, Qt::UserRole).toULongLong())) { + p->setAlignment((Qt::Alignment)ti->data(0, Qt::UserRole).toInt()); + BlockItemPin * np = block.addPin(p, false); + ti->child(i)->setData(0, Qt::UserRole, qulonglong(np)); + ti->child(i)->setData(0, Qt::UserRole + 1, ti->data(0, Qt::UserRole).toInt()); + break; + } + } + } + +// for (int i = 0; i < ui->treePins->topLevelItemCount(); ++i) { +// QTreeWidgetItem * ti = ui->treePins->topLevelItem(i); +// if (tli.contains(ti)) continue; +// ti = ui->treePins->takeTopLevelItem(i); +// pin_tli[ti->data(0, Qt::UserRole + 1).toInt()]->addChild(ti); +// foreach (BlockItemPin * p, pins) +// if (p->text() == ti->text(0)) { +// p->setAlignment((Qt::Alignment)ti->data(0, Qt::UserRole + 1).toInt()); +// block.addPin(p, false); +// break; +// } +// } + block.arrangePins(); +} + + +/// *********************************************************** +/// *********************************************************** +/// *********************************************************** +/// *********************************************************** + + +QWidget * PinAlignDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { + QComboBox * combo = new QComboBox(parent); + int cv = index.data().toInt(); + combo->addItem("Left", int(Qt::AlignLeft)); if (cv == Qt::AlignLeft) combo->setCurrentIndex(0); + combo->addItem("Right", int(Qt::AlignRight)); if (cv == Qt::AlignRight) combo->setCurrentIndex(1); + combo->addItem("Top", int(Qt::AlignTop)); if (cv == Qt::AlignTop) combo->setCurrentIndex(2); + combo->addItem("Bottom", int(Qt::AlignBottom)); if (cv == Qt::AlignBottom) combo->setCurrentIndex(3); + combo->setGeometry(option.rect); + return combo; +} + + +QString PinAlignDelegate::displayText(const QVariant & value, const QLocale & locale) const { + int cv = value.toInt(); + switch (cv) { + case Qt::AlignLeft: return "Left"; break; + case Qt::AlignRight: return "Right"; break; + case Qt::AlignTop: return "Top"; break; + case Qt::AlignBottom: return "Bottom"; break; + } + return "unknown"; +} + + +void PinAlignDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { + model->setData(index, ((QComboBox*)editor)->itemData(((QComboBox*)editor)->currentIndex()).toInt()); +} + + +/// *********************************************************** +/// *********************************************************** +/// *********************************************************** +/// *********************************************************** + + +QWidget * PinBusDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { + QSpinBox * spin = new QSpinBox(parent); + spin->setMinimum(-2147483648); + spin->setMaximum(2147483647); + spin->setValue(index.data().toInt()); + return spin; +} + + +QString PinBusDelegate::displayText(const QVariant & value, const QLocale & locale) const { + int cv = value.toInt(); + return QString::number(cv); +} + + +void PinBusDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { + model->setData(index, ((QSpinBox*)editor)->value()); +} + + + +//void BlockEditor::on_treePins_itemSelectionChanged() { +// arrangePins(); +// qDebug() << "111111111111111"; +//} diff --git a/qad/blockview/blockeditor.h b/qad/blockview/blockeditor.h new file mode 100644 index 0000000..71388b8 --- /dev/null +++ b/qad/blockview/blockeditor.h @@ -0,0 +1,81 @@ +#ifndef BLOCKEDITOR_H +#define BLOCKEDITOR_H + +#include +#include +#include +#include "blockitem.h" + + +namespace Ui { +class BlockEditor; +} + + +class BlockEditor : public QWidget +{ + Q_OBJECT + +public: + explicit BlockEditor(QWidget *parent = 0); + ~BlockEditor(); + + +public slots: + void loadModel(const QByteArray & model); + QByteArray saveModel(); + +private slots: + void selectionChanged(); + void addItem(QGraphicsItem * item); + void updateBlock(); + void treePinsClear(); + void arrangePins(); + void on_actionRemove_items_triggered(); + void on_buttonSave_clicked(); + void on_buttonLoad_clicked(); + void on_buttonClear_clicked(); + void on_buttonPinAdd_clicked(); + void on_buttonPinDup_clicked(); + void on_buttonPinDelete_clicked(); + void on_buttonPinClear_clicked(); + void on_treePins_itemChanged(QTreeWidgetItem *item, int column); +// void on_treePins_itemSelectionChanged(); + +private: + bool eventFilter(QObject * o, QEvent * e); + + Ui::BlockEditor *ui; + QMap pin_tli; + BlockItem block; + QString cur_file; + bool init; +}; + + + +class PinAlignDelegate: public QStyledItemDelegate { + Q_OBJECT +public: + PinAlignDelegate(QObject * parent = 0): QStyledItemDelegate(parent) {} + QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const; + QString displayText(const QVariant & value, const QLocale & locale) const; + void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const; + QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const {return QSize(60, 26);} +}; + + +class PinBusDelegate: public QStyledItemDelegate { + Q_OBJECT +public: + PinBusDelegate(QObject * parent = 0): QStyledItemDelegate(parent) {} + QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const; + QString displayText(const QVariant & value, const QLocale & locale) const; + void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const; + QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const {return QSize(60, 26);} +private: + typedef QPair ISPair; + QVector buses; +}; + +#endif // BLOCKEDITOR_H diff --git a/qad/blockview/blockeditor.ui b/qad/blockview/blockeditor.ui new file mode 100644 index 0000000..a07c7ce --- /dev/null +++ b/qad/blockview/blockeditor.ui @@ -0,0 +1,458 @@ + + + BlockEditor + + + + 0 + 0 + 901 + 861 + + + + Form + + + + + + Qt::Vertical + + + + Qt::Horizontal + + + + Block parameters + + + Qt::AlignCenter + + + + 4 + + + + + Width: + + + + + + + 1000 + + + 20 + + + 100 + + + + + + + Heigth: + + + + + + + 1000 + + + 20 + + + 60 + + + + + + + Pins margin: + + + + + + + 100 + + + 10 + + + 10 + + + + + + + Color: + + + + + + + + + + + Pins + + + Qt::AlignCenter + + + + 2 + + + + + + 0 + 200 + + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::ScrollPerPixel + + + false + + + false + + + 200 + + + + Name + + + + + Bus + + + + + + + + + + Add + + + + :/icons/list-add.png:/icons/list-add.png + + + + + + + Clone + + + + :/icons/edit-copy.png:/icons/edit-copy.png + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + Remove selected + + + + :/icons/edit-delete.png:/icons/edit-delete.png + + + + + + + Remove all + + + + :/icons/edit-clear.png:/icons/edit-clear.png + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Save + + + + :/icons/document-save.png:/icons/document-save.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Load + + + + :/icons/document-open.png:/icons/document-open.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Clear + + + + :/icons/edit-clear.png:/icons/edit-clear.png + + + + + + + + + + :/icons/edit-delete.png:/icons/edit-delete.png + + + Remove items + + + + + + BlockView + QGraphicsView +
blockview.h
+
+ + ColorButton + QPushButton +
colorbutton.h
+
+
+ + + + + + spin_w + valueChanged(int) + BlockEditor + updateBlock() + + + 170 + 21 + + + 254 + 1 + + + + + spin_h + valueChanged(int) + BlockEditor + updateBlock() + + + 250 + 49 + + + 373 + 5 + + + + + spin_margin + valueChanged(int) + BlockEditor + updateBlock() + + + 350 + 90 + + + 492 + 8 + + + + + button_color + colorChanged(QColor) + BlockEditor + updateBlock() + + + 561 + 115 + + + 613 + 6 + + + + + + updateBlock() + +
diff --git a/qad/blockview/blockeditor_main.cpp b/qad/blockview/blockeditor_main.cpp new file mode 100644 index 0000000..24a6356 --- /dev/null +++ b/qad/blockview/blockeditor_main.cpp @@ -0,0 +1,10 @@ +#include +#include "blockeditor.h" + + +int main(int argc, char * argv[]) { + QApplication a(argc, argv); + BlockEditor w; + w.show(); + return a.exec(); +} diff --git a/qad/blockview/blockitem.cpp b/qad/blockview/blockitem.cpp new file mode 100644 index 0000000..e5ae0b3 --- /dev/null +++ b/qad/blockview/blockitem.cpp @@ -0,0 +1,448 @@ +#include "blockitem.h" + + + +BlockItemPin::BlockItemPin(Qt::Alignment a, int bus_type_, const QString & text_, QGraphicsItem * _parent): QGraphicsItem(_parent), ell_item(this), text_item(this) { + parent_ = 0; + setData(1004, "pin"); + setAcceptHoverEvents(true); + text_item.setData(1002, true); + ell_item.setData(1003, true); + br[Disconnected] = QBrush(Qt::lightGray); + br[Connected] = QBrush(Qt::darkGreen); + br[Hover] = QBrush(Qt::blue); + br[Drop] = QBrush(Qt::green); + br[Accept] = QBrush(Qt::green); + br[Reject] = QBrush(Qt::red); + setState(Disconnected); + setAlignment(a); + setBusType(bus_type_); + setText(text_); + setZValue(2.); + setDirection(BlockItemPin::InputOutput); + _reparent(); +} + + +void BlockItemPin::resizePin(double r) { + ell_item.setRect(-r, -r, r+r, r+r); +} + + +void BlockItemPin::_init(bool affect_parent) { + QRectF tbr = text_item.boundingRect(); + const double r = 7.; + ell_item.setRect(-r, -r, r+r, r+r); + ell_item.setSpanAngle(16*180); + text_item.resetTransform(); + text_item.setPos(0, -tbr.height() / 2.); + text_item.setTransformOriginPoint(0, tbr.height() / 2.); + switch (align) { + case Qt::AlignBottom: ell_item.setStartAngle(16*0); text_item.setRotation(-90.); text_item.moveBy(0, -r * 1.5); break; + case Qt::AlignRight: ell_item.setStartAngle(16*90); text_item.setRotation(0.); text_item.moveBy(-tbr.width() - r * 1.5, 0); break; + case Qt::AlignTop: ell_item.setStartAngle(16*180); text_item.setRotation(-90.); text_item.moveBy(0, tbr.width() + r * 1.5); break; + case Qt::AlignLeft: ell_item.setStartAngle(16*270); text_item.setRotation(0.); text_item.moveBy(r * 1.5, 0); break; + default: break; + } + if (affect_parent && parent_) + parent_->arrangePins(); +} + + +void BlockItemPin::_reparent() { + if (parentItem() == 0) return; + if (qgraphicsitem_cast(parentItem()) == 0) return; + QPen p = qgraphicsitem_cast(parentItem())->g_main.pen(); + ell_item.setPen(p); +} + + +QVariant BlockItemPin::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant & value) { + if (change == QGraphicsItem::ItemParentChange) + _reparent(); + return QGraphicsItem::itemChange(change, value); +} + + +void BlockItemPin::hoverEnterEvent(QGraphicsSceneHoverEvent * e) { + bool m_pin_mc(false); + if (scene()) if (!scene()->views().isEmpty()) + QMetaObject::invokeMethod(scene()->views()[0], "getPinMC", Q_ARG(bool*, &m_pin_mc)); + if ((state() != Disconnected) && !m_pin_mc) return; + saveState(); + setState(BlockItemPin::Hover); + update(); +} + + +void BlockItemPin::hoverLeaveEvent(QGraphicsSceneHoverEvent * e) { + restoreState(); + update(); +} + +#define BLOCKITEM_DEFAULT_PIN_MARGIN 20 + +BlockItem::BlockItem(QGraphicsItem * parent): QGraphicsObject(parent), PropertyStorage(), +g_main(this), g_selection(this) { + setData(1006, "item"); + setZValue(1.); + setAcceptHoverEvents(true); + setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); + g_main.setData(1002, true); + g_selection.setData(1007, "item_selection"); + g_selection.setAcceptedMouseButtons(0); + g_selection.setZValue(10.); + g_selection.hide(); + g_selection.setData(1003, true); + col = Qt::lightGray; + _resize(QSizeF(100., 60.)); + QPen p(QColor(128, 128, 255), 1., Qt::DotLine); + p.setCosmetic(true); + g_selection.setPen(p); + g_selection.setBrush(QColor(128, 128, 255, 32)); + pins_margin = BLOCKITEM_DEFAULT_PIN_MARGIN; + //g_main.setBrush(QColor(128, 128, 128, 64)); + /* + BlockItemPin * pin = new BlockItemPin(Qt::AlignRight, 0, this); + pin->setText("text"); + pin->setBusType(0); + addPin(pin); + pin = new BlockItemPin(Qt::AlignTop, this); + pin->setBusType(0); addPin(pin); + pin = new BlockItemPin(Qt::AlignLeft, this); + pin->setBusType(1); addPin(pin); + pin = new BlockItemPin(Qt::AlignRight, this); + pin->setBusType(1); addPin(pin);*/ +} + + +BlockItem::~BlockItem() { + clearDecors(); +} + + +void BlockItem::_resize(QSizeF s) { + g_main.setRect(QRectF(QPointF(), s)); + g_main.setPos(-g_main.rect().center()); + g_selection.setRect(enlargedRect(g_main.rect(), 0, 0, 8)); + g_selection.setPos(g_main.pos()); + QRadialGradient g(g_main.rect().width() / 2., 0, qMax(g_main.rect().width() / 2., g_main.rect().height())); + g.setSpread(QGradient::PadSpread); + g.setCoordinateMode(QGradient::LogicalMode); + g.setColorAt(0., col.darker(120.)); + g.setColorAt(1., col.lighter(120.)); + g_main.setBrush(QBrush(g)); + prepareGeometryChange(); + arrangePins(); +} + + +BlockItemPin * BlockItem::addPin(BlockItemPin * pin, bool update_) { + pin->setParentItem(this); + if (!pins_[pin->alignment()].contains(pin)) pins_[pin->alignment()] << pin; + pin->parent_ = this; + if (update_) + arrangePins(); + return pin; +} + + +BlockItemPin * BlockItem::addPin(Qt::Alignment align, int bus_type, const QString & text, bool update_) { + BlockItemPin * pin = new BlockItemPin(align, bus_type, text, this); + pin->parent_ = this; + pins_[pin->alignment()] << pin; + if (update_) + arrangePins(); + return pin; +} + + +void BlockItem::removePin(BlockItemPin * pin) { + if (!pin) return; + QMutableMapIterator > it(pins_); + while (it.hasNext()) { + it.next(); + it.value().remove(it.value().indexOf(pin)); + } + delete pin; + arrangePins(); +} + + +void BlockItem::addDecor(QGraphicsItem * item) { + if (decors_.contains(item)) return; + if (qgraphicsitem_cast(item)) + qgraphicsitem_cast(item)->setTransformationMode(Qt::SmoothTransformation); + if (qgraphicsitem_cast(item)) + qgraphicsitem_cast(item)->setData(1010, qgraphicsitem_cast(item)->text()); + if (qgraphicsitem_cast(item)) + qgraphicsitem_cast(item)->setData(1010, qgraphicsitem_cast(item)->text()); + item->setData(1002, true); + item->setData(1011, "decor"); + decors_ << item; + item->setParentItem(this); +} + + +void BlockItem::addDecor(QGraphicsItem & item) { + if (decors_.contains(&item)) return; + if (qgraphicsitem_cast(&item)) + qgraphicsitem_cast(&item)->setTransformationMode(Qt::SmoothTransformation); + if (qgraphicsitem_cast(&item)) + qgraphicsitem_cast(&item)->setData(1010, qgraphicsitem_cast(&item)->text()); + if (qgraphicsitem_cast(&item)) + qgraphicsitem_cast(&item)->setData(1010, qgraphicsitem_cast(&item)->text()); + item.setData(1002, true); + item.setData(1011, "decor"); + //decors_ << &item; + item.setParentItem(this); +} + + +void BlockItem::removeDecor(QGraphicsItem * item) { + if (scene() && item) + scene()->sendEvent(item, new QGraphicsSceneEvent(QEvent::Close)); + decors_.removeAll(item); + delete item; +} + + +QVector BlockItem::takePins() { + QVector ret = pins(); + pins_.clear(); + return ret; +} + + +void BlockItem::clearPins() { + QList > mp = pins_.values(); + for (int i = 0; i < mp.size(); ++i) + qDeleteAll(mp[i]); + pins_.clear(); +} + + +void BlockItem::clearDecors() { + bool pbs = false; + if (scene()) pbs = scene()->blockSignals(true); + if (scene()) + foreach (QGraphicsItem * i, decors_) + scene()->sendEvent(i, new QGraphicsSceneEvent(QEvent::Close)); + qDeleteAll(decors_); + decors_.clear(); + if (scene()) { + scene()->blockSignals(pbs); + QMetaObject::invokeMethod(scene(), "selectionChanged"); + } +} + + +QVector BlockItem::pins() const { + QList > mp = pins_.values(); + QVector ret; + for (int i = 0; i < mp.size(); ++i) + ret << mp[i]; + return ret; +} + + +QByteArray BlockItem::saveModel() { + /*QDataStream s(&ret, QIODevice::ReadWrite); + QVector ps = pins(); + s << pos() << rotation() << size() << color() << ps.size(); + foreach (BlockItemPin * p, ps) + s << int(p->alignment()) << p->busType() << p->text() << p->devices(); + s << decors_.size(); + foreach (QGraphicsItem * i, decors_) + s << i;*/ + ChunkStream cs; + cs << cs.chunk(1, pos()) << cs.chunk(2, rotation()) << cs.chunk(3, size()) << cs.chunk(4, color()) << cs.chunk(5, pins()) << cs.chunk(6, decors_) << cs.chunk(7, pins_margin); + return cs.data(); +} + + +void BlockItem::loadModel(const QByteArray & data) { + //qDebug() << "load from" << data.size() << "bytes"; + clearPins(); + clearDecors(); + col = Qt::lightGray; + _resize(QSizeF(100., 60.)); + if (data.isEmpty()) return; + /*QDataStream s(data); + {QPointF _v; s >> _v;} + {qreal _v; s >> _v;} + {QSizeF _v; s >> _v; setSize(_v);} + {QColor _v; s >> _v; setColor(_v);} + int _s; s >> _s; + for (int i = 0; i < _s; ++i) { + BlockItemPin * pin = new BlockItemPin(); + {int _v; s >> _v; pin->setAlignment((Qt::Alignment)_v);} + {int _v; s >> _v; pin->setBusType(_v);} + {QString _v; s >> _v; pin->setText(_v);} + {QMap _v; s >> _v; pin->setDevices(_v);} + addPin(pin); + } + s >> _s; + for (int i = 0; i < _s; ++i) { + if (s.atEnd()) break; + QGraphicsItem * ni = 0; + s >> ni; + if (ni) { + addDecor(ni); + } + }*/ + ChunkStream cs(data); + QVector tp; + QList dl; + while (!cs.atEnd()) { + switch (cs.read()) { + case 1: /*setPos(cs.getData());*/ break; + case 2: /*setRotation(cs.getData());*/ break; + case 3: setSize(cs.getData()); break; + case 4: setColor(cs.getData()); break; + case 5: + tp = cs.getData >(); + foreach (BlockItemPin * p, tp) addPin(p); + break; + case 6: + dl = cs.getData >(); + foreach (QGraphicsItem * d, dl) addDecor(d); + break; + case 7: setPinsMargin(cs.getData()); break; + } + } +} + + +QByteArray BlockItem::save() const { + ChunkStream cs; + QMap > pp; + foreach (BlockItemPin * p, pins()) { + pp[p->text()] = p->properties(); + } + cs << cs.chunk(1, pos()) << cs.chunk(2, rotation()) << cs.chunk(3, props) << cs.chunk(5, pp) << cs.chunk(6, size()); + cs << cs.chunk(10, data(2000)) << cs.chunk(11, data(2001)); + return cs.data(); +} + + +void BlockItem::load(const QByteArray & data) { + if (data.isEmpty()) return; + ChunkStream cs(data); + QMap > _p; + while (!cs.atEnd()) { + switch (cs.read()) { + case 1: setPos(cs.getData()); break; + case 2: setRotation(cs.getData()); break; + case 3: props = cs.getData >(); break; + case 5: + _p = cs.getData > >(); + foreach (BlockItemPin * p, pins()) + if (_p.contains(p->text())) + p->properties() = _p[p->text()]; + break; + case 6: setSize(cs.getData()); break; + case 10: setData(2000, cs.getData()); break; + case 11: setData(2001, cs.getData()); break; + } + } +} + + +BlockItem * BlockItem::copy() const { + BlockItem * ret = new BlockItem(); + ret->setPos(pos()); + ret->setSize(size()); + ret->setColor(color()); + ret->setSelected(false); + ret->props = props; + ret->setPinsMargin(pinsMargin()); + QVector mp = pins(); + foreach (BlockItemPin * p, mp) { + BlockItemPin * np = new BlockItemPin(); + np->setBusType(p->busType()); + np->setAlignment(p->alignment()); + np->setText(p->text()); + np->setToolTip(p->toolTip()); + np->properties() = p->properties(); + ret->addPin(np); + } + QByteArray ba; + foreach (QGraphicsItem * i, decors_) { + ba.clear(); + QGraphicsItem * ni = 0; + QDataStream s(&ba, QIODevice::ReadWrite); s << i; + QDataStream s2(ba); s2 >> ni; + if (ni) + ret->addDecor(ni); + } + return ret; +} + + +QList BlockItem::connectedBuses() const { + QList ret; + foreach (BlockItemPin * p, pins()) + ret << p->connectedBuses(); + return ret; +} + + +BlockItemPin * BlockItem::pinByText(const QString & t) const { + foreach (BlockItemPin * p, pins()) + if (p->text() == t) + return p; + return 0; +} + + +BlockItemPin * BlockItem::pinAtBus(BlockBusItem * bus) const { + if (bus == 0) return 0; + foreach (BlockItemPin * p, pins()) + if (p->connectedBuses().contains(bus)) + return p; + return 0; +} + + +QRectF BlockItem::boundingRect() const { + return g_main.mapRectToParent(g_main.boundingRect()); +} + + +void BlockItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event) { + //QGraphicsItem::mouseMoveEvent(event); +} + +#define _POS(m) (i - ((cp.size() - 1) / 2)) * m + +void BlockItem::arrangePins() { + //double w = g_main.rect().width(), h = g_main.rect().height(); + QVector pl = pins(); +// pl = pl.fromList(pins().toList()); + pins_.clear(); + foreach (BlockItemPin * p, pl) + pins_[p->alignment()] << p; + QVector cp = pins_.value(Qt::AlignBottom); + for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(_POS(pins_margin), bottom()); + cp = pins_.value(Qt::AlignTop); + for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(_POS(pins_margin), top()); + cp = pins_.value(Qt::AlignLeft); + for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(left(), _POS(pins_margin)); + cp = pins_.value(Qt::AlignRight); + for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(right(), _POS(pins_margin)); +} + +#undef _POS + + +void BlockItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { + //if () +} + + +QVariant BlockItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant & value) { + if (change == QGraphicsItem::ItemSelectedChange) + g_selection.setVisible(value.toBool()); + return QGraphicsItem::itemChange(change, value); +} diff --git a/qad/blockview/blockitem.h b/qad/blockview/blockitem.h new file mode 100644 index 0000000..aa2e763 --- /dev/null +++ b/qad/blockview/blockitem.h @@ -0,0 +1,207 @@ +#ifndef BLOCKITEM_H +#define BLOCKITEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "blockbase.h" +#include "alignedtextitem.h" +#include "chunkstream.h" + + +/// data: +/// 1002 - flag for move parent (true) +/// 1003 - flag for visualize selection (true) +/// 1004 - BlockItemPin ("pin") +/// 1005 - BlockBusItem ("connection") +/// 1006 - BlockItem ("item") +/// 1007 - BlockItem selection ("item_selection") +/// 1008 - item is NOT decor, ignore for function decors() (true) +/// 1009 - item is scene decor ("decor") +/// 1010 - BlockItem decor (src text for QGraphicsSimpleTextItem) +/// 1011 - item is BlockItem decor ("decor") +/// 1100 - flag for correct move (true) + + +class BlockItem; +class BlockBusItem; + + +class BlockItemPin: public QGraphicsItem, public PropertyStorage +{ + friend class BlockView; + friend class BlockItem; +public: + BlockItemPin(Qt::Alignment a = Qt::AlignLeft, int bus_type = 0, const QString & text_ = QString(), QGraphicsItem * parent_ = 0); + + enum State { + Disconnected, + Connected, + Hover, + Drop, + Accept, + Reject + }; + + enum Direction { + None = 0x0, + Input = 0x1, + Output = 0x2, + InputOutput = 0x3 + }; + + void setPen(const QPen & p) {ell_item.setPen(p);} + QPen pen() const {return ell_item.pen();} + void setBrush(const QBrush & b) {ell_item.setBrush(b);} + QBrush brush() const {return ell_item.brush();} + + int busType() const {return bus_type;} + Qt::Alignment alignment() const {return align;} + Direction direction() const {return dir;} + QString text() const {return text_item.text();} + State state() const {return state_;} + + void setBusType(int type_) {bus_type = type_;} + void setAlignment(Qt::Alignment a) {align = a; _init(true);} + void setDirection(Direction d) {dir = d; _init(true);} + void setText(const QString & t) {text_item.setText(t); _init(true);} + void setState(State s) {state_ = s; setBrush(br[int(state_)]); update();} + + void saveState() {sstate_.push(state_);} + bool restoreState() {if (sstate_.isEmpty()) return false; setState(sstate_.pop()); return true;} + void clearStateStack() {sstate_.clear();} + + void resizePin(double r = 7.); + + BlockItem * parent() const {return parent_;} + QList connectedBuses() const {return buses_;} + + enum {Type = UserType + 3}; + +protected: + void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0) {} + QRectF boundingRect() const {return ell_item.boundingRect().translated(ell_item.pos()) | text_item.boundingRect().translated(text_item.pos());} + int type() const {return Type;} + QVariant itemChange(GraphicsItemChange change, const QVariant & value); + void hoverEnterEvent(QGraphicsSceneHoverEvent * e); + void hoverLeaveEvent(QGraphicsSceneHoverEvent * e); + void _init(bool affect_parent = false); + void _reparent(); + int bus_type; + State state_; + QGraphicsEllipseItem ell_item; + QGraphicsSimpleTextItem text_item; + QStack sstate_; + QList buses_; + BlockItem * parent_; + Qt::Alignment align; + Direction dir; + QBrush br[6]; + +}; + + + + +class BlockItem: public QGraphicsObject, public PropertyStorage +{ + friend class BlockView; + friend class BlockItemPin; + friend class DrawTools; + Q_OBJECT +public: + BlockItem(QGraphicsItem * parent = 0); + ~BlockItem(); + + BlockItem * copy() const; + BlockItemPin * addPin(BlockItemPin * pin, bool update_ = true); + BlockItemPin * addPin(Qt::Alignment align, int bus_type, const QString & text, bool update_ = true); + void removePin(BlockItemPin * pin); + void addDecor(QGraphicsItem * item); + void addDecor(QGraphicsItem & item); + void removeDecor(QGraphicsItem * item); + QVector takePins(); + void clearPins(); + void clearDecors(); + QVector pins() const; + QList decors() const {return decors_;} + QList connectedBuses() const; + BlockItemPin * pinByText(const QString & t) const; + BlockItemPin * pinAtBus(BlockBusItem * bus) const; + QColor color() const {return col;} + void setColor(QColor c) {col = c; _resize(size());} + QSizeF size() const {return g_main.rect().size();} + qreal width() const {return size().width();} + qreal height() const {return size().height();} + int pinsMargin() const {return pins_margin;} + void setSize(QSizeF s) {_resize(s);} + void setSize(qreal w, qreal h) {setSize(QSizeF(w, h));} + void setWidth(qreal w) {setSize(QSizeF(w, size().height()));} + void setHeight(qreal h) {setSize(QSizeF(size().width(), h));} + void setPinsMargin(int marg) {if (marg > 1 && marg < 256) pins_margin = marg; arrangePins();} + + QByteArray saveModel(); + void loadModel(const QByteArray & data); + QByteArray save() const; + void load(const QByteArray & data); + void arrangePins(); + + enum {Type = UserType + 1}; + +protected: + void _resize(QSizeF s); + int type() const {return Type;} + QRectF boundingRect() const; + void mouseMoveEvent(QGraphicsSceneMouseEvent * event); + double left() const {return boundingRect().left();} + double right() const {return boundingRect().right();} + double top() const {return boundingRect().top();} + double bottom() const {return boundingRect().bottom();} + void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0); + QVariant itemChange(GraphicsItemChange change, const QVariant & value); + + QGraphicsRectItem g_main, g_selection; + int pins_margin; + QColor col; + QMap > pins_; + QList decors_; + +}; + + +inline QDataStream & operator <<(QDataStream & s, const BlockItemPin * p) { + ChunkStream cs; + cs << cs.chunk(1, int(p->alignment())) << cs.chunk(2, p->busType()) << cs.chunk(3, p->text()) << cs.chunk(4, p->toolTip()); + s << cs.data(); return s;} +inline QDataStream & operator >>(QDataStream & s, BlockItemPin *& p) { + ChunkStream cs(s); + p = new BlockItemPin(); + while (!cs.atEnd()) { + switch (cs.read()) { + case 1: p->setAlignment((Qt::Alignment)cs.getData()); break; + case 2: p->setBusType(cs.getData()); break; + case 3: p->setText(cs.getData()); break; + case 4: p->setToolTip(cs.getData()); break; + } + } + return s; +} + + +inline QDataStream & operator <<(QDataStream & s, const BlockItem * b) {s << b->save(); return s;} +inline QDataStream & operator >>(QDataStream & s, BlockItem *& b) { + QByteArray ba; s >> ba; + b = new BlockItem(); + b->load(ba); + return s; +} + + +#endif // BLOCKITEM_H diff --git a/qad/blockview/blockview.cpp b/qad/blockview/blockview.cpp new file mode 100644 index 0000000..92b7ac2 --- /dev/null +++ b/qad/blockview/blockview.cpp @@ -0,0 +1,1630 @@ +#include "blockview.h" +#include +#include +#include +#include +#include +#include +#include +#include + +const QString _BlockView_Mime_ = "_BlockView_copypaste_"; + + +BlockView::BlockView(QWidget * parent): QGraphicsView(parent), tmp_bus(true) { + _init(); +} + + +BlockView::BlockView(QGraphicsScene * scene, QWidget * parent): QGraphicsView(scene, parent), tmp_bus(true) { + _init(); +} + + +BlockView::~BlockView() { +} + + +void BlockView::_init() { + if (scene() == 0) { + scene_ = new QGraphicsScene; + setScene(scene_); + } + scene_ = scene(); + scene_->setSceneRect(-2500, -2500, 5000, 5000); + scene_->setItemIndexMethod(QGraphicsScene::NoIndex); + scene_->installEventFilter(this); + scene_->addItem(&tmp_bus); + widget_thumb.setParent(this); + //widget_thumb.setAutoFillBackground(true); + //widget_thumb.setStyleSheet("background-color: rgb(255, 0, 0);"); + widget_thumb.installEventFilter(this); + widget_thumb.setMouseTracking(true); + widget_thumb.show(); + widget_thumb.setWindowOpacity(0.); + thumb_anim.setTargetObject(this); + thumb_anim.setPropertyName("_thumb"); + thumb_anim.setEasingCurve(QEasingCurve::InCubic); + connect(scene_, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(adjustThumb())); + connect(scene_, SIGNAL(selectionChanged()), this, SLOT(sceneSelectionChanged())); + centerOn(scene_->sceneRect().center()); + setCacheMode(CacheBackground); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + setResizeAnchor(QGraphicsView::AnchorUnderMouse); + setRenderHint(QPainter::Antialiasing); + setRenderHint(QPainter::SmoothPixmapTransform); + setMouseTracking(true); + grid_visible = grid_snap = pm_connect = navigation = m_connect = m_trace_with_buses = minimap = true; + mm_drag = moved = new_branch = new_bus = mm_cancel = iconnect = mm_copy = m_pin_mc = mm_thumb = false; + match_bus = bus_from = 0; + mm_ci = 0; + hpin = 0; + grid_step = 10.; + grid_points = 1; + grid_pen = QPen(Qt::lightGray, 1, Qt::NoPen); + thumb_hide_delay = 500; + smode = BlockView::MultiSelection; + cur_scl = thumb_scl = 1.; + _talpha = 0.; + ae_enabled = true; + thumb_size = QSizeF(200, 200); + sel_rect.setZValue(999.); + sel_rect.hide(); + QColor sc = palette().color(QPalette::Highlight); + sc.setAlphaF(0.6); + QPen pen(sc.darker(200), 2., Qt::DotLine); + pen.setCosmetic(true); + sel_rect.setPen(pen); + sc.setAlphaF(0.2); + sel_rect.setBrush(QBrush(sc)); + + /*AlignedTextItem * ti = new AlignedTextItem("This is text!"); + ti->setFlag(QGraphicsItem::ItemIsSelectable, true); + ti->setFlag(QGraphicsItem::ItemIsMovable, true); + addItem(ti); + ti->setAlignment(Qt::AlignBottom | Qt::AlignLeft); + ti->setText("text\nt"); + QGraphicsSimpleTextItem * t__ = new QGraphicsSimpleTextItem("TEXT"); + t__->setFlags(QGraphicsItem::ItemIsSelectable); + addItem(t__); + addItem(new QGraphicsLineItem(0, -50, 0, 50)); + addItem(new QGraphicsLineItem(-50, 0, 50, 0)); + + for (int i = 0; i < 5; ++i) { + BlockItem * it = new BlockItem(); + it->setPos(i*150, i*20); + it->addPin(new BlockItemPin()); + if (i == 2) + it->setFlags(QGraphicsItem::ItemIsSelectable); + scene_->addItem(it); + } + QGraphicsItem * it = new QGraphicsRectItem(0, 0, 200, 100); + it->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); + it->setData(1001, true); + scene_->addItem(it); + + BlockBusItem * bus = new BlockBusItem(); + bus->setImages(QImage("icons/bus_twin.png"), QImage("icons/bus_end_rj45.png")); + bus->setEndpointsNumber(3); + bus->setBusType(1); + bus->appendPoint(QPointF(20, 40)); + bus->appendPoint(QPointF(150, -20)); + bus->appendPoint(QPointF(40, -80)); + //bus->setImages(QImage("icons/bus_twin.png"), QImage("icons/bus_end_rj45.png")); + addItem(bus); + bus = new BlockBusItem(); + bus->appendPoint(QPointF(-20, 40)); + bus->appendPoint(QPointF(100, -30)); + bus->appendPoint(QPointF(20, -60)); + addItem(bus);*/ +} + + +void BlockView::_updateBack() { + setCacheMode(CacheNone); + invalidateScene(); + setCacheMode(CacheBackground); +} + + +bool BlockView::eventFilter(QObject * o, QEvent * e) { + if (o == &widget_thumb) { + QMouseEvent * me = (QMouseEvent*)e; + switch (e->type()) { + case QEvent::Paint: + drawThumb(); + return true; + case QEvent::Enter: + thumbShow(); + break; + case QEvent::Leave: + restartTimer(timer_thumb, thumb_hide_delay); + break; + case QEvent::MouseButtonPress: + thumb_press = me->pos(); + widget_thumb.setCursor(Qt::ClosedHandCursor); + if (!thumb_vr.contains(thumb_press)) { + thumb_vr.moveCenter(thumb_press); + scrollFromThumb(); + } + break; + case QEvent::MouseButtonRelease: + widget_thumb.setCursor(Qt::OpenHandCursor); + break; + case QEvent::MouseMove: + if (me->buttons() == 0) + widget_thumb.setCursor(thumb_vr.contains(me->pos()) ? Qt::OpenHandCursor : Qt::CrossCursor); + if (me->buttons().testFlag(Qt::LeftButton)) { + thumb_vr.translate(me->pos() - thumb_press); + scrollFromThumb(); + thumb_press = me->pos(); + } + break; + default: break; + } + return QGraphicsView::eventFilter(o, e); + } + if (o == scene_) { + QGraphicsSceneMouseEvent * me = (QGraphicsSceneMouseEvent*)e; + QList mil; + QPointF mdp; + bool fmm_drag = false; + int btncnt = 0; + switch (e->type()) { + case QEvent::GraphicsSceneMouseDoubleClick: + mil = scene_->items(scene_point); + foreach (QGraphicsItem * i, mil) { + if (i->data(1006) == "item") { + emit blockDoubleClicked((BlockItem * )i); + break; + } + if (i->data(1005) == "connection") { + if (qgraphicsitem_cast(i)->isBusSelected()) { + emit busDoubleClicked(qgraphicsitem_cast(i)); + break; + } + } + } + //return true; + break; + /*case QEvent::GraphicsSceneHoverMove: + mil = scene_->items(scene_point); + mm_ci = (mil.isEmpty() ? 0 : mil.front()); + if (mm_ci != 0) { + while (mm_ci->data(1005).toString() == "connection") { + if (qgraphicsitem_cast(mm_ci)) + if (qgraphicsitem_cast(mm_ci)->isBusSelected()) + break; + if (mil.size() > 1) { + mm_ci = mil[1]; + mil.pop_front(); + } else { + mm_ci = 0; + break; + } + } + } + break;*/ + case QEvent::GraphicsSceneMousePress: + if (mm_ci != 0) + if (mm_ci->data(1008).toBool()) + break; + //qDebug() << "press"; + if (me->buttons().testFlag(Qt::LeftButton)) btncnt++; + if (me->buttons().testFlag(Qt::RightButton)) btncnt++; + if (me->buttons().testFlag(Qt::MidButton)) btncnt++; + mm_cancel = btncnt >= 2; + match_bus = bus_from = 0; + hpin = 0; + copy_dp = QPointF(); + //qDebug() << mm_cancel << mm_copy << mm_drag << new_branch << new_bus; + if (mm_copy && mm_cancel) { + deleteCopyTemp(); + mm_copy = moved = false; + unsetCursor(); + } + if (new_bus && mm_cancel) { + new_bus = false; + unmarkPins(true); + reconnectAll(); + tmp_bus.hide(); + tmp_bus.clear(); + } + if (new_branch && mm_cancel) { + new_branch = false; + tmp_bus.hide(); + tmp_bus.clear(); + } + if (moved && mm_cancel) { + moved = false; + restoreSelState(); + tmp_bus.hide(); + tmp_bus.clear(); + } + if (mm_cancel) return true; + mm_mods = me->modifiers(); + mm_drag = moved = false; + screen_point = me->screenPos(); + scene_point = me->scenePos(); + if (me->button() == Qt::MidButton) { + thumbShow(); + restartTimer(timer_thumb, thumb_hide_delay); + return true; + } + mil = scene_->items(scene_point); + mm_ci = (mil.isEmpty() ? 0 : mil.front()); + if (mil.isEmpty()) return true; + if (mm_ci != 0) { + if (mm_ci->data(1008).toBool()) + break; + while (mm_ci->data(1005).toString() == "connection") { + if (qgraphicsitem_cast(mm_ci)) + if (qgraphicsitem_cast(mm_ci)->isBusSelected()) + break; + if (mil.size() > 1) { + mm_ci = mil[1]; + mil.pop_front(); + } else { + mm_ci = 0; + break; + } + } + if (mm_ci->data(1003).toBool()) { + if (mil.size() > 1) { + mm_ci = mil[1]; + mil.pop_front(); + if (mm_ci->data(1003).toBool()) + if (mil.size() > 1) + mm_ci = mil[1]; + } else + mm_ci = 0; + } + if (mm_ci->data(1002).toBool()) { + while (mm_ci->parentItem() != 0) + mm_ci = mm_ci->parentItem(); + return true; + } + } + if (mm_ci) { + if (mm_ci->data(1004) == "pin" && m_connect) { + if (qgraphicsitem_cast(mm_ci)->state() == BlockItemPin::Hover) { + trace_from = mm_ci->scenePos(); + qgraphicsitem_cast(mm_ci)->clearStateStack(); + tmp_bus.setBusType(qgraphicsitem_cast(mm_ci)->busType()); + tmp_bus.setEndpointsNumber(3); + tmp_bus.clear(); + tmp_bus.show(); + new_bus = true; + newBusStarted(tmp_bus.busType()); + markPins(tmp_bus.busType()); + if (qgraphicsitem_cast(mm_ci)->alignment() == Qt::AlignLeft || + qgraphicsitem_cast(mm_ci)->alignment() == Qt::AlignRight) + wavetrace.setPreferredDirection(BlockViewWavetrace::Horizontal); + else + wavetrace.setPreferredDirection(BlockViewWavetrace::Vertical); + } + } + } + cur_scl = qSqrt(transform().determinant()); + //return true; + break; + case QEvent::GraphicsSceneMouseMove: + //qDebug() << "move" << (mm_ci != 0 ? mm_ci : 0); + if (mm_ci) + if (mm_ci->data(1008).toBool()) + break; + if (mm_cancel) return true; + if (me->buttons().testFlag(Qt::LeftButton)) { + if (!mm_drag) { + if ((screen_point - me->screenPos()).manhattanLength() >= QApplication::startDragDistance()) { + mm_drag = fmm_drag = true; + saveBusesState(); + } + } else { + if (tmp_bus.isVisible()) { + mil = scene_->items(me->scenePos()); + hpin = 0; + foreach (QGraphicsItem * i, mil) + if (i->data(1004) == "pin") { + hpin = qgraphicsitem_cast(i); + break; + } + if (hpin) { + if (hpin->state() == BlockItemPin::Accept) + hoverAcceptedPin(hpin); + else + hpin = 0; + } else + unhoverPins(); + if (new_branch) { + matchBus(); + break; + } + trace(trace_from, me->scenePos(), &tmp_bus); + matchBus(); + } + } + if (mm_mods.testFlag(Qt::ShiftModifier)) { + if (fmm_drag) { + fmm_drag = false; + if (mm_ci) { + if ((mm_ci->data(1006) == "item")) { + if (!mm_ci->isSelected() && sel_items.isEmpty()) { + clearSelection(); + mm_ci->setSelected(true); + } + } else { + mm_ci = 0; + break; + } + } else { + break; + } + sel_items = scene_->selectedItems(); + deleteCopyTemp(); + QList bi; + foreach (QGraphicsItem * i, sel_items) { + if (i->data(1006) == "item") { + //qDebug() << "copy"; + bi << qgraphicsitem_cast(i); + BlockItem * ti = bi.back()->copy(); + ti->g_main.setPen(QPen(ti->g_main.pen().color(), ti->g_main.pen().widthF(), Qt::DashLine)); + QColor bc = ti->g_main.brush().color(); bc.setAlphaF(bc.alphaF() * 0.5); + ti->g_main.setBrush(bc); + copy_items << ti; + scene_->addItem(ti); + } + } + QList ibi = internalBuses(bi); + foreach (BlockBusItem * i, ibi) { + i = i->copy(); + i->setOpacity(i->opacity() * 0.5); + copy_buses << i; + scene_->addItem(i); + } + mm_copy = true; + setCursor(Qt::DragCopyCursor); + } + } else { + if (smode == BlockView::SingleSelection) { + if (fmm_drag) { + clearSelection(); + if (mm_ci != 0) { + mm_ci->setSelected(true); + } + saveSelState(); + } + } + if (smode == BlockView::MultiSelection) { + sel_rect.setRect(QRectF(scene_point, me->scenePos()).normalized()); + if (fmm_drag) { + if (mm_ci == 0) { + scene_->addItem(&sel_rect); + sel_rect.show(); + if (!mm_mods.testFlag(Qt::ControlModifier)) + clearSelection(); + } else { + if (!mm_mods.testFlag(Qt::ControlModifier) && !mm_ci->isSelected()) { + clearSelection(); + mm_ci->setSelected(true); + } + } + saveSelState(); + if (mm_ci != 0) + if (!sel_items.contains(mm_ci)) + mm_ci = 0; + } + } + } + if (sel_rect.isVisible()) + applySelRect(me); + else { + if (mm_drag && mm_ci != 0) { + mdp = (me->scenePos() - scene_point); + if (grid_snap) + mdp = quantize(mdp, grid_step); + if (!mdp.isNull()) { + scene_point += mdp; + copy_dp += mdp; + } + if (mm_copy) { + if (!mdp.isNull()) + moved = true; + foreach (QGraphicsItem * i, copy_items) + i->setPos(i->pos() + mdp); + foreach (BlockBusItem * i, copy_buses) + i->movePolyline(mdp); + } + if (!mm_mods.testFlag(Qt::ControlModifier) && !mm_mods.testFlag(Qt::ShiftModifier)) { + if (!mdp.isNull()) + moved = true; + foreach (QGraphicsItem * i, sel_items) + if (i->flags().testFlag(QGraphicsItem::ItemIsMovable)) + i->setPos(i->pos() + mdp); + moveBuses(sel_items, mdp); + setCursor(Qt::ClosedHandCursor); + } + return true; + } + } + if (mm_ci) + if (mm_ci->data(1100).toBool()) + return true; + } + if (me->modifiers().testFlag(Qt::ControlModifier) && me->buttons() != 0 && mm_ci == 0) + return true; + //qDebug() << "scene mouse"; + //return true; + break; + case QEvent::GraphicsSceneMouseRelease: + if (me->buttons().testFlag(Qt::LeftButton)) btncnt++; + if (me->buttons().testFlag(Qt::RightButton)) btncnt++; + if (me->buttons().testFlag(Qt::MidButton)) btncnt++; + mm_cancel = btncnt > 0; + if (mm_cancel || me->button() == Qt::MidButton) { + mm_ci = 0; + return true; + } + if (mm_ci) + if (mm_ci->data(1008).toBool()) { + mm_ci = 0; + break; + } + if (mm_copy) { + QList ai; + blockSignals(true); + if (moved) { + QList ci; + QList bi; + foreach (QGraphicsItem * b, sel_items) + if (b->data(1006) == "item") { + ci << qgraphicsitem_cast(b); + ai << qgraphicsitem_cast(b); + } + bi = internalBuses(ci); + if (!ci.isEmpty()) copyBlocks(ci, copy_dp); + if (!bi.isEmpty()) copyBuses(bi, copy_dp); + } + deleteCopyTemp(); + blockSignals(false); + if (moved) { + moved = false; + reconnectAll(); + emitActionEvent(BlockItemBase::BlockCopy, ai); + } + } + if (new_branch) { + tmp_bus.hide(); + } + if (moved && pm_connect) { + QList ci; + foreach (QGraphicsItem * b, sel_items) + if (b->data(1006) == "item") + ci << b; + simplifyBuses(); + emitActionEvent(BlockItemBase::BlockMove, ci); + reconnectAll(); + } + moved = mm_copy = false; + if (tmp_bus.isVisible()) { + //qDebug() << "!!!"; + if (match_bus == 0) { + BlockBusItem * nb = new BlockBusItem(tmp_bus); + loadBus(nb); + addItem(nb); + } else { + if (connectTmpToBus(match_bus)) { + emitActionEvent(BlockItemBase::BusAdd, QList() << match_bus); + emit connectionsChanged(); + } + } + unmarkPins(); + tmp_bus.hide(); + tmp_bus.clear(); + reconnectAll(); + } + clearBusStates(); + if (!mm_drag) { + switch (smode) { + case SingleSelection: + clearSelection(); + if (mm_ci) + mm_ci->setSelected(true); + break; + case MultiSelection: + if (mm_ci == 0 || !me->modifiers().testFlag(Qt::ControlModifier)) { + clearSelection(); + if (mm_ci) + mm_ci->setSelected(true); + } else { + if (mm_ci != 0) { + if (me->modifiers().testFlag(Qt::ControlModifier)) { + if (mm_ci->data(1006) == "item") + mm_ci->setSelected(!mm_ci->isSelected()); + } else + mm_ci->setSelected(true); + } + } + break; + default: + clearSelection(); + break; + } + } + sel_rect.hide(); + if (sel_rect.scene()) + scene_->removeItem(&sel_rect); + mm_drag = false; + mm_ci = 0; + unsetCursor(); + break; + default: break; + } + } + return QGraphicsView::eventFilter(o, e); +} + + +void BlockView::stopTimer(int & tid) { + if (tid > 0) killTimer(tid); + tid = 0; +} + + +void BlockView::restartTimer(int & tid, int msecs) { + stopTimer(tid); + tid = startTimer(msecs); +} + + +void BlockView::timerEvent(QTimerEvent * e) { + if (e->timerId() == timer_thumb) { + thumbHide(); + stopTimer(timer_thumb); + return; + } + QGraphicsView::timerEvent(e); +} + + +void BlockView::wheelEvent(QWheelEvent * event) { + if (!navigation) return; + if (event->modifiers().testFlag(Qt::ControlModifier)) { + double scl = 1. + event->delta() / 500.; + scale(scl, scl); + return; + } + QGraphicsView::wheelEvent(event); +} + + +void BlockView::mousePressEvent(QMouseEvent * event) { + press_point = event->pos(); + QGraphicsView::mousePressEvent(event); +} + + +void BlockView::mouseMoveEvent(QMouseEvent * event) { + if (navigation) { + if (event->buttons().testFlag(Qt::MidButton)) { + QPoint dp = (press_point - event->pos()); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dp.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() + dp.y()); + press_point = event->pos(); + return; + } + } + QGraphicsView::mouseMoveEvent(event); +} + + +void BlockView::keyPressEvent(QKeyEvent * e) { + if (e->key() == Qt::Key_Shift) { + if (tmp_bus.isVisible()) { + wavetrace.setPreferredDirection((BlockViewWavetrace::Direction)(1 - wavetrace.preferredDirection())); + trace(last_trace_from, trace_to, &tmp_bus); + } + return; + } + QGraphicsView::keyPressEvent(e); +} + + +void BlockView::resizeEvent(QResizeEvent * event) { + QGraphicsView::resizeEvent(event); + adjustThumb(); +} + + +void BlockView::scrollContentsBy(int dx, int dy) { + QGraphicsView::scrollContentsBy(dx, dy); + if (isHidden()) return; + thumbShow(); + restartTimer(timer_thumb, thumb_hide_delay); + QMetaObject::invokeMethod(&widget_thumb, "repaint", Qt::QueuedConnection); +} + + +void BlockView::drawBackground(QPainter * painter, const QRectF & rect) { + QGraphicsView::drawBackground(painter, rect); + if (mm_thumb) return; + float rx, ry, sx = grid_step, sy = grid_step; + double scl = qRound(1. / qSqrt(transform().determinant())); + painter->eraseRect(rect); + painter->setRenderHint(QPainter::Antialiasing, false); + if (scl > 0.) { + sx *= scl; + sy *= scl; + } + if (!grid_visible) return; + rx = quantize(rect.left(), sx); + ry = quantize(rect.top(), sy); + bool gp = grid_points > 0.5; + if (gp) { + QPen pp(grid_pen.color(), grid_points, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + pp.setCosmetic(true); + painter->setPen(pp); + for(int i = 0; i < qCeil(rect.width() / sx) + 1; ++i) + for(int j = 0; j < qCeil(rect.height() / sy) + 1; ++j) + painter->drawPoint(rx + i * sx, ry + j * sy); + } + if (grid_pen.style() == Qt::NoPen) return; + painter->setPen(grid_pen); + for(int i = 0; i < qCeil(rect.width() / sx) + 1; ++i) { + double cx = rx + i * sx; + painter->drawLine(cx, ry, cx, ry + rect.height()); + } + for(int j = 0; j < qCeil(rect.height() / sy) + 1; ++j) { + double cy = ry + j * sy; + painter->drawLine(rx, cy, rx + rect.width(), cy); + } +} + + +void BlockView::scrollFromThumb() { + QRect r(thumb_vr); + double scl(thumb_scl); + horizontalScrollBar()->setValue(r.x() / scl + horizontalScrollBar()->minimum()); + verticalScrollBar()->setValue(r.y() / scl + verticalScrollBar()->minimum()); +} + + +void BlockView::deleteCopyTemp() { + qDeleteAll(copy_items); + copy_items.clear(); + qDeleteAll(copy_buses); + copy_buses.clear(); +} + + +void BlockView::emitActionEvent(BlockItemBase::Action action, QList items) { + if (!ae_enabled) return; + emit actionEvent(action, items); +} + + +void BlockView::drawThumb() { + if (!minimap) return; + QPainter p(&widget_thumb); + QRect wr = widget_thumb.rect().adjusted(0, 0, -1, -1); + QSizeF sr = sceneRect().size(), tr; + if (sr.width() >= sr.height()) + thumb_scl = thumb_size.width() / sr.width(); + else + thumb_scl = thumb_size.height() / sr.height(); + tr = sr * thumb_scl; + cur_scl = qSqrt(transform().determinant()); + thumb_scl /= cur_scl; + QSizeF vs(size().width() - verticalScrollBar()->width(), size().height() - horizontalScrollBar()->height()); + QRectF vr(QPointF(horizontalScrollBar()->value() - horizontalScrollBar()->minimum(), + verticalScrollBar()->value() - verticalScrollBar()->minimum()) * thumb_scl, vs * thumb_scl); + vr.adjust(0, 0, -1, -1); + + p.setBrush(Qt::lightGray); + p.setOpacity(0.5 * _talpha); + p.drawRect(wr); + p.drawImage(0, 0, im_scene); + p.setBrush(Qt::NoBrush); + p.drawRect(wr); + p.setBrush(Qt::white); + p.setRenderHint(QPainter::Antialiasing); + p.drawRect(vr); + thumb_sr = wr; + thumb_vr = vr.toRect(); +} + + +void BlockView::drawSceneThumb() { + if (!minimap) return; + QRect wr = widget_thumb.rect().adjusted(0, 0, -1, -1); + im_scene = QImage(wr.size(), QImage::Format_ARGB32); + im_scene.fill(Qt::transparent); + QPainter p(&im_scene); + p.setRenderHint(QPainter::Antialiasing); + mm_thumb = true; + scene_->render(&p, im_scene.rect()); + mm_thumb = false; +} + + +void BlockView::thumbHide() { + if (!minimap) { + widget_thumb.hide(); + return; + } + if (QApplication::widgetAt(QCursor::pos()) == &widget_thumb) return; + thumb_anim.stop(); + thumb_anim.setDuration(1000); + thumb_anim.setStartValue(_thumb()); + thumb_anim.setEndValue(0.); + thumb_anim.start(); + //qDebug() << "hide" << thumb_anim.startValue() << thumb_anim.endValue(); + //widget_thumb.hide(); +} + + +void BlockView::thumbShow() { + if (!minimap) return; + if (widget_thumb.isHidden() || (_talpha < 0.1)) drawSceneThumb(); + thumb_anim.stop(); + /*thumb_anim.setDuration(100); + thumb_anim.setStartValue(_thumb()); + thumb_anim.setEndValue(1.); + thumb_anim.start();*/ + _setThumb(1.); + //qDebug() << "show" << thumb_anim.startValue() << thumb_anim.endValue(); + //widget_thumb.show(); +} + + +void BlockView::clearSelection() { + sel_items.clear(); + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + i->setSelected(false); +} + + +void BlockView::addItem(QGraphicsItem * item) { + scene_->addItem(item); + applyGridStep(); + if (item->data(1005) == "connection") { + loadBus(qgraphicsitem_cast(item)); + connect((BlockBusItem*)item, SIGNAL(destroyed(QObject*)), this, SLOT(removedBus(QObject*)), Qt::UniqueConnection); + emitActionEvent(BlockItemBase::BusAdd, QList() << item); + emit connectionsChanged(); + return; + } + if (item->data(1006) == "item") { + connect((BlockItem*)item, SIGNAL(destroyed(QObject*)), this, SLOT(removedBlock(QObject*)), Qt::UniqueConnection); + emitActionEvent(BlockItemBase::BlockAdd, QList() << item); + return; + } + item->setData(1009, "decor"); +} + + +QList BlockView::buses() const { + QList ret; + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->data(1005) == "connection") + if (!copy_buses.contains((BlockBusItem*)i)) + ret << qgraphicsitem_cast(i); + return ret; +} + + +QList BlockView::wrongConnectedBuses() const { + QList sl = buses(), ret; + QList bl = blocks(); + foreach (BlockItem * b, bl) { + QVector pins = b->pins(); + foreach (BlockItemPin * p, pins) + if (p->state() == BlockItemPin::Reject) { + QPointF pp = p->scenePos(); + foreach (BlockBusItem * s, sl) + if (s->pol.contains(pp)) + if (!ret.contains(s)) + ret << s; + } + } + return ret; +} + + +QList BlockView::blocks() const { + QList ret; + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->data(1006) == "item") + ret << qgraphicsitem_cast(i); + return ret; +} + + +QList BlockView::decors() const { + QList ret, gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if ((i->data(1009) == "decor") && !i->data(1008).toBool() && (i->parentItem() == 0) && (i != &sel_rect) && (i != &tmp_bus)) + ret << i; + return ret; +} + + +BlockBusItem * BlockView::connectionBus(BlockItem * b0, BlockItem * b1) const { + QList cbl = connectionBuses(b0, b1); + if (cbl.isEmpty()) return 0; + return cbl.front(); +} + + +QList BlockView::connectionBuses(BlockItem * b0, BlockItem * b1) const { + if (!b0 || !b1) return QList(); + QSet bs0 = b0->connectedBuses().toSet(), bs1 = b1->connectedBuses().toSet(); + return (bs0 & bs1).values(); +} + + +bool BlockView::connectPins(BlockItemPin * p0, BlockItemPin * p1) { + if (!p0 || !p1) return false; + if (p0 == p1) return false; + if (p0->busType() != p1->busType()) return false; + QList bl0 = p0->connectedBuses(), bl1 = p1->connectedBuses(); + if (!(bl0.toSet() & bl1.toSet()).isEmpty()) return true; + BlockBusItem * nb = new BlockBusItem(); + nb->setBusType(p0->busType()); + //nb->setEndpointsNumber(3); + loadBus(nb); + if (!bl0.isEmpty() && !bl1.isEmpty()) { // connect two existing buses + } else { + if ((bl0.isEmpty() && !bl1.isEmpty()) || (bl1.isEmpty() && !bl0.isEmpty())) { // connect empty pin to existing bus + BlockItemPin * ep = 0; + BlockBusItem * eb = 0; + if (bl0.isEmpty()) {ep = p0; eb = bl1[0];} + else {ep = p1; eb = bl0[0];} + double md = -1; int mi = -1; + QPointF sp = ep->scenePos(); + if (eb->pol.size() == 2) { + eb->selSegment = 0; + eb->addPoint((eb->pol[0] + eb->pol[1]) / 2.); + eb->selPoint = -1; + mi = 2; + } else { + for (int i = 0; i < eb->pol.size(); ++i) { + if (eb->ends.contains(i)) continue; + double cd = QVector2D(sp - eb->pol[i]).lengthSquared(); + if (md < 0 || md > cd) { + md = cd; + mi = i; + } + } + } + if (mi < 0) { + return false; + } + trace(ep->scenePos(), eb->pol[mi], nb); + if (nb->pol.size() < 2) { + delete nb; + return false; + } + nb->pol.pop_back(); + int lp = eb->pol.size(); + eb->pol << nb->pol; + for (int i = 0; i < nb->pol.size() - 1; ++i) + eb->segments << QPair(lp + i, lp + i + 1); + eb->segments << QPair(mi, lp + nb->pol.size() - 1); + eb->updateGeometry(); + delete nb; + } else { // connect two empty pins + trace(p0->scenePos(), p1->scenePos(), nb); + if (nb->pol.isEmpty()) { + delete nb; + return false; + } + addItem(nb); + } + } + reconnectAll(); + emitActionEvent(BlockItemBase::BusAdd, QList() << nb); + emit connectionsChanged(); + return true; +} + + +void BlockView::restoreSelState() { + foreach (QGraphicsItem * i, sel_items) { + i->setPos(i->data(1001).toPointF()); + } + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->data(1005) == "connection") { + BlockBusItem * bi = qgraphicsitem_cast(i); + bi->pol = bi->bpol; + bi->prepareGeometryChange(); + } +} + + +void BlockView::saveSelState() { + QList gi = scene_->items(); + sel_items = scene_->selectedItems(); + foreach (QGraphicsItem * i, gi) { + i->setData(1000, i->isSelected()); + i->setData(1001, i->pos()); + if (i->data(1005) == "connection") + qgraphicsitem_cast(i)->bpol = qgraphicsitem_cast(i)->pol; + } +} + + +void BlockView::saveBusesState() { + QList bl = buses(); + foreach (BlockBusItem * b, bl) + b->saveState(); +} + + +void BlockView::restoreBusesState() { + QList bl = buses(); + foreach (BlockBusItem * b, bl) + b->restoreState(); +} + + +void BlockView::applySelRect(QGraphicsSceneMouseEvent * me) { + QList ci = sel_rect.collidingItems(Qt::IntersectsItemBoundingRect); + QList gi = scene_->items(); + bool add = me->modifiers().testFlag(Qt::ControlModifier); + if (!add) clearSelection(); + else { + foreach (QGraphicsItem * i, gi) + i->setSelected(i->data(1000).toBool()); + } + foreach (QGraphicsItem * i, ci) { + i->setSelected(!i->isSelected()); + } +} + + +void BlockView::applyGridStep() { + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->type() == QGraphicsItem::UserType + 2) + qgraphicsitem_cast(i)->setGridStep(grid_step); +} + + +void BlockView::trace(QPointF scene_pos_from, QPointF scene_pos_to, BlockBusItem * bus) { + if (hpin) + scene_pos_to = hpin->scenePos(); + last_trace_from = scene_pos_from; + trace_to = scene_pos_to; + QRect sr = scene_->sceneRect().toRect(); + int dx = sr.left() / grid_step, dy = sr.top() / grid_step; + //qDebug() << dp; + QPoint dp(-dx, -dy), qpt = quantize(scene_pos_to, grid_step).toPoint() / grid_step + dp; + QTime tm; + tm.restart(); + wavetrace.resize(sr.size() / grid_step); + wavetrace.fill(BlockViewWavetrace::Empty); + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->data(1006) == "item") { + QRect ir = i->mapRectToScene(i->boundingRect()).toRect().normalized(); + wavetrace.fill(QRect(ir.topLeft() / grid_step + dp, ir.bottomRight() / grid_step + dp), BlockViewWavetrace::Blocked); + QVector pins = qgraphicsitem_cast(i)->pins(); + foreach (BlockItemPin * p, pins) { + if (p->busType() == bus->busType()) + wavetrace.fill(quantize(p->scenePos(), grid_step).toPoint() / grid_step + dp, BlockViewWavetrace::Empty); + } + } + if (m_trace_with_buses) { + foreach (QGraphicsItem * i, gi) + if (i->data(1005) == "connection") { + BlockBusItem * b = qgraphicsitem_cast(i); + if (!b) continue; + for (int s = 0; s < b->segments.size(); ++s) { + QPointF p0 = b->pol[b->segments[s].first], p1 = b->pol[b->segments[s].second], cp = p0; + double sx(0.), sy(0.), dx = qAbs(p1.x() - p0.x()), dy = qAbs(p1.y() - p0.y()); + double signx = (p1.x() >= p0.x() ? 1. : -1.), signy = (p1.y() >= p0.y() ? 1. : -1.); + int steps(0); + if ((dx + dy) < grid_step) continue; + if (dx >= dy) { // by x + sx = grid_step; + sy = sx * dy / dx; + steps = qRound(dx / grid_step); + } else { + sy = grid_step; + sx = sy * dx / dy; + steps = qRound(dy / grid_step); + } + sx *= signx; + sy *= signy; + //qDebug() << "fill" << p0 << "->" << p1 << "in" << steps << sx << sy; + for (int j = 0; j < steps; ++j) { + QPoint tp = quantize(cp, grid_step).toPoint() / grid_step + dp; + if (tp != qpt) + wavetrace.fill(tp, BlockViewWavetrace::Blocked); + //qDebug() << " set" << cp; + cp += QPointF(sx, sy); + } + } + } + } + bus->clear(); + if (wavetrace.trace(quantize(scene_pos_from, grid_step).toPoint() / grid_step + dp, qpt)) { + wavetrace.gatherPath(); + foreach (const QPoint & p, wavetrace.path()) { + bus->appendPoint((p - dp) * grid_step); + } + } + //qDebug() << quantize(scene_pos_from, grid_step).toPoint() / grid_step + dp << qpt; + scene_->update(); +} + + +void BlockView::clearBusStates() { + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->data(1005) == "connection") { + BlockBusItem * b = qgraphicsitem_cast(i); + b->clearBusState(); + if (i != bus_from && i != match_bus) + b->selPoint = b->selSegment = -1; + } +} + + +void BlockView::matchBus() { + match_bus = 0; + bool bv = tmp_bus.isVisible(); + QList gi = scene_->items(); + QList buses; + QList blockl; + int sp = -1, ss = -1; + QPointF point; + iconnect = false; + if (!tmp_bus.pol.isEmpty()) + point = tmp_bus.pol.back(); + foreach (QGraphicsItem * i, gi) { + if (i != bus_from) { + if (i->data(1005) == "connection") + buses << qgraphicsitem_cast(i); + if (i->data(1006) == "item") + blockl << qgraphicsitem_cast(i); + } + } + foreach (BlockBusItem * b, buses) { + b->clearBusState(); + b->selPoint = b->selSegment = -1; + } + if (!bv) return; + BlockBusItem * b(0); + if (m_pin_mc) { + foreach (BlockItem * b_, blockl) + foreach (BlockItemPin * p_, b_->pins()) + if (p_->scenePos() == point) { + + return; + } + } + //qDebug() << "1" << buses.size() << tmp_bus.pol; + for (int i = 0; i < buses.size(); ++i) { + b = buses[i]; + b->testPoint(point, &sp, &ss); + //qDebug() << i << sp << ss; + if (sp >= 0 || ss >= 0) break; + } + if ((sp < 0 && ss < 0) || b == 0) return; + //qDebug("2"); + match_bus = b; + if ((b->busType() != tmp_bus.busType()) || b->connections_.value(sp, 0) != 0) { + b->setBusState(false); + } else { + if (b->max_ep >= 2) { + if (bus_from == 0) { + if (ss >= 0) { + if (b->endpointCount() >= b->max_ep) { + b->setBusState(false); + return; + } + } + if (sp >= 0) { + if (b->endpointCount() + b->pointSegmentsCount(sp) - 2 >= b->max_ep) { + b->setBusState(false); + return; + } + } + } else { + int sep = b->endpointCount() + bus_from->endpointCount(); + if (b->pointSegmentsCount(sp) == 1) sep--; + if (bus_from->selPoint >= 0) + if (bus_from->pointSegmentsCount(bus_from->selPoint) == 1) sep--; + if (sep > b->max_ep) { + b->setBusState(false); + return; + } + } + } + //b->press_point = point; + iconnect = true; + b->setBusState(true); + b->selPoint = sp; + b->selSegment = ss; + } +} + + +bool BlockView::connectTmpToBus(BlockBusItem * bus) { + if (bus == 0) return false; + if (!bus->busState()) return false; + if (tmp_bus.pol.size() < 2) return false; + int np = bus->selPoint; + if (np < 0) + np = bus->addPoint(tmp_bus.pol.back()); + if (np < 0) return false; + tmp_bus.pol.pop_back(); + int lp = bus->pol.size(); + bus->pol << tmp_bus.pol; + for (int i = 0; i < tmp_bus.pol.size() - 1; ++i) + bus->segments << QPair(lp + i, lp + i + 1); + bus->segments << QPair(np, lp + tmp_bus.pol.size() - 1); + bus->updateGeometry(); + tmp_bus.clear(); + return true; +} + + +void BlockView::markPins(int bus_type) { + unhoverPins(); + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) { + if (i->data(1004) == "pin") { + BlockItemPin * p = qgraphicsitem_cast(i); + p->saveState(); + if (m_pin_mc) { + if (p->busType() == tmp_bus.busType()) + p->setState(BlockItemPin::Accept); + } else { + if (p->busType() == tmp_bus.busType() && p->state() == BlockItemPin::Disconnected) + p->setState(BlockItemPin::Accept); + } + } + } +} + + +void BlockView::unmarkPins(bool to_normal) { + unhoverPins(); + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) { + if (i->data(1004) == "pin") { + qgraphicsitem_cast(i)->restoreState(); + if (to_normal) + while (qgraphicsitem_cast(i)->restoreState()); + } + } +} + + +void BlockView::hoverAcceptedPin(BlockItemPin * pin) { + if (!pin) return; + pin->resizePin(12.); +} + + +void BlockView::unhoverPins() { + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->data(1004) == "pin") + ((BlockItemPin*)i)->resizePin(); +} + + +void BlockView::simplifyBuses() { + QList bl = buses(); + foreach (BlockBusItem * b, bl) + b->simplify(); +} + + +void BlockView::moveBuses(const QList & items, QPointF dp) { + if (dp.isNull()) return; + QList gi = scene_->items(); + QVector pins; + QList buses; + //qDebug() << "move" << dp; + foreach (QGraphicsItem * i, items) + if (i->data(1006) == "item" && i->flags().testFlag(QGraphicsItem::ItemIsMovable)) + pins << qgraphicsitem_cast(i)->pins(); + foreach (QGraphicsItem * i, gi) + if (i->data(1005) == "connection") + buses << qgraphicsitem_cast(i); + foreach (BlockBusItem * b, buses) { + QList bpins = b->connections_.values(); + if (!bpins.isEmpty()) { + foreach (BlockItemPin * p, pins) + bpins.removeAll(p); + if (bpins.isEmpty()) { + b->movePolyline(dp); + continue; + } + } + foreach (BlockItemPin * p, pins) { + QList ends = b->connections_.keys(p); + for (int i = 0; i < ends.size(); ++i) { + /*int isp = b->segmentPointPair(ends[i]); + QPointF sdp; + if (isp >= 0 && b->pol.size() > 2) { + sdp = b->pol[isp] - b->pol[ends[i]]; + if (!sdp.isNull()) { + if (sdp.x() == 0. && dp.x() != 0.) + b->movePoint(isp, QPointF(dp.x(), 0.)); + if (sdp.y() == 0. && dp.y() != 0.) + b->movePoint(isp, QPointF(0., dp.y())); + } else { + if (p->alignment() == Qt::AlignTop || p->alignment() == Qt::AlignBottom) + b->movePoint(isp, QPointF(dp.x(), 0.)); + if (p->alignment() == Qt::AlignLeft || p->alignment() == Qt::AlignRight) + b->movePoint(isp, QPointF(0., dp.y())); + } + }*/ + QPointF pdp = dp; + double ang = 0.; + switch (p->alignment()) { + case Qt::AlignRight : pdp.setX(0.); ang = 0.; break; + case Qt::AlignTop : pdp.setY(0.); ang = 90.; break; + case Qt::AlignLeft : pdp.setX(0.); ang = 180.; break; + case Qt::AlignBottom: pdp.setY(0.); ang = 270.; break; + default: break; + } + QVector epl = b->endpointLine(ends[i], ang); + foreach (int e, epl) + b->movePoint(e, pdp); + b->movePoint(ends[i], dp); + } + } + } +} + + +QList BlockView::internalBuses(const QList & items) { + QList ret; + if (items.isEmpty()) return ret; + QList sbl = buses(); + QSet sis = QSet::fromList(items); + foreach (BlockBusItem * bi, sbl) { + QSet bis = QSet::fromList(bi->connectedBlocks()); + if ((bis - sis).isEmpty()) + ret << bi; + } + return ret; +} + + +QList BlockView::selectedBlocks() const { + QList ret; + QList sil = scene()->selectedItems(); + foreach (QGraphicsItem * b, sil) + if (b->data(1006) == "item") + ret << qgraphicsitem_cast(b); + return ret; +} + + +QList BlockView::selectedDecors() const { + QList ret, sil = decors(); + foreach (QGraphicsItem * b, sil) + if (b->isSelected()) + ret << b; + return ret; +} + + +void BlockView::adjustThumb() { + if (!scene()) return; + QSizeF sr = sceneRect().size(), tr; + double scl; + if (sr.width() >= sr.height()) + scl = thumb_size.width() / sr.width(); + else + scl = thumb_size.height() / sr.height(); + tr = sr * scl; + widget_thumb.setGeometry(QRect(QPoint(width() - tr.width() - 10 - verticalScrollBar()->width(), + height() - tr.height() - 10 - horizontalScrollBar()->height()), tr.toSize())); +} + + +void BlockView::newBranch(BlockBusItem * item) { + bus_from = item; + newBusStarted(item->busType()); + markPins(item->busType()); + new_branch = true; + tmp_bus.setBusType(item->busType()); + if (item->selSegment >= 0) { + QPointF ds(item->pol[item->segments[item->selSegment].first] - item->pol[item->segments[item->selSegment].second]); + if (ds.x() == 0.) wavetrace.setPreferredDirection(BlockViewWavetrace::Horizontal); + if (ds.y() == 0.) wavetrace.setPreferredDirection(BlockViewWavetrace::Vertical); + } +} + + +void BlockView::newBranchTrace(BlockBusItem * item, QPointF to) { + trace(item->press_pos, to, &tmp_bus); + tmp_bus.show(); +} + + +void BlockView::newBranchAccept(BlockBusItem * item) { + unmarkPins(); + if (!new_branch) return; + new_branch = false; + tmp_bus.hide(); + if (tmp_bus.pol.size() < 2) return; + tmp_bus.pol.pop_front(); + int np = item->addPoint(item->press_pos); + if (np < 0) return; + if (match_bus) { + if (iconnect) tmp_bus.pol.pop_back(); + else return; + } + if (item == match_bus) return; + int snp = np; + int lp = item->pol.size(); + if (!tmp_bus.pol.isEmpty()) { + item->pol << tmp_bus.pol; + item->segments << QPair(np, lp); + for (int i = 0; i < tmp_bus.pol.size() - 1; ++i) + item->segments << QPair(lp + i, lp + i + 1); + } + if (match_bus != 0) { + if (!iconnect) return; + np = match_bus->selPoint; + if (np < 0) + np = match_bus->addPoint(trace_to); + if (np < 0) return; + lp = item->pol.size(); + item->pol << match_bus->pol; + for (int i = 0; i < match_bus->segments.size(); ++i) + item->segments << QPair(match_bus->segments[i].first + lp, match_bus->segments[i].second + lp); + if (tmp_bus.pol.isEmpty()) + item->segments << QPair(lp + np, snp); + else + item->segments << QPair(lp + np, lp - 1); + match_bus->setProperty("_nodelete_", true); + match_bus->deleteLater(); + match_bus = 0; + } + item->updateGeometry(); + emitActionEvent(BlockItemBase::BusAdd, QList() << item); + emit connectionsChanged(); + tmp_bus.clear(); +} + + +void BlockView::newBranchCancel() { + unmarkPins(); + //qDebug() << "cancel"; + new_branch = false; + tmp_bus.hide(); + tmp_bus.clear(); +} + + +void BlockView::removedBus(QObject * o) { + mm_ci = 0; + reconnectAll(); + BlockBusItem * bus = (BlockBusItem*)o; + if (bus->property("_nodelete_").toBool()) return; + emitActionEvent(BlockItemBase::BusRemove, QList() << bus); + emit connectionsChanged(); +} + + +void BlockView::removedBlock(QObject * o) { + emit blockRemoved((BlockItem*)o); + emitActionEvent(BlockItemBase::BlockRemove, QList() << qgraphicsitem_cast((BlockItem*)o)); +} + + +void BlockView::removeJunk() { + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) { + if (i->data(1005) != "connection") continue; + BlockBusItem * b = qgraphicsitem_cast(i); + if (b->pol.size() <= 1) { + b->deleteLater(); + } + } +} + + +void BlockView::sceneSelectionChanged() { + bool ie = scene()->selectedItems().isEmpty(); + emit copyEnabledChanged(!ie); +} + + +void BlockView::_setThumb(double v) { + _talpha = v; + QMetaObject::invokeMethod(&widget_thumb, "repaint", Qt::QueuedConnection); + if (_talpha <= 0.01) widget_thumb.hide(); + else widget_thumb.show(); +} + + +void BlockView::reconnectAll() { + //qDebug() << "reconnect"; + removeJunk(); + QList gi = scene_->items(); + QList pins; + QList buses; + foreach (QGraphicsItem * i, gi) { + if (i->data(1004) == "pin") + pins << qgraphicsitem_cast(i); + if (i->data(1005) == "connection") + buses << qgraphicsitem_cast(i); + } + foreach (BlockItemPin * p, pins) { + p->setState(BlockItemPin::Disconnected); + p->buses_.clear(); + } + foreach (BlockBusItem * b, buses) { + b->connections_.clear(); + QVector conns(b->endpoints()); + for (int c = 0; c < conns.size(); ++c) { + QPointF cp = b->pol[conns[c]]; + for (int j = 0; j < pins.size(); ++j) { + if (!pins[j]->isVisible()) continue; + QPointF pp = pins[j]->scenePos(); + if (cp == pp) { + //qDebug() << "found"; + if (b->busType() == pins[j]->busType()) { + b->connections_[conns[c]] = pins[j]; + if (!pins[j]->buses_.contains(b)) + pins[j]->buses_ << b; + pins[j]->setState(BlockItemPin::Connected); + } else + pins[j]->setState(BlockItemPin::Reject); + break; + } + } + } + } + //qDebug() << pins.size() << buses.size(); +} + + +void BlockView::zoom(double factor) { + scale(factor, factor); +} + + +void BlockView::zoomReset() { + cur_scl = qSqrt(transform().determinant()); + zoom(1. / cur_scl); +} + + +void BlockView::copyToClipboard() { + QList bll = selectedBlocks(); + QList del = selectedDecors(); + //qDebug() << "copy" << bll.size() << del.size(); + if (bll.isEmpty() && del.isEmpty()) return; + QList bul = internalBuses(bll); + QByteArray ba; + QDataStream s(&ba, QIODevice::ReadWrite); + s << uint(0x89abcdef) << bll << bul << del; + QMimeData * mime = new QMimeData(); + mime->setData(_BlockView_Mime_, ba); + QApplication::clipboard()->setMimeData(mime); +} + + +void BlockView::pasteFromClipboard() { + const QMimeData * mime = QApplication::clipboard()->mimeData(); + if (!mime) return; + if (!mime->hasFormat(_BlockView_Mime_)) return; + QByteArray ba = mime->data(_BlockView_Mime_); + //qDebug() << "paste" << ba.size(); + if (ba.isEmpty()) return; + QList bll; + QList bul; + QList del, gl; + uint hdr = 0; + QDataStream s(ba); + s >> hdr; + if (hdr != 0x89abcdef) return; + s >> bll >> bul >> del; + int all = bll.size() + bul.size() + del.size(); + if (all == 0) return; + QRectF br; + foreach (BlockItem * b, bll) { + br |= b->boundingRect().translated(b->pos()); + gl << b; + } + foreach (BlockBusItem * b, bul) + gl << b; + foreach (QGraphicsItem * b, del) + br |= b->boundingRect().translated(b->pos()); + gl << del; + QPointF copy_dp; + if (underMouse()) copy_dp = mapToScene(mapFromGlobal(QCursor::pos())); + else copy_dp = mapToScene(rect().center()); + copy_dp -= br.center(); + copy_dp = quantize(copy_dp, grid_step); + ae_enabled = false; + if (!bll.isEmpty()) copyBlocks(bll, copy_dp); + if (!bul.isEmpty()) copyBuses(bul, copy_dp); + foreach (QGraphicsItem * i, del) + i->setPos(i->pos() + copy_dp); + addItems(del); + ae_enabled = true; + emitActionEvent(BlockItemBase::Paste, gl); +} + + +void BlockView::selectNone() { + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + i->setSelected(false); +} + + +void BlockView::selectAll() { + QList gi = scene_->items(); + foreach (QGraphicsItem * i, gi) + if (i->flags().testFlag(QGraphicsItem::ItemIsSelectable)) + i->setSelected(true); +} + + +void BlockView::removeSelected() { + QList gi = scene_->selectedItems(), ai; + blockSignals(true); + QList sbuses = buses(), dbuses, wbuses = wrongConnectedBuses(); + //foreach (BlockBusItem * i, wbuses) + // sbuses.removeOne(i); + foreach (BlockBusItem * i, sbuses) + if (i->connectedBlocks().isEmpty()) + dbuses << i; + foreach (QGraphicsItem * i, gi) { + if (i->data(1006) == "item") + ai << qgraphicsitem_cast(i); + if ((i->data(1006) == "item") || (i->data(1005) == "connection") || (i->data(1009) == "decor")) { + scene_->sendEvent(i, new QGraphicsSceneEvent(QEvent::Close)); + delete i; + } + } + reconnectAll(); + foreach (BlockBusItem * i, sbuses) + if (i->connectedBlocks().isEmpty()) + if (!dbuses.contains(i)) + delete i; + + blockSignals(false); + foreach (QGraphicsItem * i, ai) + emit blockRemoved((BlockItem*)i); + emitActionEvent(BlockItemBase::BlockRemove, ai); +} + + +void BlockView::removeAll() { + QList gi = scene_->items(), ai; + blockSignals(true); + foreach (QGraphicsItem * i, gi) { + if (i->data(1006) == "item") + ai << qgraphicsitem_cast(i); + if ((i->data(1006) == "item") || (i->data(1005) == "connection") || (i->data(1009) == "decor")) { + if ((i != &sel_rect) && (i != &tmp_bus) && (i->parentItem() == 0) && !(i->data(1008).toBool())) { + //qDebug() << "delete" << i->data(1004); + scene_->sendEvent(i, new QGraphicsSceneEvent(QEvent::Close)); + delete i; + } + } + } + blockSignals(false); + foreach (QGraphicsItem * i, ai) + emit blockRemoved((BlockItem*)i); +} diff --git a/qad/blockview/blockview.h b/qad/blockview/blockview.h new file mode 100644 index 0000000..db0078a --- /dev/null +++ b/qad/blockview/blockview.h @@ -0,0 +1,200 @@ +#ifndef BLOCKVIEW_H +#define BLOCKVIEW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "blockviewwavetrace.h" +#include "blockbusitem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class BlockView: public QGraphicsView +{ + Q_OBJECT + Q_ENUMS(SelectionMode) + + Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) + Q_PROPERTY(bool snapToGrid READ isSnapToGrid WRITE setSnapToGrid) + Q_PROPERTY(QPen gridPen READ gridPen WRITE setGridPen) + Q_PROPERTY(double gridStep READ gridStep WRITE setGridStep) + Q_PROPERTY(double gridPointsWidth READ gridPointsWidth WRITE setGridPointsWidth) + Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(bool postMoveConnect READ isPostMoveConnectEnabled WRITE setPostMoveConnectEnabled) + Q_PROPERTY(bool connectByMouse READ isConnectByMouseEnabled WRITE setConnectByMouseEnabled) + Q_PROPERTY(bool navigationEnabled READ isNavigationEnabled WRITE setNavigationEnabled) + Q_PROPERTY(bool traceConsiderBuses READ isTraceConsiderBuses WRITE setTraceConsiderBuses) + Q_PROPERTY(bool pinMulticonnect READ isPinMulticonnectEnabled WRITE setPinMulticonnectEnabled) + Q_PROPERTY(bool miniMap READ isMiniMapEnabled WRITE setMiniMapEnabled) + + Q_PROPERTY(double _thumb READ _thumb WRITE _setThumb DESIGNABLE false SCRIPTABLE false) + +public: + BlockView(QWidget * parent = 0); + BlockView(QGraphicsScene * scene, QWidget * parent = 0); + ~BlockView(); + + enum SelectionMode { + NoSelection, + SingleSelection, + MultiSelection + }; + + QPen gridPen() const {return grid_pen;} + bool isGridVisible() const {return grid_visible;} + bool isSnapToGrid() const {return grid_snap;} + bool isPostMoveConnectEnabled() const {return pm_connect;} + bool isNavigationEnabled() const {return navigation;} + bool isConnectByMouseEnabled() const {return m_connect;} + bool isTraceConsiderBuses() const {return m_trace_with_buses;} + bool isPinMulticonnectEnabled() const {return m_pin_mc;} + bool isMiniMapEnabled() const {return minimap;} + double gridStep() const {return grid_step;} + double gridPointsWidth() const {return grid_points;} + SelectionMode selectionMode() const {return smode;} + void setSelectionMode(SelectionMode mode) {smode = mode;} + + void addItems(QList items) {foreach (QGraphicsItem * i, items) addItem(i);} + QList buses() const; + QList wrongConnectedBuses() const; + QList blocks() const; + QList decors() const; + BlockBusItem * connectionBus(BlockItem * b0, BlockItem * b1) const; + QList connectionBuses(BlockItem * b0, BlockItem * b1) const; + bool connectPins(BlockItemPin * p0, BlockItemPin * p1); + +protected: + void _init(); + void _updateBack(); + bool eventFilter(QObject * o, QEvent * e); + void stopTimer(int & tid); + void restartTimer(int & tid, int msecs); + void timerEvent(QTimerEvent * e); + void wheelEvent(QWheelEvent * event); + void mousePressEvent(QMouseEvent * event); + void mouseMoveEvent(QMouseEvent * event); + void keyPressEvent(QKeyEvent * event); + void resizeEvent(QResizeEvent * event); + void scrollContentsBy(int dx, int dy); + void drawBackground(QPainter * painter, const QRectF & rect); + void drawThumb(); + void drawSceneThumb(); + void thumbHide(); + void thumbShow(); + void restoreSelState(); + void saveSelState(); + void saveBusesState(); + void restoreBusesState(); + void applySelRect(QGraphicsSceneMouseEvent * me); + void applyGridStep(); + void trace(QPointF scene_pos_from, QPointF scene_pos_to, BlockBusItem * bus); + void clearBusStates(); + void matchBus(); + bool connectTmpToBus(BlockBusItem* bus); + void markPins(int bus_type); + void unmarkPins(bool to_normal = false); + void hoverAcceptedPin(BlockItemPin * pin); + void unhoverPins(); + void simplifyBuses(); + void moveBuses(const QList & items, QPointF dp); + QList internalBuses(const QList & items); + QList selectedBlocks() const; + QList selectedDecors() const; + double _thumb() const {return _talpha;} + void scrollFromThumb(); + void deleteCopyTemp(); + void emitActionEvent(BlockItemBase::Action action, QList items); + + virtual void loadBus(BlockBusItem * bus) {} + virtual void copyBlocks(QList items, QPointF offset) {} + virtual void copyBuses(QList items, QPointF offset) {} + virtual void newBusStarted(int bus_type) {} + + QGraphicsScene * scene_; + QGraphicsRectItem sel_rect; + QGraphicsItem * mm_ci; + QList sel_items; + QList copy_items; + QList copy_buses; + BlockBusItem tmp_bus, * match_bus, * bus_from; + BlockItemPin * hpin; + BlockViewWavetrace wavetrace; + QPoint press_point, screen_point, thumb_press; + QPointF scene_point, trace_from, last_trace_from, trace_to, copy_dp; + QRect thumb_sr, thumb_vr; + QSizeF thumb_size; + QPen grid_pen; + SelectionMode smode; + QImage im_scene; + QWidget widget_thumb; + Qt::KeyboardModifiers mm_mods; + QPropertyAnimation thumb_anim; + int timer_thumb, thumb_hide_delay; + bool mm_drag, new_bus, new_branch, moved, mm_cancel, iconnect, mm_copy, mm_thumb, ae_enabled; + bool grid_visible, grid_snap, pm_connect, navigation, m_connect, m_trace_with_buses, m_pin_mc, minimap; + double grid_step, grid_points, cur_scl, _talpha, thumb_scl; + +protected slots: + void getPinMC(bool * v) {if (v) *v = m_pin_mc;} + void adjustThumb(); + void newBranch(BlockBusItem * item); + void newBranchTrace(BlockBusItem * item, QPointF to); + void newBranchAccept(BlockBusItem * item); + void newBranchCancel(); + void removedBus(QObject * o); + void removedBlock(QObject * o); + void removeJunk(); + void sceneSelectionChanged(); + void _setThumb(double v); + +public slots: + void setGridPen(const QPen & pen) {grid_pen = pen; _updateBack();} + void setGridVisible(bool yes) {grid_visible = yes; _updateBack();} + void setSnapToGrid(bool yes) {grid_snap = yes;} + void setGridStep(double step) {grid_step = step; applyGridStep(); _updateBack();} + void setGridPointsWidth(double width_) {grid_points = width_; _updateBack();} + void setPostMoveConnectEnabled(bool on) {pm_connect = on;} + void setNavigationEnabled(bool on) {navigation = on;} + void setConnectByMouseEnabled(bool on) {m_connect = on;} + void setTraceConsiderBuses(bool on) {m_trace_with_buses = on;} + void setPinMulticonnectEnabled(bool on) {m_pin_mc = on;} + void setMiniMapEnabled(bool on) {minimap = on;} + + void zoom(double factor); + void zoomIn() {zoom(1.2);} + void zoomOut() {zoom(1. / 1.2);} + void zoomReset(); + + void copyToClipboard(); + void pasteFromClipboard(); + + void reconnectAll(); + void selectNone(); + void selectAll(); + void removeSelected(); + void removeAll(); + void clearSelection(); + void addItem(QGraphicsItem * item); + +signals: + void blockDoubleClicked(BlockItem * ); + void busDoubleClicked(BlockBusItem * ); + void actionEvent(BlockItemBase::Action action, QList items); + void blockRemoved(BlockItem * item); + void connectionsChanged(); + void copyEnabledChanged(bool); + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // BLOCKVIEW_H diff --git a/qad/blockview/blockviewwavetrace.cpp b/qad/blockview/blockviewwavetrace.cpp new file mode 100644 index 0000000..c070555 --- /dev/null +++ b/qad/blockview/blockviewwavetrace.cpp @@ -0,0 +1,197 @@ +#include "blockviewwavetrace.h" +#include + + +BlockViewWavetrace::BlockViewWavetrace(int width, int height) { + max_steps = 512; + resize(width, height); + setPreferredDirection(BlockViewWavetrace::Horizontal); +} + + +void BlockViewWavetrace::resize(int width, int height) { + wid = width; + hei = height; + if (field.size() != wid) + field.resize(wid); + for (int i = 0; i < wid; ++i) { + if (field[i].size() != hei) { + field[i].resize(hei); + field[i].fill(-1); + } + } +} + + +void BlockViewWavetrace::fill(short val) { + QTime tm; tm.restart(); + for (int i = 0; i < wid; ++i) { + if (i == 0) + field[i].fill(val); + else + memcpy(field[i].data(), field[0].constData(), hei * sizeof(field[0][0])); + } +} + + +void BlockViewWavetrace::fill(const QRect & rect, short val) { + for (int i = rect.left(); i <= rect.right(); ++i) + for (int j = rect.top(); j <= rect.bottom(); ++j) + field[i][j] = val; +} + + +bool BlockViewWavetrace::trace(const QPoint & start, const QPoint & finish) { + st = start; + fn = finish; + //qDebug() << "trace" << start << finish; + //return true; + int cx, cy; + short cl = 0, empty = (short)BlockViewWavetrace::Empty; + QRect frect(0, 0, wid - 1, hei - 1); + QVector cpnts, npnts; + fill(st, cl); + cpnts.push_back(st); + if (field[fn.x()][fn.y()] == (short)BlockViewWavetrace::Blocked) + return false; + while (cpnts.size() > 0) { + npnts.clear(); + cl++; + if (cl >= max_steps) return false; + for (int i = 0; i < cpnts.size(); ++i) { + if (cpnts[i] == fn) { + return true; + } + cx = cpnts[i].x() - 1; + cy = cpnts[i].y(); + if (frect.contains(cx, cy)) { + if (field[cx][cy] == empty) { + npnts.push_back(QPoint(cx, cy)); + fill(cx, cy, cl); + } + } + cx = cpnts[i].x() + 1; + if (frect.contains(cx, cy)) { + if (field[cx][cy] == empty) { + npnts.push_back(QPoint(cx, cy)); + fill(cx, cy, cl); + } + } + cx = cpnts[i].x(); + cy = cpnts[i].y() - 1; + if (frect.contains(cx, cy)) { + if (field[cx][cy] == empty) { + npnts.push_back(QPoint(cx, cy)); + fill(cx, cy, cl); + } + } + cy = cpnts[i].y() + 1; + if (frect.contains(cx, cy)) { + if (field[cx][cy] == empty) { + npnts.push_back(QPoint(cx, cy)); + fill(cx, cy, cl); + } + } + } + cpnts = npnts; + //qDebug() << cl << ": " << cpnts.size(); + } + return false; +} + + +void BlockViewWavetrace::gatherPath() { + path_.clear(); + path_.push_back(fn); + int cx, cy; + int pa = -1, ca = -1; + bool first = true; + short cl = field[fn.x()][fn.y()]; + QRect frect(0, 0, wid, hei); + QPoint cpnt = fn; + //cout << "start from " << cl << endl; + while (cl > 0) { + cl--; + pa = ca; + int dir = 0; + cx = cpnt.x() + dps[dir].x(); + cy = cpnt.y() + dps[dir].y(); + dir++; + if (frect.contains(cx, cy)) { + if (field[cx][cy] == cl) { + ca = QLineF(QPointF(cx, cy), cpnt).angle(); + if (ca != pa && !first) + path_.push_front(cpnt); + cpnt = QPoint(cx, cy); + first = false; + continue; + } + } + cx = cpnt.x() + dps[dir].x(); + cy = cpnt.y() + dps[dir].y(); + dir++; + if (frect.contains(cx, cy)) { + if (field[cx][cy] == cl) { + ca = QLineF(QPointF(cx, cy), cpnt).angle(); + if (ca != pa && !first) + path_.push_front(cpnt); + cpnt = QPoint(cx, cy); + first = false; + continue; + } + } + cx = cpnt.x() + dps[dir].x(); + cy = cpnt.y() + dps[dir].y(); + dir++; + if (frect.contains(cx, cy)) { + if (field[cx][cy] == cl) { + ca = QLineF(QPointF(cx, cy), cpnt).angle(); + if (ca != pa && !first) + path_.push_front(cpnt); + cpnt = QPoint(cx, cy); + first = false; + continue; + } + } + cx = cpnt.x() + dps[dir].x(); + cy = cpnt.y() + dps[dir].y(); + if (frect.contains(cx, cy)) { + if (field[cx][cy] == cl) { + ca = QLineF(QPointF(cx, cy), cpnt).angle(); + if (ca != pa && !first) + path_.push_front(cpnt); + cpnt = QPoint(cx, cy); + first = false; + continue; + } + } + } + path_.push_front(st); + //cout << path_.size() << endl; +} + + +void BlockViewWavetrace::setPreferredDirection(BlockViewWavetrace::Direction dir) { + dir_ = dir; + if (dir == BlockViewWavetrace::Horizontal) { + dps[0] = QPoint(0, -1); + dps[1] = QPoint(0, 1); + dps[2] = QPoint(-1, 0); + dps[3] = QPoint(1, 0); + } + if (dir == BlockViewWavetrace::Vertical) { + dps[2] = QPoint(0, -1); + dps[3] = QPoint(0, 1); + dps[0] = QPoint(-1, 0); + dps[1] = QPoint(1, 0); + } +} + + +const QVector & BlockViewWavetrace::path() const { + /*path_.resize(3); + path_[0] = st; + path_[1] = (st + fn) / 2; + path_[2] = fn;*/ + return path_; +} diff --git a/qad/blockview/blockviewwavetrace.h b/qad/blockview/blockviewwavetrace.h new file mode 100644 index 0000000..41f453e --- /dev/null +++ b/qad/blockview/blockviewwavetrace.h @@ -0,0 +1,43 @@ +#ifndef BLOCKVIEWWAVETRACE_H +#define BLOCKVIEWWAVETRACE_H + +#include "blockitem.h" + +class BlockViewWavetrace { +public: + BlockViewWavetrace(int width = 1, int height = 1); + + enum CellState {Empty = -1, Blocked = -2}; + enum Direction {Horizontal = 0, Vertical = 1}; + + int width() const {return wid;} + int height() const {return hei;} + void resize(int width, int height); + void resize(const QSize & sz) {resize(sz.width(), sz.height());} + void fill(short val = -1); + void fill(const QRect & rect, short val = -1); + void fill(const QPoint & point, short val = -1) {field[point.x()][point.y()] = val;} + void fill(int px, int py, short val = -1) {field[px][py] = val;} + void fill(BlockViewWavetrace::CellState val = Empty) {fill((short)val);} + void fill(const QRect & rect, BlockViewWavetrace::CellState val = Empty) {fill(rect, (short)val);} + void fill(const QPoint & point, BlockViewWavetrace::CellState val = Empty) {fill(point, (short)val);} + void fill(int px, int py, BlockViewWavetrace::CellState val = Empty) {fill(px, py, (short)val);} + void clear() {fill(-1);} + bool trace(const QPoint & start, const QPoint & finish); + Direction preferredDirection() const {return dir_;} + void setPreferredDirection(Direction dir); + void setMaximumSteps(int steps) {max_steps = steps;} + int maximumSteps() const {return max_steps;} + void gatherPath(); + const QVector & path() const; + +private: + int wid, hei, max_steps; + Direction dir_; + QVector > field; + QVector path_; + QPoint dps[4], st, fn; + +}; + +#endif // BLOCKVIEWWAVETRACE_H diff --git a/qad/blockview/drawtools.cpp b/qad/blockview/drawtools.cpp new file mode 100644 index 0000000..2e01120 --- /dev/null +++ b/qad/blockview/drawtools.cpp @@ -0,0 +1,791 @@ +#include "drawtools.h" +#include "ui_drawtools.h" +#include "alignedtextitem.h" +#include +#include +#include +#include +#include +#include +#include + + +_DTSizeItem::_DTSizeItem(): QGraphicsObject() { + cur_item = 0; + grid = 10.; + in_process = can_drag = false; + setData(1008, true); + for (int i = 0; i < 8; ++i) { + //qDebug() << &(rects[i]); + rects[i].setData(1008, true); + rects[i].setFlag(QGraphicsItem::ItemIgnoresTransformations); + rects[i].setZValue(10.); + rects[i].setAcceptHoverEvents(true); + rects[i].setRect(-5, -5, 10, 10); + rects[i].setPen(QPen(Qt::darkBlue)); + rects[i].setBrush(QBrush(QColor(64, 64, 255, 128))); + //rects[i].setData(1100, true); + } +} + + +_DTSizeItem::~_DTSizeItem() { + assignObject(0); + //qDebug() << "!!!"; +} + + +void _DTSizeItem::assignObject(QGraphicsItem * item) { + if (cur_item) + if (qgraphicsitem_cast(cur_item)) + cur_item->removeSceneEventFilter(this); + cur_item = item; + if (!cur_item) { + for (int i = 0; i < 8; ++i) { + rects[i].hide(); + rects[i].setParentItem(0); + rects[i].removeSceneEventFilter(this); + } + return; + } + if (item) + if (item->scene()) + if (!item->scene()->views().isEmpty()) + grid = ((BlockView*)(item->scene()->views()[0]))->gridStep(); + QGraphicsRectItem * irect = qgraphicsitem_cast(cur_item); + QGraphicsEllipseItem * iell = qgraphicsitem_cast(cur_item); + QGraphicsLineItem * iline = qgraphicsitem_cast(cur_item); + if (irect || iell || iline) { + is_line = qgraphicsitem_cast(item); + for (int i = 0; i < (is_line ? 2 : 8); ++i) { + rects[i].setParentItem(item); + rects[i].installSceneEventFilter(this); + rects[i].show(); + } + } + item->installSceneEventFilter(this); + moveRects(); +} + + +void _DTSizeItem::moveRects() { + if (!cur_item) return; + QRectF rect = itemRect(cur_item); + QPointF tl = rect.topLeft(), tr = rect.topRight(), bl = rect.bottomLeft(), br = rect.bottomRight(); + if (is_line) { + rects[0].setPos(tl); rects[0].setData(2001, int(Qt::SizeAllCursor)); + rects[1].setPos(br); rects[1].setData(2001, int(Qt::SizeAllCursor)); + } else { + rects[0].setPos(tl); rects[0].setData(2001, int(Qt::SizeFDiagCursor)); + rects[1].setPos((tl + tr) / 2.); rects[1].setData(2001, int(Qt::SizeVerCursor)); + rects[2].setPos(tr); rects[2].setData(2001, int(Qt::SizeBDiagCursor)); + rects[3].setPos((tr + br) / 2.); rects[3].setData(2001, int(Qt::SizeHorCursor)); + rects[4].setPos(br); rects[4].setData(2001, int(Qt::SizeFDiagCursor)); + rects[5].setPos((br + bl) / 2.); rects[5].setData(2001, int(Qt::SizeVerCursor)); + rects[6].setPos(bl); rects[6].setData(2001, int(Qt::SizeBDiagCursor)); + rects[7].setPos((bl + tl) / 2.); rects[7].setData(2001, int(Qt::SizeHorCursor)); + } +} + + +void _DTSizeItem::applyRect() { + if (!cur_item) return; + QGraphicsRectItem * irect = qgraphicsitem_cast(cur_item); + QGraphicsEllipseItem * iell = qgraphicsitem_cast(cur_item); + QGraphicsLineItem * iline = qgraphicsitem_cast(cur_item); + if (irect) + irect->setRect(nrect); + if (iell) + iell->setRect(nrect); + if (iline) + iline->setLine(QLineF(nrect.topLeft(), nrect.bottomRight())); +} + + +void _DTSizeItem::doubleClick() { + QGraphicsSimpleTextItem * itext = qgraphicsitem_cast(cur_item); + AlignedTextItem * iatext = qgraphicsitem_cast(cur_item); + QGraphicsPixmapItem * ipixmap = qgraphicsitem_cast(cur_item); + if (itext || iatext) { + emit textEditRequest(); + } + if (ipixmap) { + emit pixmapEditRequest(); + } +} + + +QRectF _DTSizeItem::itemRect(const QGraphicsItem * item) const { + if (!cur_item) return QRectF(); + QGraphicsRectItem * irect = qgraphicsitem_cast(cur_item); + QGraphicsEllipseItem * iell = qgraphicsitem_cast(cur_item); + QGraphicsLineItem * iline = qgraphicsitem_cast(cur_item); + if (irect) + return irect->rect(); + if (iell) + return iell->rect(); + if (iline) + return QRectF(iline->line().p1(), iline->line().p2()); + return QRectF(); +} + + +QRectF _DTSizeItem::boundingRect() const { + QRectF ret = rects[0].boundingRect().translated(rects[0].pos()); + for (int i = 1; i < 8; ++i) + ret |= rects[i].boundingRect().translated(rects[i].pos()); + return ret; +} + + +bool _DTSizeItem::sceneEventFilter(QGraphicsItem * watched, QEvent * event) { + QGraphicsSceneMouseEvent * me = (QGraphicsSceneMouseEvent * )event; + if (watched == cur_item) { + if (event->type() == QEvent::Close) + assignObject(0); + if (event->type() == QEvent::GraphicsSceneMouseDoubleClick) { + doubleClick(); + return true; + } + return QGraphicsItem::sceneEventFilter(watched, event); + } + if (!cur_item) + return QGraphicsItem::sceneEventFilter(watched, event); + view_ = 0; + switch (event->type()) { + case QEvent::GraphicsSceneHoverEnter: + if (watched->scene()) if (!watched->scene()->views().isEmpty()) view_ = watched->scene()->views()[0]; + if (view_) view_->setCursor(Qt::CursorShape(watched->data(2001).toInt())); + break; + case QEvent::GraphicsSceneHoverLeave: + if (watched->scene()) if (!watched->scene()->views().isEmpty()) view_ = watched->scene()->views()[0]; + if (view_) view_->unsetCursor(); + break; + case QEvent::GraphicsSceneMousePress: + can_drag = (me->buttons() == Qt::LeftButton); + if (in_process) { + nrect = cur_item->data(2000).toRectF(); + applyRect(); + moveRects(); + } + in_process = false; + pp = quantize(me->scenePos(), grid); + cur_item->setData(2000, itemRect(cur_item)); + return true; + case QEvent::GraphicsSceneMouseMove: + if (me->buttons().testFlag(Qt::LeftButton)) { + sp = quantize(me->scenePos(), grid); + if (pp != sp && can_drag) { + in_process = true; + nrect = itemRect(cur_item); + if (is_line) { + if (watched == &(rects[0])) nrect.setTopLeft(rects[0].pos() + (sp - pp)); + if (watched == &(rects[1])) nrect.setBottomRight(rects[1].pos() + (sp - pp)); + } else { + if (watched == &(rects[0])) nrect.setTopLeft(rects[0].pos() + (sp - pp)); + if (watched == &(rects[1])) nrect.setTop(rects[1].pos().y() + (sp - pp).y()); + if (watched == &(rects[2])) nrect.setTopRight(rects[2].pos() + (sp - pp)); + if (watched == &(rects[3])) nrect.setRight(rects[3].pos().x() + (sp - pp).x()); + if (watched == &(rects[4])) nrect.setBottomRight(rects[4].pos() + (sp - pp)); + if (watched == &(rects[5])) nrect.setBottom(rects[5].pos().y() + (sp - pp).y()); + if (watched == &(rects[6])) nrect.setBottomLeft(rects[6].pos() + (sp - pp)); + if (watched == &(rects[7])) nrect.setLeft(rects[7].pos().x() + (sp - pp).x()); + nrect = nrect.normalized(); + } + pp = sp; + applyRect(); + moveRects(); + } + } + return true; + case QEvent::GraphicsSceneMouseRelease: + if (in_process) + emit sizeChanged(); + in_process = false; + can_drag = false; + return true; + default: break; + } + return QGraphicsItem::sceneEventFilter(watched, event); +} + + + + +DrawTools::DrawTools(BlockView * parent): QObject(parent), +actions_Z_up(this), actions_Z_top(this), actions_Z_down(this), actions_Z_bottom(this) { + widget_props = new QWidget(); + ui = new Ui::DrawTools(); + ui->setupUi(widget_props); + widget_props->setEnabled(false); + setAlignCompact(false); + menu_hor.addActions(QList() << ui->actionLeft << ui->actionHCenter << ui->actionRight); + menu_ver.addActions(QList() << ui->actionTop << ui->actionVCenter << ui->actionBottom); + ui->buttonAlignHor->setMenu(&menu_hor); + ui->buttonAlignVer->setMenu(&menu_ver); + new_type = -1; + new_item = cur_item = 0; + view_ = 0; + resize_enabled = true; + text_dlg.setWindowTitle(trUtf8("Edit text")); + text_dlg.setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); + QDialogButtonBox * bbox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel); + connect(bbox, SIGNAL(accepted()), &text_dlg, SLOT(accept())); + connect(bbox, SIGNAL(rejected()), &text_dlg, SLOT(reject())); + text_dlg.layout()->addWidget(&text_edit); + text_dlg.layout()->addWidget(bbox); + actions_Z_up.setText(trUtf8("Bring\nforward")); actions_Z_up.setIcon(QIcon(":/icons/z-up.png")); actions_Z_up.setEnabled(false); + actions_Z_top.setText(trUtf8("Bring\nto front")); actions_Z_top.setIcon(QIcon(":/icons/z-top.png")); actions_Z_top.setEnabled(false); + actions_Z_down.setText(trUtf8("Send\nbackward")); actions_Z_down.setIcon(QIcon(":/icons/z-down.png")); actions_Z_down.setEnabled(false); + actions_Z_bottom.setText(trUtf8("Send\nto back")); actions_Z_bottom.setIcon(QIcon(":/icons/z-bottom.png")); actions_Z_bottom.setEnabled(false); + actions_add << newAction(trUtf8("Draw\nRectangle"), QIcon(":/icons/draw-rectangle.png"), 1) + << newAction(trUtf8("Draw\nEllipse"), QIcon(":/icons/draw-ellipse.png"), 2) + << newAction(trUtf8("Draw\nLine"), QIcon(":/icons/draw-line.png"), 4) + << newAction(trUtf8("Draw\nText"), QIcon(":/icons/draw-text.png"), 0) + << newAction(trUtf8("Draw\nImage"), QIcon(":/icons/view-preview.png"), 3); + buttons_align << ui->buttonAlignTL << ui->buttonAlignTC << ui->buttonAlignTR + << ui->buttonAlignCL << ui->buttonAlignCC << ui->buttonAlignCR + << ui->buttonAlignBL << ui->buttonAlignBC << ui->buttonAlignBR; + foreach (QAction * a, actions_add) + connect(a, SIGNAL(toggled(bool)), this, SLOT(toggleNewItem(bool))); + foreach (QToolButton * b, buttons_align) + connect(b, SIGNAL(clicked(bool)), this, SLOT(alignClicked())); + connect(ui->buttonImage, SIGNAL(clicked(bool)), this, SLOT(buttonImage_clicked())); + connect(ui->buttonFont, SIGNAL(clicked(bool)), this, SLOT(buttonFont_clicked())); + connect(ui->buttonTextEdit, SIGNAL(clicked(bool)), this, SLOT(buttonTextEdit_clicked())); + connect(ui->spinWidth, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged())); + connect(ui->spinWidth, SIGNAL(editingFinished()), this, SLOT(changeFinished())); + connect(ui->spinHeight, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged())); + connect(ui->spinHeight, SIGNAL(editingFinished()), this, SLOT(changeFinished())); + connect(ui->spinThick, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged())); + connect(ui->spinThick, SIGNAL(editingFinished()), this, SLOT(changeFinished())); + connect(ui->comboText, SIGNAL(editTextChanged(QString)), this, SLOT(propertyChanged())); + connect(ui->comboText->lineEdit(), SIGNAL(editingFinished()), this, SLOT(changeFinished())); + connect(ui->colorButtonPen, SIGNAL(colorChanged(QColor)), this, SLOT(propertyChanged())); + connect(ui->colorButtonPen, SIGNAL(colorChanged(QColor)), this, SLOT(changeFinished())); + connect(ui->colorButtonBrush, SIGNAL(colorChanged(QColor)), this, SLOT(propertyChanged())); + connect(ui->colorButtonBrush, SIGNAL(colorChanged(QColor)), this, SLOT(changeFinished())); + connect(ui->actionTop, SIGNAL(triggered(bool)), this, SLOT(actionTop_triggered(bool))); + connect(ui->actionVCenter, SIGNAL(triggered(bool)), this, SLOT(actionVCenter_triggered(bool))); + connect(ui->actionBottom, SIGNAL(triggered(bool)), this, SLOT(actionBottom_triggered(bool))); + connect(ui->actionLeft, SIGNAL(triggered(bool)), this, SLOT(actionLeft_triggered(bool))); + connect(ui->actionHCenter, SIGNAL(triggered(bool)), this, SLOT(actionHCenter_triggered(bool))); + connect(ui->actionRight, SIGNAL(triggered(bool)), this, SLOT(actionRight_triggered(bool))); + connect(&font_dlg, SIGNAL(currentFontChanged(QFont)), this, SLOT(propertyChanged())); + connect(&size_item, SIGNAL(sizeChanged()), this, SLOT(sizeChanged())); + connect(&size_item, SIGNAL(textEditRequest()), this, SLOT(buttonTextEdit_clicked())); + connect(&size_item, SIGNAL(pixmapEditRequest()), this, SLOT(buttonImage_clicked())); + connect(&actions_Z_up, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered())); + connect(&actions_Z_top, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered())); + connect(&actions_Z_down, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered())); + connect(&actions_Z_bottom, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered())); + setBlockView(parent); +} + + +DrawTools::~DrawTools() { + size_item.assignObject(0); + //delete ui; + //delete widget_props; +} + + +void DrawTools::setBlockView(BlockView * v) { + if (view_) view_->viewport()->removeEventFilter(this); + disconnect(this, SLOT(selectionChanged())); + view_ = v; + if (!view_) return; + view_->addItem(&size_item); + view_->viewport()->installEventFilter(this); + connect(view_->scene(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); +} + + +void DrawTools::setAlignCompact(bool yes) { + ui->widgetAlign2->setVisible(yes); + ui->widgetAlign9->setVisible(!yes); +} + + +bool DrawTools::eventFilter(QObject * o, QEvent * e) { + QMouseEvent * me = (QMouseEvent*)e; + QPointF sp; + if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseMove) + sp = quantize(view_->mapToScene(me->pos()), view_->gridStep()); + QRectF mr; + switch (e->type()) { + case QEvent::MouseButtonPress: + if (new_type < 0) break; + if (new_item) { + delete new_item; + new_item = 0; + if (!me->modifiers().testFlag(Qt::ControlModifier)) { + foreach (QAction * a, actions_add) + a->setChecked(false); + new_type = -1; + //view_->setCursor(Qt::ArrowCursor); + return true; + } + } + new_item = 0; + pp = sp; + switch (new_type) { + case 0: + new_item = new AlignedTextItem(); + ((AlignedTextItem*)new_item)->setText("Text"); + ((AlignedTextItem*)new_item)->setPos(sp); + break; + case 1: + new_item = new QGraphicsRectItem(); + break; + case 2: + new_item = new QGraphicsEllipseItem(); + break; + case 3: + new_item = new QGraphicsPixmapItem(QPixmap(":/icons/view-preview.png")); + ((QGraphicsPixmapItem*)new_item)->setPos(sp - QPointF(new_item->boundingRect().width() / 2, new_item->boundingRect().height() / 2)); + break; + case 4: + new_item = new QGraphicsLineItem(QLineF(sp, sp)); + break; + }; + if (new_item) { + if (new_type == 1 || new_type == 2) + ((QAbstractGraphicsShapeItem*)new_item)->setBrush(Qt::white); + new_item->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); + new_item->setData(1100, true); + emit itemCreated(new_item); + return true; + } + break; + case QEvent::MouseMove: + if (me->buttons().testFlag(Qt::LeftButton)) { + if (new_item) { + mr = new_item->mapRectFromScene(QRectF(pp, sp).normalized()); + //mr = QRectF(pp, sp).normalized(); + switch (new_type) { + case 0: + ((AlignedTextItem*)new_item)->setPos(sp); + break; + case 1: + ((QGraphicsRectItem*)new_item)->setRect(mr); + break; + case 2: + ((QGraphicsEllipseItem*)new_item)->setRect(mr); + break; + case 3: + ((QGraphicsPixmapItem*)new_item)->setPos(sp - QPointF(new_item->boundingRect().width() / 2, new_item->boundingRect().height() / 2)); + break; + case 4: + ((QGraphicsLineItem*)new_item)->setLine(QLineF(pp, sp)); + break; + }; + return true; + } + } + break; + case QEvent::MouseButtonRelease: + if (new_item) { + if (new_item->boundingRect().isEmpty()) + delete new_item; + else + emit itemAddConfirm(new_item); + new_item = 0; + if (!me->modifiers().testFlag(Qt::ControlModifier)) { + foreach (QAction * a, actions_add) + a->setChecked(false); + new_type = -1; + //view_->setCursor(Qt::ArrowCursor); + } + return true; + } + break; + default: break; + } + return QObject::eventFilter(o, e); +} + + +QComboBox * DrawTools::textEditCombo() const { + return ui->comboText; +} + + +QAction * DrawTools::newAction(const QString & text, const QIcon & icon, int type) { + QAction * ret = new QAction(icon, text, this); + ret->setCheckable(true); + ret->setData(type); + return ret; +} + + +void DrawTools::toggleNewItem(bool on) { + QAction * sa = (QAction * )sender(); + foreach (QAction * a, actions_add) + if (a != sa) + a->setChecked(false); + if (!on) { + new_type = -1; + view_->unsetCursor(); + return; + } + new_type = sa->data().toInt(); + view_->setCursor(Qt::CrossCursor); +} + + +void DrawTools::alignClicked() { + QToolButton * sb = (QToolButton * )sender(); + foreach (QToolButton * b, buttons_align) + if (b != sb) + b->setChecked(false); + sb->setChecked(true); + align = 0; + QString als = sb->objectName().right(2).toLower(); + if (als[0] == 't') align |= Qt::AlignTop; + if (als[0] == 'c') align |= Qt::AlignVCenter; + if (als[0] == 'b') align |= Qt::AlignBottom; + if (als[1] == 'l') align |= Qt::AlignLeft; + if (als[1] == 'c') align |= Qt::AlignHCenter; + if (als[1] == 'r') align |= Qt::AlignRight; + propertyChanged(); +} + + +void DrawTools::setPenBrushEnabled(bool pen, bool brush) { + ui->labelPen->setEnabled(pen); + ui->colorButtonPen->setEnabled(pen); + ui->labelBrush->setEnabled(brush); + ui->colorButtonBrush->setEnabled(brush); +} + + +void DrawTools::blockPropSignals(bool block_) { + ui->spinWidth->blockSignals(block_); + ui->spinHeight->blockSignals(block_); + ui->spinThick->blockSignals(block_); + ui->comboText->blockSignals(block_); + ui->colorButtonPen->blockSignals(block_); + ui->colorButtonBrush->blockSignals(block_); + ui->actionTop->blockSignals(block_); + ui->actionVCenter->blockSignals(block_); + ui->actionBottom->blockSignals(block_); + ui->actionHCenter->blockSignals(block_); + ui->actionLeft->blockSignals(block_); + ui->actionRight->blockSignals(block_); + foreach (QToolButton * b, buttons_align) + b->blockSignals(block_); +} + + +void DrawTools::actionAlignTrigger(bool vert, Qt::AlignmentFlag value) { + blockPropSignals(true); + if (vert) foreach (QAction * a, menu_ver.actions()) a->setChecked(false); + else foreach (QAction * a, menu_hor.actions()) a->setChecked(false); + align = align & (vert ? Qt::AlignHorizontal_Mask : Qt::AlignVertical_Mask); + align |= value; + ((QAction*)sender())->setChecked(true); + blockPropSignals(false); + propertyChanged(); +} + + +void DrawTools::emitZAvailabe(QGraphicsItem * item) { + BlockView * view = 0; + if (item) if (item->scene()) if (!item->scene()->views().isEmpty()) view = qobject_cast(item->scene()->views()[0]); + if (view == 0) { + moveZUpAvailable(false); + moveZDownAvailable(false); + return; + } + QList dl; + if (item->parentItem() == 0) dl = view->decors(); + else if (item->parentItem()->data(1006) == "item") dl = ((BlockItem*)(item->parentItem()))->decors_; + if (dl.size() <= 1) { + moveZUpAvailable(false); + moveZDownAvailable(false); + return; + } + int ind = dl.indexOf(item); + if (ind < 0) { + moveZUpAvailable(false); + moveZDownAvailable(false); + } else { + moveZUpAvailable(ind < dl.size() - 1); + moveZDownAvailable(ind > 0); + } +} + + +void DrawTools::selectionChanged() { + cur_item = 0; + size_item.assignObject(0); + if (!view_) { + emitZAvailabe(); + return; + } + QList sil = view_->scene()->selectedItems(); + if (sil.size() != 1) { + emitZAvailabe(); + widget_props->setEnabled(false); + return; + } + widget_props->setEnabled(true); + cur_item = sil[0]; + if (!cur_item) { + emitZAvailabe(); + return; + } + QGraphicsSimpleTextItem * itext = qgraphicsitem_cast(cur_item); + AlignedTextItem * iatext = qgraphicsitem_cast(cur_item); + QGraphicsPixmapItem * ipixmap = qgraphicsitem_cast(cur_item); + QGraphicsRectItem * irect = qgraphicsitem_cast(cur_item); + QGraphicsEllipseItem * iell = qgraphicsitem_cast(cur_item); + QGraphicsLineItem * iline = qgraphicsitem_cast(cur_item); + blockPropSignals(true); + if (itext) { + ui->stackedProperties->setCurrentIndex(0); + ui->comboText->setEditText(itext->text()); + ui->colorButtonPen->setColor(itext->brush().color()); + font_dlg.blockSignals(true); + font_dlg.setCurrentFont(itext->font()); + font_dlg.blockSignals(false); + setPenBrushEnabled(true, false); + ui->widgetAlign2->setEnabled(false); + ui->widgetAlign9->setEnabled(false); + size_item.assignObject(itext); + } else if (iatext) { + ui->stackedProperties->setCurrentIndex(0); + ui->comboText->setEditText(iatext->text()); + ui->colorButtonPen->setColor(iatext->brush().color()); + font_dlg.blockSignals(true); + font_dlg.setCurrentFont(iatext->font()); + font_dlg.blockSignals(false); + setPenBrushEnabled(true, false); + foreach (QAction * a, menu_hor.actions()) a->setChecked(false); + foreach (QAction * a, menu_ver.actions()) a->setChecked(false); + align = iatext->alignment(); + QString als; + if (align.testFlag(Qt::AlignTop)) {als += "T"; ui->actionTop->setChecked(true);} + if (align.testFlag(Qt::AlignVCenter)) {als += "C"; ui->actionVCenter->setChecked(true);} + if (align.testFlag(Qt::AlignBottom)) {als += "B"; ui->actionBottom->setChecked(true);} + if (align.testFlag(Qt::AlignLeft)) {als += "L"; ui->actionLeft->setChecked(true);} + if (align.testFlag(Qt::AlignHCenter)) {als += "C"; ui->actionHCenter->setChecked(true);} + if (align.testFlag(Qt::AlignRight)) {als += "R"; ui->actionRight->setChecked(true);} + foreach (QToolButton * b, buttons_align) + b->setChecked(false); + foreach (QToolButton * b, buttons_align) + if (b->objectName().endsWith(als)) { + b->setChecked(true); + break; + } + ui->widgetAlign2->setEnabled(true); + ui->widgetAlign9->setEnabled(true); + size_item.assignObject(iatext); + } else if (ipixmap) { + ui->stackedProperties->setCurrentIndex(2); + setPenBrushEnabled(false, false); + size_item.assignObject(ipixmap); + } else if (irect || iell) { + ui->stackedProperties->setCurrentIndex(1); + QAbstractGraphicsShapeItem * ishape(0); + if (irect) { + ishape = irect; + ui->spinWidth->setValue(irect->rect().width()); + ui->spinHeight->setValue(irect->rect().height()); + } + if (iell) { + ishape = iell; + ui->spinWidth->setValue(iell->rect().width()); + ui->spinHeight->setValue(iell->rect().height()); + } + if (ishape) { + ui->colorButtonPen->setColor(ishape->pen().color()); + ui->colorButtonBrush->setColor(ishape->brush().color()); + ui->spinThick->setValue(ishape->pen().widthF()); + setPenBrushEnabled(true, true); + if (resize_enabled) + size_item.assignObject(ishape); + } + } else if (iline) { + ui->stackedProperties->setCurrentIndex(1); + ui->colorButtonPen->setColor(iline->pen().color()); + ui->spinThick->setValue(iline->pen().widthF()); + setPenBrushEnabled(true, false); + if (resize_enabled) + size_item.assignObject(iline); + } else { + ui->stackedProperties->setCurrentIndex(3); + widget_props->setEnabled(false); + } + emitZAvailabe(cur_item); + blockPropSignals(false); +} + + +void DrawTools::sizeChanged() { + blockPropSignals(true); + QGraphicsRectItem * irect = qgraphicsitem_cast(cur_item); + QGraphicsEllipseItem * iell = qgraphicsitem_cast(cur_item); + if (irect || iell) { + if (irect) { + ui->spinWidth->setValue(irect->rect().width()); + ui->spinHeight->setValue(irect->rect().height()); + } + if (iell) { + ui->spinWidth->setValue(iell->rect().width()); + ui->spinHeight->setValue(iell->rect().height()); + } + } + blockPropSignals(false); + changeFinished(); +} + + +void DrawTools::propertyChanged() { + if (!cur_item) return; + QGraphicsSimpleTextItem * itext = qgraphicsitem_cast(cur_item); + AlignedTextItem * iatext = qgraphicsitem_cast(cur_item); + QGraphicsPixmapItem * ipixmap = qgraphicsitem_cast(cur_item); + QGraphicsRectItem * irect = qgraphicsitem_cast(cur_item); + QGraphicsEllipseItem * iell = qgraphicsitem_cast(cur_item); + QGraphicsLineItem * iline = qgraphicsitem_cast(cur_item); + if (itext) { + QRectF obr = itext->boundingRect(); + itext->setFont(font_dlg.currentFont()); + itext->setText(ui->comboText->currentText()); + QRectF nbr = itext->boundingRect(); + QSizeF ds = (obr.size() - nbr.size()) / 2.; + itext->setPos(itext->pos() + QPointF(ds.width(), ds.height())); + itext->setBrush(ui->colorButtonPen->color()); + } else if (iatext) { + iatext->setFont(font_dlg.currentFont()); + iatext->setText(ui->comboText->currentText()); + iatext->setBrush(ui->colorButtonPen->color()); + iatext->setAlignment(align); + } else if (ipixmap) { + } else if (irect || iell) { + QAbstractGraphicsShapeItem * ishape(0); + if (irect) { + ishape = irect; + irect->setRect(QRectF(irect->rect().topLeft(), QSizeF(ui->spinWidth->value(), ui->spinHeight->value()))); + } + if (iell) { + ishape = iell; + iell->setRect(QRectF(iell->rect().topLeft(), QSizeF(ui->spinWidth->value(), ui->spinHeight->value()))); + } + if (ishape) { + ishape->setPen(QPen(ui->colorButtonPen->color(), ui->spinThick->value())); + ishape->setBrush(ui->colorButtonBrush->color()); + if (resize_enabled) + size_item.assignObject(ishape); + } + } else if (iline) { + iline->setPen(QPen(ui->colorButtonPen->color(), ui->spinThick->value())); + if (resize_enabled) + size_item.assignObject(iline); + } +} + + +void DrawTools::buttonImage_clicked() { + QGraphicsPixmapItem * pi = qgraphicsitem_cast(cur_item); + if (!pi) return; + QList sif(QImageReader::supportedImageFormats()); + QString f; + foreach (const QByteArray & i, sif) { + if (!f.isEmpty()) f += " "; + f += "*."; + f += i; + } + QString ret = QFileDialog::getOpenFileName(0, trUtf8("Select image"), pi->data(1101).toString(), QString("Images(%1)").arg(f)); + if (ret.isEmpty()) return; + QImage im(ret); + if (im.isNull()) return; + pi->setData(1101, ret); + QRectF obr = pi->boundingRect(); + pi->setPixmap(QPixmap::fromImage(im)); + QRectF nbr = pi->boundingRect(); + QSizeF ds = (obr.size() - nbr.size()) / 2.; + pi->setPos(pi->pos() + QPointF(ds.width(), ds.height())); + changeFinished(); +} + + +void DrawTools::buttonFont_clicked() { + if (!cur_item) return; + QGraphicsSimpleTextItem * ti = qgraphicsitem_cast(cur_item); + AlignedTextItem * ati = qgraphicsitem_cast(cur_item); + if (!ti && !ati) return; + QFont font_prev; + if (ti) font_prev = ti->font(); + if (ati) font_prev = ati->font(); + font_dlg.blockSignals(true); + font_dlg.setCurrentFont(font_prev); + font_dlg.blockSignals(false); + if (font_dlg.exec() == QDialog::Rejected) + font_dlg.setCurrentFont(font_prev); + else + changeFinished(); +} + + +void DrawTools::buttonTextEdit_clicked() { + text_edit.setPlainText(ui->comboText->lineEdit()->text()); + if (text_dlg.exec() == QDialog::Rejected) + return; + ui->comboText->lineEdit()->setText(text_edit.toPlainText()); + propertyChanged(); + changeFinished(); +} + + +void DrawTools::actionZ_triggered() { + if (!cur_item) return; + if (cur_item->data(1009) == "decor") { + BlockView * view = 0; + if (cur_item) if (cur_item->scene()) if (!cur_item->scene()->views().isEmpty()) + view = qobject_cast(cur_item->scene()->views()[0]); + if (!view) return; + QGraphicsScene * scene = view->scene(); + QList dl = view->decors(); + scene->blockSignals(true); + foreach (QGraphicsItem * d, dl) scene->removeItem(d); + int ind = dl.indexOf(cur_item); + dl.removeAt(ind); + if (sender() == &actions_Z_up) dl.insert(ind + 1, cur_item); + if (sender() == &actions_Z_top) dl.append(cur_item); + if (sender() == &actions_Z_down) dl.insert(ind - 1, cur_item); + if (sender() == &actions_Z_bottom) dl.prepend(cur_item); + foreach (QGraphicsItem * d, dl) scene->addItem(d); + scene->blockSignals(false); + } + if (cur_item->data(1011) == "decor") { + BlockItem * bi = qgraphicsitem_cast(cur_item->parentItem()); + if (!bi) return; + QList dl = bi->decors_; + foreach (QGraphicsItem * d, dl) d->setParentItem(0); + int ind = dl.indexOf(cur_item); + dl.removeAt(ind); + if (sender() == &actions_Z_up) dl.insert(ind + 1, cur_item); + if (sender() == &actions_Z_top) dl.append(cur_item); + if (sender() == &actions_Z_down) dl.insert(ind - 1, cur_item); + if (sender() == &actions_Z_bottom) dl.prepend(cur_item); + bi->decors_ = dl; + foreach (QGraphicsItem * d, dl) d->setParentItem(bi); + } + size_item.assignObject(cur_item); + emitZAvailabe(cur_item); + emit itemZChanged(cur_item); +} + + +void DrawTools::setResizeHandlesEnabled(bool on) { + resize_enabled = on; + if (!on) { + size_item.assignObject(0); + return; + } + if (cur_item && on) + propertyChanged(); +} diff --git a/qad/blockview/drawtools.h b/qad/blockview/drawtools.h new file mode 100644 index 0000000..fd5d546 --- /dev/null +++ b/qad/blockview/drawtools.h @@ -0,0 +1,129 @@ +#ifndef DRAWTOOLS_H +#define DRAWTOOLS_H + +#include +#include +#include +#include +#include +#include +#include "blockview.h" + +class QComboBox; + +class _DTSizeItem: public QGraphicsObject +{ + Q_OBJECT +public: + _DTSizeItem(); + ~_DTSizeItem(); + + void assignObject(QGraphicsItem * item); + +protected: + void moveRects(); + void applyRect(); + void doubleClick(); + QRectF itemRect(const QGraphicsItem * item) const; + QRectF boundingRect() const; + void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0) {} + bool sceneEventFilter(QGraphicsItem * watched, QEvent * event); + + QGraphicsItem * cur_item; + QGraphicsView * view_; + QGraphicsRectItem rects[8]; + QPointF pp, sp; + QRectF nrect; + qreal grid; + bool in_process, can_drag, is_line; + +signals: + void sizeChanged(); + void textEditRequest(); + void pixmapEditRequest(); + +}; + +namespace Ui { + class DrawTools; +}; + +class DrawTools: public QObject +{ + Q_OBJECT + Q_PROPERTY(bool resizeHandlesEnabled READ isResizeHandlesEnabled WRITE setResizeHandlesEnabled) +public: + explicit DrawTools(BlockView * parent = 0); + ~DrawTools(); + + void setBlockView(BlockView * v); + void resetSizeTool() {size_item.assignObject(0);} + bool isResizeHandlesEnabled() const {return resize_enabled;} + void setAlignCompact(bool yes); + + QComboBox * textEditCombo() const; + QList actionsForAdd() const {return actions_add;} + QList actionsForZ() const {return QList() << &actions_Z_bottom << &actions_Z_down << &actions_Z_up << &actions_Z_top;} + QWidget * propertyWidget() const {return widget_props;} + +protected: + bool eventFilter(QObject * o, QEvent * e); + + QAction * newAction(const QString & text, const QIcon & icon, int type); + void setPenBrushEnabled(bool pen, bool brush); + void blockPropSignals(bool block_); + void actionAlignTrigger(bool vert, Qt::AlignmentFlag value); + void emitZAvailabe(QGraphicsItem * item = 0); + + QWidget * widget_props; + Ui::DrawTools * ui; + BlockView * view_; + QList actions_add; + mutable QAction actions_Z_up, actions_Z_top, actions_Z_down, actions_Z_bottom; + QList buttons_align; + QGraphicsItem * new_item, * cur_item; + QFontDialog font_dlg; + QPointF pp; + QDialog text_dlg; + QPlainTextEdit text_edit; + QMenu menu_hor, menu_ver; + _DTSizeItem size_item; + Qt::Alignment align; + int new_type; + bool resize_enabled; + +private slots: + void toggleNewItem(bool on); + void alignClicked(); + void selectionChanged(); + void sizeChanged(); + void propertyChanged(); + void changeFinished() {if (cur_item) emit itemEdited(cur_item);} + void moveZUpAvailable(bool yes) {actions_Z_up.setEnabled(yes); actions_Z_top.setEnabled(yes);} + void moveZDownAvailable(bool yes) {actions_Z_down.setEnabled(yes); actions_Z_bottom.setEnabled(yes);} + + void buttonImage_clicked(); + void buttonFont_clicked(); + void buttonTextEdit_clicked(); + + void actionTop_triggered(bool on) {actionAlignTrigger(true, Qt::AlignTop);} + void actionVCenter_triggered(bool on) {actionAlignTrigger(true, Qt::AlignVCenter);} + void actionBottom_triggered(bool on) {actionAlignTrigger(true, Qt::AlignBottom);} + void actionLeft_triggered(bool on) {actionAlignTrigger(false, Qt::AlignLeft);} + void actionHCenter_triggered(bool on) {actionAlignTrigger(false, Qt::AlignHCenter);} + void actionRight_triggered(bool on) {actionAlignTrigger(false, Qt::AlignRight);} + void actionZ_triggered(); + +public slots: + void setResizeHandlesEnabled(bool on); + +signals: + void itemCreated(QGraphicsItem * item); + void itemAddConfirm(QGraphicsItem * item); + void itemEdited(QGraphicsItem * item); + void itemZChanged(QGraphicsItem * item); + +}; + + +#endif // DRAWTOOLS_H diff --git a/qad/blockview/drawtools.ui b/qad/blockview/drawtools.ui new file mode 100644 index 0000000..7449dcf --- /dev/null +++ b/qad/blockview/drawtools.ui @@ -0,0 +1,666 @@ + + + DrawTools + + + + 0 + 0 + 656 + 111 + + + + Form + + + + 0 + + + + + 3 + + + + + 0 + + + + + Font ... + + + + :/icons/draw-text.png:/icons/draw-text.png + + + + + + + Text: + + + + + + + + 0 + 0 + + + + true + + + -1 + + + 32 + + + QComboBox::NoInsert + + + + + + + Edit text ... + + + Edit text ... + + + + :/icons/document-edit-.png:/icons/document-edit-.png + + + Qt::ToolButtonIconOnly + + + + + + + + 0 + + + + + Align center left + + + + :/icons/align-hor.png:/icons/align-hor.png + + + + 27 + 22 + + + + QToolButton::InstantPopup + + + + + + + Align center left + + + + :/icons/align-ver.png:/icons/align-ver.png + + + + 27 + 22 + + + + QToolButton::InstantPopup + + + + + + + + + + + 0 + + + 2 + + + + + + 0 + 0 + + + + Align center + + + + :/icons/align-center-center.png:/icons/align-center-center.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align center right + + + + :/icons/align-center-right.png:/icons/align-center-right.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align center left + + + + :/icons/align-center-left.png:/icons/align-center-left.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align top right + + + + :/icons/align-top-right.png:/icons/align-top-right.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align bottom right + + + + :/icons/align-bottom-right.png:/icons/align-bottom-right.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align bottom center + + + + :/icons/align-bottom-center.png:/icons/align-bottom-center.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align top left + + + + :/icons/align-top-left.png:/icons/align-top-left.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align top center + + + + :/icons/align-top-center.png:/icons/align-top-center.png + + + + 27 + 16 + + + + true + + + + + + + + 0 + 0 + + + + Align bottom left + + + + :/icons/align-bottom-left.png:/icons/align-bottom-left.png + + + + 27 + 16 + + + + true + + + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + Size: + + + + + + + + 0 + 0 + + + + 0 + + + 1000.000000000000000 + + + 10.000000000000000 + + + + + + + + 0 + 0 + + + + X + + + + + + + + 0 + 0 + + + + 0 + + + 1000.000000000000000 + + + 10.000000000000000 + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + Width: + + + + + + + + 0 + 0 + + + + 1 + + + 999.000000000000000 + + + 0.500000000000000 + + + + + + + + + 0 + + + + + Load image ... + + + + :/icons/document-open.png:/icons/document-open.png + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 16 + 20 + + + + + + + + :/icons/format-stroke-color.png + + + + + + + true + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 16 + 20 + + + + + + + + :/icons/format-fill-color.png + + + + + + + true + + + true + + + + + + + true + + + Top + + + + + true + + + Center + + + Center + + + + + true + + + Bottom + + + Bottom + + + + + true + + + Center + + + Center + + + + + true + + + Left + + + Left + + + + + true + + + Right + + + Right + + + + + + ColorButton + QPushButton +
colorbutton.h
+
+
+ + + + +
diff --git a/qad/blockview/lang/qad_blockview_ru.qm b/qad/blockview/lang/qad_blockview_ru.qm new file mode 100644 index 0000000..a863ce1 Binary files /dev/null and b/qad/blockview/lang/qad_blockview_ru.qm differ diff --git a/qad/blockview/lang/qad_blockview_ru.ts b/qad/blockview/lang/qad_blockview_ru.ts new file mode 100644 index 0000000..377960d --- /dev/null +++ b/qad/blockview/lang/qad_blockview_ru.ts @@ -0,0 +1,290 @@ + + + + + Graphic + + + Autofit + Автомасштаб + + + + Grid + Сетка + + + + Cursor axis + Плавающие оси + + + + Only expand Y + Только расширять Y + + + + Only expand X + Только расширять X + + + + Border inputs + + + + + Legend + Легенда + + + + Configure ... + Настроить ... + + + + Save image ... + Сохранить изображение ... + + + + Clear + Очистить + + + + Close + Закрыть + + + + Cursor: ( ; ) + Курсор: ( ; ) + + + + + Cursor: + Курсор: + + + + Selection + Выделение + + + + Size + Размер + + + + + Range + Диапазон + + + + + Length + Длина + + + + + Cursor + Курсор + + + + Save Image + Сохранить изображение + + + + y(x) + + + + + Check all + Выбрать все + + + + GraphicConf + + + Graphic parameters + Параметры графика + + + + Appearance + Внешний вид + + + + Border inputs + + + + + Antialiasing + Сглаживание + + + + Status bar + Панель статуса + + + + OpenGL + + + + + Legend + Легенда + + + + Background color: + Цвет фона: + + + + Text color: + Цвет текста: + + + + Graphics + Графики + + + + + Color: + Цвет: + + + + + Style: + Стиль: + + + + Lines width: + Толщина линий: + + + + Points width: + Толщина точек: + + + + Fill: + Заливка: + + + + Grid + Сетка + + + + Width: + Толщина: + + + + Step X: + Шаг X: + + + + Step Y: + Шаг Y: + + + + Auto step + Автоматический шаг + + + + Margins + Поля + + + + + + + + px + пикс + + + + All: + Все: + + + + Right: + Правое: + + + + Left: + Левое: + + + + Bottom: + Нижнее: + + + + Top: + Верхнее: + + + + NoPen + НетЛинии + + + + Solid + Сплошная + + + + Dash + Штриховая + + + + Dot + Пунктирная + + + + Dash-Dot + ШтрихПунктирная + + + + Dash-Dot-Dot + ШтрихПунктирПунктирная + + + diff --git a/qad/blockview/plugin/CMakeLists.txt b/qad/blockview/plugin/CMakeLists.txt new file mode 100644 index 0000000..15ccc7a --- /dev/null +++ b/qad/blockview/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(blockview "") diff --git a/qad/blockview/plugin/blockviewplugin.cpp b/qad/blockview/plugin/blockviewplugin.cpp new file mode 100644 index 0000000..4bd2d2a --- /dev/null +++ b/qad/blockview/plugin/blockviewplugin.cpp @@ -0,0 +1,69 @@ +#include "blockview.h" +#include "blockviewplugin.h" +#include + + +BlockViewPlugin::BlockViewPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void BlockViewPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool BlockViewPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * BlockViewPlugin::createWidget(QWidget * parent) { + return new BlockView(parent); +} + + +QString BlockViewPlugin::name() const { + return QLatin1String("BlockView"); +} + + +QString BlockViewPlugin::group() const { + return QLatin1String("Display Widgets"); +} + + +QIcon BlockViewPlugin::icon() const { + return QIcon(":/icons/blockview.png"); +} + + +QString BlockViewPlugin::toolTip() const { + return QLatin1String(""); +} + + +QString BlockViewPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool BlockViewPlugin::isContainer() const { + return false; +} + + +QString BlockViewPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString BlockViewPlugin::includeFile() const { + return QLatin1String("blockview.h"); +} + diff --git a/qad/blockview/plugin/blockviewplugin.h b/qad/blockview/plugin/blockviewplugin.h new file mode 100644 index 0000000..798c154 --- /dev/null +++ b/qad/blockview/plugin/blockviewplugin.h @@ -0,0 +1,31 @@ +#ifndef BLOCKVIEWPLUGIN_H +#define BLOCKVIEWPLUGIN_H + +#include + +class BlockViewPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + BlockViewPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // BLOCKVIEWPLUGIN_H diff --git a/qad/blockview/plugin/qad_blockview.cpp b/qad/blockview/plugin/qad_blockview.cpp new file mode 100644 index 0000000..b479558 --- /dev/null +++ b/qad/blockview/plugin/qad_blockview.cpp @@ -0,0 +1,14 @@ +#include "blockviewplugin.h" +#include "qad_blockview.h" + +QADBlockView::QADBlockView(QObject * parent): QObject(parent) +{ + m_widgets.append(new BlockViewPlugin(this)); +} + + +QList QADBlockView::customWidgets() const { + return m_widgets; +} + +Q_EXPORT_PLUGIN2(qad_graphic_plugin, QADBlockView) diff --git a/qad/blockview/plugin/qad_blockview.h b/qad/blockview/plugin/qad_blockview.h new file mode 100644 index 0000000..5063596 --- /dev/null +++ b/qad/blockview/plugin/qad_blockview.h @@ -0,0 +1,21 @@ +#ifndef QAD_BLOCKVIEW_H +#define QAD_BLOCKVIEW_H + +#include +#include + +class QADBlockView: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit QADBlockView(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; + +}; + +#endif // QAD_BLOCKVIEW_H diff --git a/qad/blockview/qad_blockview.qrc b/qad/blockview/qad_blockview.qrc new file mode 100644 index 0000000..8a1aa10 --- /dev/null +++ b/qad/blockview/qad_blockview.qrc @@ -0,0 +1,53 @@ + + + lang/qad_blockview_ru.qm + ../icons/draw-line.png + ../icons/align-hor.png + ../icons/align-ver.png + ../icons/dialog-close.png + ../icons/edit-clear.png + ../icons/edit-guides.png + ../icons/view-grid.png + ../icons/zoom-fit-best.png + ../icons/configure.png + ../icons/document-save.png + ../icons/edit-clear-locationbar-rtl.png + ../icons/edit-find.png + ../icons/list-add.png + ../icons/edit-delete.png + ../icons/item.png + ../icons/node-add.png + ../icons/node.png + ../icons/edit-copy.png + ../icons/edit-paste.png + ../icons/expand_s_x.png + ../icons/expand_s_y.png + ../icons/expand_x.png + ../icons/expand_y.png + ../icons/border-line.png + ../icons/legend.png + ../icons/blockview.png + ../icons/view-fullscreen.png + ../icons/draw-ellipse.png + ../icons/draw-rectangle.png + ../icons/draw-text.png + ../icons/view-preview.png + ../icons/format-fill-color.png + ../icons/format-stroke-color.png + ../icons/document-open.png + ../icons/document-edit-.png + ../icons/align-bottom-center.png + ../icons/align-bottom-left.png + ../icons/align-bottom-right.png + ../icons/align-center-center.png + ../icons/align-center-left.png + ../icons/align-center-right.png + ../icons/align-top-center.png + ../icons/align-top-left.png + ../icons/align-top-right.png + ../icons/z-bottom.png + ../icons/z-down.png + ../icons/z-top.png + ../icons/z-up.png + + diff --git a/qad/graphic/CMakeLists.txt b/qad/graphic/CMakeLists.txt new file mode 100644 index 0000000..2fcdf87 --- /dev/null +++ b/qad/graphic/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES} qad_widgets qad_utils) +qad_project(graphic "${LIBS}") diff --git a/qad/graphic/graphic.cpp b/qad/graphic/graphic.cpp new file mode 100644 index 0000000..29318f0 --- /dev/null +++ b/qad/graphic/graphic.cpp @@ -0,0 +1,1522 @@ +#include "graphic.h" +#include "ui_graphic.h" +#include "ui_graphic_conf.h" + + +__GraphicRegistrator__ __graphic_registrator__; + + +ELineEdit::ELineEdit(QWidget * parent): CLineEdit(parent) { + last_ret = complexd_0; + is_auto = false; + is_reset = true; + connect(this, SIGNAL(editingFinished()), this, SLOT(calculate())); + connect(this, SIGNAL(cleared()), this, SLOT(toDefaultClicked())); +} + + +void ELineEdit::wheelEvent(QWheelEvent * e) { + double mul = 1.1; + if (e->delta() < 0) mul = 0.9; + CLineEdit::setText(QString::number(last_ret.real() * mul).toUpper()); + calculate(); +} + + +void ELineEdit::calculate() { + evaluator.check(text().replace(",", ".")); + if (!evaluator.isCorrect()) return; + is_reset = false; + last_ret = evaluator.evaluate(); + CLineEdit::setText(QString::number(last_ret.real()).toUpper()); + emit valueChanged(last_ret.real()); +} + + + +Graphic::Graphic(QWidget * parent): QFrame(parent), line_x_min(this), line_x_max(this), line_y_min(this), line_y_max(this) { + QTranslator * trans = new QTranslator(); + trans->load(":/lang/qad_graphic_" + QLocale::system().name().left(2)); + if (trans->isEmpty()) + trans->load("lang/qad_graphic_" + QLocale::system().name().left(2)); + qApp->installTranslator(trans); + leg_update = true; + visible_update = fullscr = false; + ui = new Ui::Graphic(); + ui->setupUi(this); + /*line_x_min.resize(70, 22); + line_x_max.resize(70, 22); + line_y_min.resize(70, 22); + line_y_max.resize(70, 22);*/ + line_x_min.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + line_x_max.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + ((QBoxLayout * )ui->widgetLY->layout())->insertWidget(0, &line_y_min); + ((QBoxLayout * )ui->widgetLY->layout())->addWidget(&line_y_max); + ((QBoxLayout * )ui->widgetLX->layout())->insertWidget(0, &line_x_min); + ((QBoxLayout * )ui->widgetLX->layout())->addWidget(&line_x_max); + tm.restart(); + grid_numbers_x = grid_numbers_y = 1; + LN2 = qLn(2.); + LN5 = qLn(5.); + LN10 = qLn(10.); + connect(&line_x_min, SIGNAL(valueChanged(double)), this, SLOT(lineXMinChanged(double))); + connect(&line_x_max, SIGNAL(valueChanged(double)), this, SLOT(lineXMaxChanged(double))); + connect(&line_y_min, SIGNAL(valueChanged(double)), this, SLOT(lineYMinChanged(double))); + connect(&line_y_max, SIGNAL(valueChanged(double)), this, SLOT(lineYMaxChanged(double))); + connect(ui->canvas_raster, SIGNAL(paintEvent(QPaintEvent * )), this, SLOT(canvasPaintEvent(QPaintEvent * ))); + connect(ui->canvas_raster, SIGNAL(mouseMoveEvent(QMouseEvent * )), this, SLOT(canvasMouseMoveEvent(QMouseEvent * ))); + connect(ui->canvas_raster, SIGNAL(mousePressEvent(QMouseEvent * )), this, SLOT(canvasMousePressEvent(QMouseEvent * ))); + connect(ui->canvas_raster, SIGNAL(mouseReleaseEvent(QMouseEvent * )), this, SLOT(canvasMouseReleaseEvent(QMouseEvent * ))); + connect(ui->canvas_raster, SIGNAL(mouseDoubleClickEvent(QMouseEvent*)), this, SLOT(canvasMouseDoubleClickEvent(QMouseEvent * ))); + connect(ui->canvas_raster, SIGNAL(wheelEvent(QWheelEvent * )), this, SLOT(canvasWheelEvent(QWheelEvent * ))); + connect(ui->canvas_raster, SIGNAL(leaveEvent(QEvent * )), this, SLOT(canvasLeaveEvent(QEvent * ))); + connect(ui->canvas_raster, SIGNAL(keyPressEvent(QKeyEvent * )), this, SLOT(canvasKeyPressEvent(QKeyEvent * ))); + connect(ui->canvas_gl, SIGNAL(paintEvent(QPaintEvent * )), this, SLOT(canvasPaintEvent(QPaintEvent * ))); + connect(ui->canvas_gl, SIGNAL(mouseMoveEvent(QMouseEvent * )), this, SLOT(canvasMouseMoveEvent(QMouseEvent * ))); + connect(ui->canvas_gl, SIGNAL(mousePressEvent(QMouseEvent * )), this, SLOT(canvasMousePressEvent(QMouseEvent * ))); + connect(ui->canvas_gl, SIGNAL(mouseReleaseEvent(QMouseEvent * )), this, SLOT(canvasMouseReleaseEvent(QMouseEvent * ))); + connect(ui->canvas_gl, SIGNAL(mouseDoubleClickEvent(QMouseEvent*)), this, SLOT(canvasMouseDoubleClickEvent(QMouseEvent * ))); + connect(ui->canvas_gl, SIGNAL(wheelEvent(QWheelEvent * )), this, SLOT(canvasWheelEvent(QWheelEvent * ))); + connect(ui->canvas_gl, SIGNAL(leaveEvent(QEvent * )), this, SLOT(canvasLeaveEvent(QEvent * ))); + connect(ui->canvas_gl, SIGNAL(keyPressEvent(QKeyEvent * )), this, SLOT(canvasKeyPressEvent(QKeyEvent * ))); + ui->canvas_raster->grabGesture(Qt::PinchGesture); + ui->canvas_raster->grabGesture(Qt::PanGesture); + ui->canvas_raster->installEventFilter(this); + ui->canvas_gl->grabGesture(Qt::PinchGesture); + ui->canvas_gl->grabGesture(Qt::PanGesture); + ui->canvas_gl->installEventFilter(this); + icon_exp_x = QIcon(":/icons/expand_x.png"); + icon_exp_y = QIcon(":/icons/expand_y.png"); + icon_exp_sx = QIcon(":/icons/expand_s_x.png"); + icon_exp_sy = QIcon(":/icons/expand_s_y.png"); + icon_pause_b = QImage(":/icons/pause-back.png"); + icon_pause_f = QImage(":/icons/pause-front.png"); + aupdate = grid = isFit = isEmpty = navigation = true; + aalias = mupdate = bufferActive = isOGL = cancel = isPrinting = guides = hasLblX = hasLblY = isHover = false; + pause_ = only_expand_x = only_expand_y = false; + //qDebug() << -DBL_MAX/2. << DBL_MAX/2. << DBL_MIN; + limit_.setCoords(-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX); + eminx = eminy = DBL_MAX; + emaxx = emaxy = DBL_MIN; + grad_x = grad_y = Auto; + axis_type_x = Numeric; + min_repaint_int = 25; + inc_x = 1.; + legy = 0; + buffer = 0; + gridx = gridy = 1.; + history = 5.; + min_int = 1; + max_int = 200; + mdm = 10.; + visible_time = -1.; + pause_phase = 0.; + selrect.setRect(0., 0., 1., 1.); + def_rect = selrect; + margins_.setRect(4, 4, 4, 4); + curaction = gaMove; + selbrush.setStyle(Qt::SolidPattern); + selbrush.setColor(QColor(60, 175, 255, 100)); + text_color = Qt::black; + grid_pen = QPen(Qt::gray, 0., Qt::DotLine); + //graph_pen = QPen(Qt::red); + //graph_pen.setCosmetic(true); + graphics.append(GraphicType()); + curGraphic = 0; + selpen = QPen(Qt::black); + selpen.setStyle(Qt::DashLine); + back_color = Qt::white; + buttons_ = AllButtons; + setButtonsPosition(Graphic::Left); + setOpenGL(false); + setAntialiasing(false); + setCaption(""); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + ui->layoutButtons->update(); + updateLegend(); + setRectToLines(); + conf = new GraphicConf(graphics, this); +} + + +Graphic::~Graphic() { + delete conf; + if (buffer != 0) delete buffer; +} + + +void Graphic::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + return; + } + QFrame::changeEvent(e); +} + + +void Graphic::timerEvent(QTimerEvent * ) { + pause_phase += 0.02; + if (pause_phase > 1.) + pause_phase -= 1.; + update(); +} + + +bool Graphic::eventFilter(QObject * o, QEvent * e) { + //qDebug() << "event" << o << e; + if (o == canvas) { + switch (e->type()) { + case QEvent::Gesture: + foreach (QGesture * g, ((QGestureEvent*)e)->gestures()) + procGesture(g); + break; + default: break; + } + } + return QFrame::eventFilter(o, e); +} + + +void Graphic::procGesture(QGesture * g) { + if (!g) return; + qDebug() << g; +} + + +void Graphic::canvasPaintEvent(QPaintEvent * ) { + if (is_lines_update) return; + QMutexLocker ml(&mutex_); + //static int pwid = 0, phei = 0; + int wid = canvas->width(), hei = canvas->height(); + lastw = wid; + lasth = hei; + font_sz = fontMetrics().size(0, "0"); + font_sz.setHeight(font_sz.height() * 1.); + font_sz.setWidth(font_sz.width() * 8); + thick = qMax(qRound(font_sz.height() / 15.), 1); + if (buffer != 0) if (buffer->width() != wid || buffer->height() != hei) {delete buffer; buffer = 0;} + if (buffer == 0) buffer = new QImage(wid, hei, QImage::Format_RGB32); + if (bufferActive) { + QPainter p(canvas); + p.drawImage(0, 0, *buffer); + painter = &p; + if (curpos != startpos) drawAction(); + drawGuides(); + return; + } + //if (!aupdate && !mupdate && pwid == wid && phei == hei) return; + /*if (pwid != wid || phei != hei) { + line_x_min.move(0, hei - 35); + line_x_max.move(0, 0); + line_y_min.move(70, hei - line_x_min.height()); + line_y_max.move(wid - line_y_max.width(), hei - line_x_min.height()); + } + line_x_min.setVisible(grid); + line_x_max.setVisible(grid); + line_y_min.setVisible(grid); + line_y_max.setVisible(grid);*/ + //pwid = wid; + //phei = hei; + QPainter p; + if (isOGL) { + glClearColor(0.f, 0.f, 0.f, 0.f); + p.begin(canvas); + } else p.begin(buffer); + p.fillRect(canvas->rect(), back_color); + painter = &p; + p.setFont(font()); + gridborder = QPoint(5, 5); + if (grid) { + gridborder += QPoint(font_sz.width(), font_sz.height()); + if (hasLblY) gridborder += QPoint(font_sz.height(), 0); + if (hasLblX) gridborder += QPoint(0, font_sz.height()); + drawGrid(); + } + p.setRenderHint(QPainter::Antialiasing, aalias); + if (isOGL) { + if (aalias) glEnable(GL_MULTISAMPLE); + else glDisable(GL_MULTISAMPLE); + } + //p.setRenderHint(QPainter::HighQualityAntialiasing, aalias); + if (!aalias) p.translate(-0.5, -0.5); + drawGraphics(); + drawGuides(); + if (pause_) drawPause(); + emit graphicPaintEvent(&p); + p.end(); + if (isOGL) return; + p.begin(canvas); + p.drawImage(0, 0, *buffer); + p.end(); +} + + +void Graphic::canvasMouseMoveEvent(QMouseEvent * e) { + isHover = true; + curpos = e->pos(); + QPointF rp = canvas2real(QPointF(e->pos())), srp = canvas2real(startpos), crp = canvas2real(curpos), dp; + QString cursorstr = tr("Cursor: ") + pointCoords(rp); + emit graphicMouseMoveEvent(rp, e->buttons()); + if (e->buttons() == Qt::NoButton) { + ui->status->setText(cursorstr); + if (guides) update(); + return; + } + if (!navigation) return; + if (curaction != gaMove && (e->buttons() & Qt::RightButton) == Qt::RightButton) return; + switch (curaction) { + case gaZoomInRect: + ui->status->setText(tr("Selection") + ": " + pointCoords(srp) + " -> " + + pointCoords(crp) + ", " + tr("Size") + ": " + pointCoords(absPoint(crp - srp))); + repaintCanvas(true); + break; + case gaZoomRangeX: + ui->status->setText(tr("Range") + ": " + QString::number(srp.x(), 'f', 3) + + " -> " + QString::number(crp.x(), 'f', 3) + ", " + tr("Length") + ": " + + QString::number(qAbs(crp.x() - srp.x()), 'f', 3)); + repaintCanvas(true); + break; + case gaZoomRangeY: + ui->status->setText(tr("Range") + ": " + QString::number(srp.y(), 'f', 3) + + " -> " + QString::number(crp.y(), 'f', 3) + ", " + tr("Length") + ": " + + QString::number(qAbs(crp.y() - srp.y()), 'f', 3)); + repaintCanvas(true); + break; + case gaMove: + dp = e->pos() - prevpos; + dp.rx() *= selrect.width() / double(gridborder.x() + 5 - lastw); + dp.ry() *= selrect.height() / double(lasth - legy - gridborder.y() - 5); + selrect.translate(dp); + isFit = false; + emit visualRectChanged(); + update(true); + setRectToLines(); + break; + default: break; + } + prevpos = e->pos(); +} + + +void Graphic::canvasMousePressEvent(QMouseEvent * e) { + emit graphicMousePressEvent(canvas2real(QPointF(e->pos())), e->buttons()); + if (!navigation) return; + ui->canvas_gl->setCursor(guides ? Qt::BlankCursor : Qt::ArrowCursor); + ui->canvas_raster->setCursor(guides ? Qt::BlankCursor : Qt::ArrowCursor); + prevpos = e->pos(); + startpos = prevpos; + if (cancel) return; + if (e->button() == Qt::MidButton) curaction = gaMove; + if (e->button() == Qt::RightButton) { + if (bufferActive) { + curpos = startpos; + repaintCanvas(true); + swapToNormal(); + cancel = true; + return; + } else { + prevaction = curaction; + curaction = gaMove; + return; + } + } + if (e->button() == Qt::LeftButton) { + if (e->modifiers() == Qt::ControlModifier) curaction = gaZoomRangeX; + else if (e->modifiers() == Qt::ShiftModifier) curaction = gaZoomRangeY; + else curaction = gaZoomInRect; + switch (curaction) { + case gaZoomInRect: + case gaZoomRangeX: + case gaZoomRangeY: + swapToBuffer(); + break; + default: break; + } + } + setCurrentAction(curaction); +} + + +void Graphic::canvasMouseReleaseEvent(QMouseEvent * e) { + emit graphicMouseReleaseEvent(canvas2real(QPointF(e->pos())), e->buttons()); + if (!navigation) return; + ui->canvas_gl->setCursor(guides ? Qt::BlankCursor : Qt::ArrowCursor); + ui->canvas_raster->setCursor(guides ? Qt::BlankCursor : Qt::ArrowCursor); + QPointF tlp, brp; + QRect sr; + sr = QRect(startpos, curpos).normalized(); + if (cancel) { + if (e->buttons() == Qt::NoButton) cancel = false; + return; + } + if (e->button() == Qt::RightButton && curaction == gaMove) { + curaction = prevaction; + return; + } + if (e->button() == Qt::LeftButton && (e->buttons() & Qt::RightButton) != Qt::RightButton) { + if (curpos != startpos) { + tlp = canvas2real(sr.topLeft()); + brp = canvas2real(sr.bottomRight()); + isFit = false; + switch (curaction) { + case gaZoomInRect: + if (sr.width() <= 1 || sr.height() <= 1) break; + selrect.setCoords(tlp.x(), brp.y(), brp.x(), tlp.y()); + setRectToLines(); + break; + case gaZoomRangeX: + if (sr.width() <= 1) break; + findGraphicsRect(tlp.x(), brp.x()); + break; + case gaZoomRangeY: + if (sr.height() <= 1) break; + findGraphicsRect(0., 0., brp.y(), tlp.y()); + break; + default: return; + } + } + swapToNormal(); + update(true); + } + QPointF rp = canvas2real(QPointF(e->pos())); + ui->status->setText(tr("Cursor") + ": " + pointCoords(rp)); + emit visualRectChanged(); +} + + +void Graphic::canvasMouseDoubleClickEvent(QMouseEvent * ) { + autofit(); +} + + +void Graphic::canvasWheelEvent(QWheelEvent * e) { + //if (curaction != gaMove) return; + emit graphicWheelEvent(canvas2real(QPointF(e->pos())), e->delta()); + if (!navigation) return; + double scl, wid = canvas->width() - gridborder.x() - margins_.width() - margins_.left(), hei = canvas->height() - gridborder.y() - margins_.height() - margins_.top(); + double px = e->pos().x() - gridborder.x() - margins_.left(), py = hei - e->pos().y() + margins_.height(); + px = px / wid * selrect.width() + selrect.x(); + py = py / hei * selrect.height() + selrect.y(); + if (e->delta() > 0) scl = 1. / 1.2; + else scl = 1.2; + if (e->modifiers() == Qt::NoModifier) + selrect.setRect(px - (px - selrect.x()) * scl, py - (py - selrect.y()) * scl, selrect.width() * scl, selrect.height() * scl); + else { + if (e->modifiers() == Qt::ControlModifier) + selrect.setRect(px - (px - selrect.x()) * scl, selrect.y(), selrect.width() * scl, selrect.height()); + if (e->modifiers() == Qt::ShiftModifier) + selrect.setRect(selrect.x(), py - (py - selrect.y()) * scl, selrect.width(), selrect.height() * scl); + } + isFit = false; + update(true); + setRectToLines(); + emit visualRectChanged(); +} + + +void Graphic::zoom(float factor) { + double wid = canvas->width() - gridborder.x() - margins_.width() - margins_.left(), hei = canvas->height() - gridborder.y() - margins_.height() - margins_.top(); + double px = wid / 2, py = hei / 2; + px = px / wid * selrect.width() + selrect.x(); + py = py / hei * selrect.height() + selrect.y(); + selrect.setRect(px - (px - selrect.x()) * factor, py - (py - selrect.y()) * factor, selrect.width() * factor, selrect.height() * factor); + isFit = false; + update(true); + setRectToLines(); +} + + +void Graphic::fullscreen() { + if (fullscr) leaveFullscreen(); + else enterFullscreen(); +} + + +void Graphic::canvasLeaveEvent(QEvent * ) { + isHover = false; + if (guides) update(true); + ui->status->setText(tr("Cursor") + ": ( ; )"); + leaveFullscreen(); +} + + +void Graphic::canvasKeyPressEvent(QKeyEvent * e) { + switch (e->key()) { + case Qt::Key_Escape: leaveFullscreen(); + default: break; + }; +} + + +void Graphic::clear() { + //cout << "clear" << endl; + for (int i = 0; i < graphics.size(); ++i) { + graphics[i].polyline.clear(); + graphics[i].polyline_pause.clear(); + graphics[i].max_x = 0.; + } + on_buttonAutofit_clicked(); +} + + +void Graphic::setAntialiasing(bool enabled) { + if (aalias == enabled) return; + aalias = enabled; + /*QGLFormat f = ui->canvas_gl->format(); + f.setSampleBuffers(enabled); + ui->canvas_gl->setFormat(f);*/ + update(); +} + + +void Graphic::setPaused(bool yes) { + pause_ = yes; + ui->checkPause->blockSignals(true); + ui->checkPause->setChecked(yes); + ui->checkPause->blockSignals(false); + if (!pause_) { + killTimer(timer_pause); + timer_pause = 0; + update(true); + return; + } + for (int i = 0; i < graphics.size(); ++i) { + graphics[i].polyline_pause = graphics[i].polyline; + graphics[i].polyline_pause.detach(); + graphics[i].max_x_pause = graphics[i].max_x; + } + timer_pause = startTimer(40); +} + + +void Graphic::setHistorySize(double val) { + history = val; + double x; + for (int i = 0; i < graphics.size(); ++i) { + QPolygonF & pol(graphics[i].polyline); + if (pol.isEmpty() || history <= 0.) continue; + x = pol.back().x() - history; + for (int j = pol.size() - 2; j >= 0 ; --j) + if (pol[j].x() < x) { + //qDebug() << pol.size() << j; + pol.erase(pol.begin(), pol.begin() + j); + break; + } + } +} + + +void Graphic::setOnlyExpandY(bool yes) { + only_expand_y = yes; + ui->checkExpandY->blockSignals(true); + ui->checkExpandY->setCheckable(yes); + ui->checkExpandY->blockSignals(false); +} + + +void Graphic::setOnlyExpandX(bool yes) { + only_expand_x = yes; + ui->checkExpandX->blockSignals(true); + ui->checkExpandX->setCheckable(yes); + ui->checkExpandX->blockSignals(false); +} + + +Graphic::GraphicsData Graphic::graphicsData() const { + GraphicsData ret; + ret.resize(graphics.size()); + for (int i = 0; i < graphics.size(); ++i) + ret[i] = graphics[i].polyline; + return ret; +} + + +void Graphic::setGraphicsData(const Graphic::GraphicsData & gd) { + setGraphicsCount(gd.size()); + for (int i = 0; i < gd.size(); ++i) + setGraphicData(gd[i], i, false); + updateGraphics(); +} + + +void Graphic::setButtons(Graphic::Buttons b) { + buttons_ = b; + ui->buttonAutofit->setVisible(b.testFlag(Autofit)); + ui->checkGrid->setVisible(b.testFlag(Grid)); + ui->checkGuides->setVisible(b.testFlag(CursorAxis)); + ui->checkExpandY->setVisible(b.testFlag(OnlyExpandY)); + ui->checkExpandX->setVisible(b.testFlag(OnlyExpandX)); + ui->buttonFullscreen->setVisible(b.testFlag(Fullscreen)); + ui->checkBorderInputs->setVisible(b.testFlag(BorderInputs)); + ui->checkLegend->setVisible(b.testFlag(Legend)); + ui->buttonClear->setVisible(b.testFlag(Clear)); + ui->buttonConfigure->setVisible(b.testFlag(Configure)); + ui->buttonSave->setVisible(b.testFlag(Save)); + ui->buttonClose->setVisible(b.testFlag(Close)); + ui->checkPause->setVisible(b.testFlag(Pause)); + if (ui->buttonAutofit->isVisible() || ui->checkGrid->isVisible() || ui->checkGuides->isVisible() || + ui->buttonConfigure->isVisible() || ui->buttonSave->isVisible() || ui->checkPause->isVisible()) + ui->verticalSpacer->changeSize(0, 30, QSizePolicy::Preferred, QSizePolicy::Preferred); + else + ui->verticalSpacer->changeSize(0, 0, QSizePolicy::Preferred, QSizePolicy::Preferred); + ui->layoutButtons->update(); +} + + +void Graphic::setButtonsPosition(Graphic::Alignment a) { + align = a; + ui->widgetLeft->hide(); + ui->widgetRight->hide(); + switch (a) { + case Graphic::Left: + ui->widgetLeft->setLayout(ui->layoutButtons); + ui->widgetLeft->show(); + break; + case Graphic::Right: + ui->widgetRight->setLayout(ui->layoutButtons); + ui->widgetRight->show(); + break; + } +} + + +void Graphic::addPoint(const QPointF & p, int graphic, bool update_) { + if (graphic >= graphics.size() || graphic < 0) return; + if (graphics.at(graphic).polyline.size() == 0) graphics[graphic].max_x = p.x(); + graphics[graphic].polyline << p; + if (graphics.at(graphic).max_x < p.x()) graphics[graphic].max_x = p.x(); + tick(graphic, true, update_); +} + + +void Graphic::setGraphicData(const QVector & g, int graphic, bool update_) { + if (graphic >= graphics.size() || graphic < 0) return; + graphics[graphic].polyline.clear(); + graphics[graphic].polyline = g; + if (graphics.at(graphic).polyline.size() == 0) { + graphics[graphic].max_x = 0.; + tick(graphic, false, update_); + return; + } + graphics[graphic].max_x = graphics.at(graphic).polyline[0].x(); + for (int i = 1; i < graphics.at(graphic).polyline.size(); ++i) + if (graphics.at(graphic).max_x < graphics.at(graphic).polyline[i].x()) + graphics[graphic].max_x = graphics.at(graphic).polyline[i].x(); + tick(graphic, false, update_); +} + + +void Graphic::setGraphicProperties(int graphic, const QString & name, const QColor& color, Qt::PenStyle style, double width, bool visible) { + if (graphic < 0 || graphic >= graphics.size()) return; + graphics[graphic].name = name; + graphics[graphic].pen.setColor(color); + graphics[graphic].pen.setStyle(style); + graphics[graphic].pen.setWidth(width); + graphics[graphic].visible = visible; + updateLegend(); +} + + +void Graphic::addGraphic(const QString & name, const QColor & color, Qt::PenStyle style, double width, bool visible) { + graphics << GraphicType(name, color, style, width, visible); + updateLegend(); +} + + +void Graphic::setVisualRect(const QRectF & rect) { + selrect = rect; + isFit = false; + update(); +} + + +void Graphic::setDefaultRect(const QRectF & rect) { + def_rect = rect; + if (isFit) autofit(); +} + + +void Graphic::saveImage() { + QString str = QFileDialog::getSaveFileName(this, tr("Save Image"), ppath, "PNG(*.png);;JPEG(*.jpg *.jpeg);;BMP(*.bmp);;TIFF(*.tiff *.tif);;PPM(*.ppm)"); + if (str == "") return; + ppath = str; + QPixmap im(canvas->size()); + mupdate = true; + canvas->render(&im); + mupdate = false; + im.save(ppath); + update(true); +} + + +void Graphic::setOpenGL(bool on) { + isOGL = on; + if (on) { + ui->canvas_raster->hide(); + ui->canvas_gl->show(); + canvas = ui->canvas_gl; + } else { + ui->canvas_gl->hide(); + ui->canvas_raster->show(); + canvas = ui->canvas_raster; + } + /*line_x_min.setParent(canvas); + line_x_max.setParent(canvas); + line_y_min.setParent(canvas); + line_y_max.setParent(canvas); + line_x_min.show(); + line_x_max.show(); + line_y_min.show(); + line_y_max.show();*/ + update(); +} + + +void Graphic::update(bool force) { + mupdate = true; + repaintCanvas(force); + mupdate = false; +} + + +void Graphic::setGraphicsCount(int arg, bool update) { + if (arg < 0) return; + while (graphics.size() < arg) + graphics.append(GraphicType(tr("y(x)"), QColor::fromHsv((graphics.size() * 55) % 360, 255, 255 - qrand() % 115))); + while (graphics.size() > arg) { + delete graphics.back().pb; + graphics.pop_back(); + } + if (update) updateLegend(); +} + + +void Graphic::setHistogramData(const QVector & g, int graphic) { + graphics[graphic].polyline.clear(); + if (g.isEmpty()) { + return; + } + QVector data = g; + QVector hist; + int ic = max_int, ci; + double md, cd, min, max, range, cx; + qSort(data); + md = DBL_MAX; + min = max = data[0]; + for (int i = 1; i < data.size(); ++i) { + if (min > data[i]) min = data[i]; + if (max < data[i]) max = data[i]; + cd = qAbs(data[i] - data[i - 1]); + if (md > cd && cd != 0.) md = cd; + } + range = max - min; + md = mdm; + //qDebug() << md << range << ic; + if (md != 0.) + ic = qRound(qMax(qMin(double(ic), range / md), double(min_int))); + md = range / ic; + hist.resize(ic); + foreach (const float & i, data) { + ci = qRound((i - min) / range * double(ic - 1)); + //if (ci < 0) ci = 0; + //if (ci >= ic) ci = ic - 1; + hist[ci]++; + } + QPolygonF & cpol(graphics[graphic].polyline); + if (hist.size() == 1 || range == 0.) { + cpol << QPointF(min - 0.5, 0.) << QPointF(min - 0.25, 0.); + cpol << QPointF(min - 0.25, hist[0]) << QPointF(min + 0.25, hist[0]); + cpol << QPointF(min + 0.25, 0.) << QPointF(min + 0.5, 0.); + } else { + cpol << QPointF(min, 0.); + for (int i = 0; i < hist.size(); ++i) { + cx = i * range / ic + min; + cpol << QPointF(cx, hist[i]) << QPointF(cx + md, hist[i]); + } + cpol << QPointF(range + min, 0.); + } + updateGraphics(); +} + + +void Graphic::findGraphicsRect(double start_x, double end_x, double start_y, double end_y) { + double cx, cy, maxX, minX, maxY, minY, vx = DBL_MIN; + bool isRangeX = (start_x != end_x), isRangeY = (start_y != end_y); + bool isEmpty = true, anyVisible = false, isTimeLimit = (visible_time > 0.) && !(isRangeX || isRangeY); + foreach (const GraphicType & t, graphics) { + const QPolygonF & pol(pause_ ? t.polyline_pause : t.polyline); + if (!pol.isEmpty()) { + isEmpty = false; + break; + } + } + if (isEmpty) { + grect = def_rect; + setRectToLines(); + return; + } + minY = minX = DBL_MAX; + maxY = maxX = -DBL_MAX; + foreach (const GraphicType & t, graphics) { + if (!t.visible) continue; + if (vx < (pause_ ? t.max_x_pause : t.max_x)) vx = (pause_ ? t.max_x_pause : t.max_x); + } + vx -= visible_time; + foreach (const GraphicType & t, graphics) { + if (!t.visible) continue; + const QPolygonF & pol(pause_ ? t.polyline_pause : t.polyline); + for (int i = 0; i < pol.size(); i++) { + cx = pol[i].x(); + cy = pol[i].y(); + if ((start_x > cx || end_x < cx) && isRangeX) continue; + if ((start_y > cy || end_y < cy) && isRangeY) continue; + if ((cx < vx) && isTimeLimit) continue; + if (maxY < cy) maxY = cy; + if (minY > cy) minY = cy; + if (maxX < cx) maxX = cx; + if (minX > cx) minX = cx; + } + if (!pol.isEmpty()) anyVisible = true; + } + if (!anyVisible) { + grect.setRect(0., 0., 1., 1.); + setRectToLines(); + return; + } + if (maxX > limit_.right()) maxX = limit_.right(); + if (minX > limit_.right()) minX = limit_.right(); + if (minX < limit_.left()) minX = limit_.left(); + if (maxX < limit_.left()) maxX = limit_.left(); + if (maxY > limit_.bottom()) maxY = limit_.bottom(); + if (minY > limit_.bottom()) minY = limit_.bottom(); + if (minY < limit_.top()) minY = limit_.top(); + if (maxY < limit_.top()) maxY = limit_.top(); + if (minX > maxX) qSwap(minX, maxX); + if (minY > maxY) qSwap(minY, maxY); + if (qAbs(minX - maxX) < 1E-60) {minX -= 1E-20; maxX += 1E-20;} + if (qAbs(minY - maxY) < 1E-60) {minY -= 1E-20; maxY += 1E-20;} + if (only_expand_x) { + if (minX > eminx) minX = eminx; + if (maxX < emaxx) maxX = emaxx; + } + if (only_expand_y) { + if (minY > eminy) minY = eminy; + if (maxY < emaxy) maxY = emaxy; + } + eminx = minX; emaxx = maxX; + eminy = minY; emaxy = maxY; + if (isRangeX) selrect.setRect(start_x, minY, end_x - start_x, maxY - minY); + else if (isRangeY) selrect.setRect(minX, start_y, maxX - minX, end_y - start_y); + else grect.setRect(minX, minY, maxX - minX, maxY - minY); + grect = grect.normalized(); + if (isFit)/* || isRangeX || isRangeY)*/ selrect = grect; + setRectToLines(); +} + + +void Graphic::drawAction() { + //qDebug() << "draw action"; + int wid = canvas->width(), hei = canvas->height() - gridborder.y(), sx = startpos.x(), sy = startpos.y(), cx = curpos.x(), cy = curpos.y(); + painter->setPen(selpen); + painter->setBrush(selbrush); + switch (curaction) { + case gaZoomInRect: + painter->drawRect(QRect(startpos, curpos)); + break; + case gaZoomRangeX: + painter->drawLine(sx, hei, sx, 0); + painter->drawLine(cx, hei, cx, 0); + painter->fillRect(sx, 0, cx - sx, hei, selbrush); + break; + case gaZoomRangeY: + painter->drawLine(gridborder.x(), sy, wid, sy); + painter->drawLine(gridborder.x(), cy, wid, cy); + painter->fillRect(gridborder.x(), sy, wid - gridborder.x(), cy - sy, selbrush); + break; + default: break; + } +} + + +void Graphic::drawGrid() { + int gbx = gridborder.x(), gby = gridborder.y(), cwid = painter->viewport().width(), chei = painter->viewport().height() - legy; + double px, py, range, step, start; + int wid = cwid - gbx - 5, hei = chei - gby - 5, cx, cy, cnt; + QRect rect; + QPair str; + + range = selrect.bottom() - selrect.top(); + if (grad_y == Graphic::Auto) step = splitRange(range, hei / gridy / font_sz.height() / 1.4); + else step = gridy;//range / hei * gridy; + start = roundTo(canvas2realY(-hei), step) - step; + py = start + step; + cy = 0; + cx = gbx - 5; + grid_pen.setWidth(qMax(qRound(thick / 1.4), 1)); + QFont sf = font(); + QFont nf = sf; + sf.setPointSizeF(qMax(sf.pointSizeF() / 1.6, 7.)); + QFontMetrics fm(nf), sfm(sf); + if (step > 0.) { + cnt = 1000; + while (cnt-- > 0) { + py -= step; + if (fabs(py) < step * .5) py = 0.; + cy = real2canvasY(py); + if (cy < 0) continue; + if (cy > hei + 5) break; + painter->setPen(grid_pen); + painter->drawLine(gbx, cy, cwid, cy); + str = gridMark(py * grid_numbers_y); + painter->setPen(text_color); + cy += font_sz.height() / 4.; + int dx = font_sz.height() / 8.; + if (!str.second.isEmpty()) { + rect = sfm.boundingRect(str.second); + painter->setFont(sf); + painter->drawText(cx - rect.width() - dx, cy - font_sz.height() / 2.5, str.second); + dx += rect.width() + font_sz.height() / 6.; + } + rect = fm.boundingRect(str.first); + painter->setFont(nf); + painter->drawText(cx - rect.width() - dx, cy, str.first); + } + } + cy = real2canvasY(0.); + if (cy >= 0 && cy <= (hei + 5)) { + QPen _p(grid_pen); + _p.setStyle(Qt::SolidLine); + painter->setPen(_p); + painter->drawLine(gbx, cy, cwid, cy); + } + if (hasLblY) { + painter->setPen(text_color); + painter->save(); + painter->translate(5, hei); + painter->rotate(-90.); + painter->drawText(0, 0, hei, font_sz.height(), Qt::AlignCenter, label_y); + painter->restore(); + } + + cy = chei - font_sz.height() / 4; + if (hasLblX) cy -= font_sz.height(); + range = selrect.right() - selrect.left(); + QString df; + if (axis_type_x == Graphic::Numeric) { + if (grad_x == Graphic::Auto) step = splitRange(range, wid / gridx / font_sz.width() * 1.4); + else step = gridx;//range / wid * gridx; + start = roundTo(canvas2realX(wid), step) + step; + px = start + step; + if (step > 0.) { + cnt = 1000; + while (cnt-- > 0) { + px -= step; + if (fabs(px) < step * .5) px = 0.; + cx = real2canvasX(px); + if (cx > cwid) continue; + if (cx < gbx) break; + painter->setPen(grid_pen); + painter->drawLine(cx, hei + 5, cx, 0); + painter->setPen(text_color); + int dx = -font_sz.height() / 4.; + painter->setFont(nf); + str = gridMark(px * grid_numbers_x); + rect = fm.boundingRect(str.first); + painter->drawText(cx + dx, cy, str.first); + dx += rect.width() + font_sz.height() / 6.; + if (!str.second.isEmpty()) { + rect = sfm.boundingRect(str.second); + painter->setFont(sf); + painter->drawText(cx + dx, cy - font_sz.height() / 2.5, str.second); + } + } + } + cx = real2canvasX(0.); + if (cx <= cwid && cx >= gbx) { + QPen _p(grid_pen); + _p.setStyle(Qt::SolidLine); + painter->setPen(_p); + painter->drawLine(cx, hei + 5, cx, 0); + } + } else { + int cur_scl[7] = {0,0,0,0,0,0,0}; + step = splitRangeDate(range, wid / gridx / font_sz.width() * 1.4, &df, cur_scl); + start = roundTo(canvas2realX(wid), step) + step; + px = start + step; + QDateTime cd = QDateTime::fromMSecsSinceEpoch(px * grid_numbers_x); + //qDebug() << "*** start" << cd << step; + roundDateTime(cd, cur_scl); + //qDebug() << "*** round" << cd; + addDateTime(cd, cur_scl); + //qDebug() << "*** add" << cd; + //qDebug() << "*** cur" << cur_scl[0] << cur_scl[1] << cur_scl[2] << cur_scl[3] << cur_scl[4] << cur_scl[5] << cur_scl[6]; + if (step > 0.) { + cnt = 1000; + while (cnt-- > 0) { + addDateTime(cd, cur_scl, -1); + //roundDateTime(cd, cur_scl); + //qDebug() << "next" << cd; + cx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x); + if (cx > cwid) continue; + if (cx < gbx) {/*qDebug() << cx << "<" << gbx;*/ break;} + painter->setPen(grid_pen); + painter->drawLine(cx, hei + 5, cx, 0); + painter->setPen(text_color); + int dx = -font_sz.height() / 4.; + painter->setFont(nf); + str.first = cd.toString(df); + painter->drawText(cx + dx, cy, str.first); + } + } + } + painter->setPen(text_color); + painter->setFont(nf); + if (hasLblX) { + painter->setPen(text_color); + painter->drawText(gbx, chei - font_sz.height(), wid, font_sz.height(), Qt::AlignCenter, label_x); + } + + painter->setPen(QPen(grid_pen.color(), thick)); + painter->drawRect(gbx, -1, wid + 6, hei + 6); +} + + +QPair Graphic::gridMark(double v) const { + QPair ret; + if ((qAbs(v) >= 1E+4 || qAbs(v) <= 1E-4) && v != 0.) { + int p = qFloor(qLn(qAbs(v)) / LN10); + v /= qPow(10., p); + if (v == 10.) { + v = 1.; + p += 1; + } + ret.first = QString::fromUtf8("%1·10").arg(v); + ret.second = QString::number(p); + } else + ret.first = QString::number(v); + return ret; +} + + +void Graphic::drawGraphics() { + if (isHover) + ui->status->setText(tr("Cursor: ") + pointCoords(canvas2real(QPointF(curpos)))); + QPointF srp = -selrect.topLeft(), cp; + double sclx, scly, wid = painter->viewport().width(), hei = painter->viewport().height() - legy, pw; + sclx = (wid - gridborder.x() - margins_.left() - margins_.width()) / selrect.width(); + scly = (hei - gridborder.y() - margins_.top() - margins_.height()) / selrect.height(); + painter->setClipping(true); + painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y())); + painter->translate(gridborder.x() + margins_.left(), hei - gridborder.y() - margins_.top()); + //if (isOGL && aalias) pen.setWidthF(1.5f); + painter->scale(sclx, -scly); + painter->translate(srp); + QTransform mat = painter->transform(); + painter->resetTransform(); + painter->setWorldMatrixEnabled(false); + QPolygonF cpol; + for (int i = 0; i < graphics.size(); ++i) { + GraphicType & t(graphics[i]); + QPolygonF & rpol(pause_ ? t.polyline_pause : t.polyline); + if (t.visible && !rpol.isEmpty()) { + pw = t.pen.widthF(); + if (t.lines) { + t.pen.setCosmetic(true); + painter->setPen(t.pen); + if (t.fill) { + cpol = rpol; + painter->setBrush(t.fill_color); + //cpol.push_front(QPointF(cpol.front().x(), 0.)); + //cpol.push_back(QPointF(cpol.back().x(), 0.)); + painter->drawPolygon(mat.map(cpol)); + } else + painter->drawPolyline(mat.map(rpol)); + } + if (t.points) { + if (qRound(t.pointWidth) == t.pointWidth) t.pen.setWidth(qRound(t.pointWidth)); + else t.pen.setWidthF(t.pointWidth); + t.pen.setCosmetic(true); + painter->setPen(t.pen); + painter->drawPoints(mat.map(rpol)); + if (qRound(pw) == pw) t.pen.setWidth(qRound(pw)); + else t.pen.setWidthF(pw); + } + } + } + painter->setWorldMatrixEnabled(true); +} + + +QString Graphic::pointCoords(QPointF point) { + if (axis_type_x == Numeric) + return "(" + QString::number(point.x(), 'f', 3) + " ; " + QString::number(point.y(), 'f', 3) + ")"; + return "(" + QDateTime::fromMSecsSinceEpoch(point.x()).toString() + " ; " + QString::number(point.y(), 'f', 3) + ")"; +} + + +void Graphic::drawGuides() { + if (!guides || !isHover) return; + int wid = canvas->width(), hei = canvas->height(); + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setPen(QPen(grid_pen.color(), qMax(qRound(thick / 1.4), 1))); + painter->resetTransform(); + painter->setClipping(true); + painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y())); + painter->drawLine(0, curpos.y(), wid, curpos.y()); + painter->drawLine(curpos.x(), 0, curpos.x(), hei); + QString str = pointCoords(canvas2real(curpos)); + QFontMetrics fm(font()); + QRect r = fm.boundingRect(str); + QPoint p = curpos + QPoint(font_sz.height() / 4., -font_sz.height() / 4.); + if (r.width() + curpos.x() > wid - font_sz.height() / 2.) p.setX(curpos.x() - r.width() - font_sz.height() / 4.); + if (curpos.y() - r.height() < font_sz.height() / 8.) p.setY(curpos.y() + r.height() - font_sz.height() / 8.); + painter->setPen(text_color); + painter->drawText(p, str); +} + + +void Graphic::drawPause() { + painter->setClipping(false); + painter->save(); + painter->resetMatrix(); + painter->translate(canvas->width() - icon_pause_b.width() - 6, 6); + double o = (0.5 - pause_phase) * 2; + painter->setOpacity(o*o); + painter->drawImage(0, 0, icon_pause_b); + painter->setOpacity(1.); + painter->drawImage(0, 0, icon_pause_f); + painter->restore(); + painter->setClipping(true); +} + + +double Graphic::splitRange(double range, int count) { + double digits, step, tln; + range = qAbs(range); + tln = qFloor(qLn(range) / LN10); + for (int i = 0; i <= 5; ++i) { + digits = qPow(10., tln - i); + step = qRound(range / count / digits); + if (step > 0.) { + digits = qPow(10., tln - i - 1); + step = qRound(range / count / digits); + break; + } + } + double step5 = qRound(step / 5.) * 5., step10 = qRound(step / 10.) * 10.; + double err5 = qAbs(step - step5), err10 = qAbs(step - step10); + step = (err5 < err10 ? step5 : step10) * digits; + return step; +} + + +double Graphic::splitRangeDate(double range, int count, QString * format, int step[7]) { + double ret = splitRange(range, count); + //qDebug() << "ret =" << ret << getScaleX(); + if (ret < 1000. * 1) {*format = "ss.zzz"; step[0] = ret;} + else if (ret < 1000. * 60) {*format = "h:m:ss"; step[1] = qRound(ret / 1000);} + else if (ret < 1000. * 60 * 60) {*format = "h:mm"; step[2] = qRound(ret / 1000 / 60);} + else if (ret < 1000. * 60 * 60 * 24) {*format = "dd(ddd) hh"; step[3] = qRound(ret / 1000 / 60 / 60);} + else if (ret < 1000. * 60 * 60 * 24 * 30) {*format = "MMM dd"; step[4] = qRound(ret / 1000 / 60 / 60 / 24);} + else if (ret < 1000. * 60 * 60 * 24 * 30 * 12) {*format = "yyyy MMM"; step[5] = qRound(ret / 1000 / 60 / 60 / 24 / 30);} + else {*format = "yyyy"; step[6] = qRound(ret / 1000 / 60 / 60 / 24 / 30 / 12);} + return ret; +} + + +double Graphic::roundTo(double value, double round_to) { + if (round_to == 0.) return value; + return qRound(value / round_to) * round_to; +} + + +void Graphic::roundDateTime(QDateTime & dt, int c[7]) { + QDate d(dt.date()); QTime t(dt.time()); + //if (c[0] != 0) t.setHMS(t.hour(), t.minute(), t.second(), 0); + if (c[1] != 0) t.setHMS(t.hour(), t.minute(), t.second()); + if (c[2] != 0) t.setHMS(t.hour(), t.minute(), 0); + if (c[3] != 0) t.setHMS(t.hour(), 0, 0); + if (c[4] != 0) {t.setHMS(0, 0, 0); d.setDate(d.year(), d.month(), d.day());} + if (c[5] != 0) {t.setHMS(0, 0, 0); d.setDate(d.year(), d.month(), 1);} + if (c[6] != 0) {t.setHMS(0, 0, 0); d.setDate(d.year(), 1, 1);} + dt = QDateTime(d, t); +} + + +void Graphic::addDateTime(QDateTime & dt, int c[7], int mul) { + if (c[0] != 0) dt = dt.addMSecs(mul * c[0]); + if (c[1] != 0) dt = dt.addSecs(mul * c[1]); + if (c[2] != 0) dt = dt.addSecs(mul * c[2] * 60); + if (c[3] != 0) dt = dt.addSecs(mul * c[3] * 60 * 60); + if (c[4] != 0) dt = dt.addDays(mul * c[4]); + if (c[5] != 0) dt = dt.addMonths(mul * c[5]); + if (c[6] != 0) dt = dt.addYears(mul * c[6]); +} + + +double Graphic::canvas2realX(double px) const { + int gbx = gridborder.x() + margins_.left(), cwid = lastw, wid = cwid - gbx - margins_.width(); + double cx = px - gbx, sclx = selrect.width() / (double)wid; + return cx * sclx + selrect.x(); +} + + +double Graphic::canvas2realY(double py) const { + int gby = gridborder.y() + margins_.top(), chei = lasth - legy, hei = chei - gby - margins_.height(); + double cy = chei - py - gby, scly = selrect.height() / (double)hei; + return cy * scly + selrect.y(); +} + + +double Graphic::real2canvasX(double px) const { + int gbx = gridborder.x() + margins_.left(), cwid = lastw, wid = cwid - gbx - margins_.width(); + double sclx = selrect.width() / (double)wid; + return (px - selrect.x()) / sclx + gbx; +} + + +double Graphic::real2canvasY(double py) const { + int gby = gridborder.y() + margins_.top(), chei = lasth - legy, hei = chei - gby - margins_.height(); + double scly = selrect.height() / (double)hei; + return chei - gby - (py - selrect.y()) / scly; +} + + +void Graphic::setCurrentAction(GraphicAction action) { + curaction = action; + switch (action) { + case gaNone: + if (guides) setCanvasCursor(Qt::BlankCursor); + else setCanvasCursor(Qt::ArrowCursor); + break; + case gaZoomInRect: + setCanvasCursor(Qt::CrossCursor); + break; + case gaZoomRangeX: + setCanvasCursor(Qt::SplitHCursor); + break; + case gaZoomRangeY: + setCanvasCursor(Qt::SplitVCursor); + break; + case gaMove: + setCanvasCursor(Qt::SizeAllCursor); + break; + } +} + + +void Graphic::setCanvasCursor(QCursor cursor) { + ui->canvas_raster->setCursor(cursor); + ui->canvas_gl->setCursor(cursor); +} + + +void Graphic::swapToBuffer() { + QImage timg; + //qDebug() << "render start"; + if (isOGL) { + timg = ui->canvas_gl->grabFrameBuffer(); + QPainter p(buffer); + p.drawImage(0, 0, timg); + p.end(); + } + //qDebug() << "render finish"; + bufferActive = true; +} + + +void Graphic::setRectToLines() { + is_lines_update = true; + line_x_min.is_auto = line_x_max.is_auto = line_y_min.is_auto = line_y_max.is_auto = true; + //qDebug() << "set to lines" << selrect; + line_x_min.is_reset = line_x_max.is_reset = line_y_min.is_reset = line_y_max.is_reset = isFit; + if (!line_x_min.hasFocus()) line_x_min.setValue(selrect.left()); + if (!line_x_max.hasFocus()) line_x_max.setValue(selrect.right()); + if (!line_y_min.hasFocus()) line_y_min.setValue(selrect.bottom()); + if (!line_y_max.hasFocus()) line_y_max.setValue(selrect.top()); + if (!isFit) { + line_x_min.setDefaultText(QString::number(grect.left()).toUpper()); + line_x_max.setDefaultText(QString::number(grect.right()).toUpper()); + line_y_min.setDefaultText(QString::number(grect.bottom()).toUpper()); + line_y_max.setDefaultText(QString::number(grect.top()).toUpper()); + } + line_x_min.is_auto = line_x_max.is_auto = line_y_min.is_auto = line_y_max.is_auto = false; + is_lines_update = false; +} + + +void Graphic::checkLines() { + isFit = (line_x_min.isDefault() && line_x_max.isDefault() && line_y_min.isDefault() && line_y_max.isDefault()); + update(true); +} + + +void Graphic::tick(int index, bool slide, bool update_) { + if (slide) { + mutex.lock(); + GraphicType & t(graphics[index]); + if (history > 0.) + while (t.polyline.size() > 1) { + if (fabs(t.polyline.back().x() - t.polyline.front().x()) <= history) break; + t.polyline.pop_front(); + } + } + if (!update_) { + if (isFit) findGraphicsRect(); + mutex.unlock(); + return; + } + //polyline.push_back(QPointF(brick->time_, brick->output(port))); + //cout << polyline.size() << endl; + if (isFit) findGraphicsRect(); + if (!slide) { + if (aupdate) update(); + return; + } + mutex.unlock(); + if (aupdate) update(); +} + + +void Graphic::on_buttonAutofit_clicked() { + isFit = true; + bool isEmpty = true; + foreach (const GraphicType & t, graphics) { + const QPolygonF & pol(pause_ ? t.polyline_pause : t.polyline); + if (!pol.isEmpty()) { + isEmpty = false; + break; + } + } + if (isEmpty) grect = def_rect; + selrect = grect; + findGraphicsRect(); + update(); +} + + +void Graphic::on_buttonConfigure_clicked() { + conf->graphicItems.clear(); + for (int i = 0; i < graphics.size(); i++) { + GraphicConf::GraphicItem item; + item.icon = graphics[i].icon; + item.name = graphics[i].name; + conf->graphicItems.append(item); + } + conf->ui->colorGrid->setColor(grid_pen.color()); + conf->ui->comboStyleGrid->setCurrentIndex((int)grid_pen.style()); + conf->ui->spinWidthGrid->setValue(grid_pen.widthF()); + conf->ui->checkOGL->setChecked(isOGL); + conf->ui->checkAAlias->setChecked(aalias); + conf->ui->checkInputs->setChecked(borderInputsVisible()); + conf->ui->checkStatus->setChecked(statusVisible()); + conf->ui->checkLegend->setChecked(legendVisible()); + conf->ui->checkGridAutoX->setChecked(grad_x == Auto); + conf->ui->checkGridAutoY->setChecked(grad_y == Auto); + conf->ui->colorBackground->setColor(back_color); + conf->ui->colorText->setColor(text_color); + conf->ui->spinGridStepX->setValue(gridx); + conf->ui->spinGridStepY->setValue(gridy); + conf->ui->spinMarginL->setValue(margins_.left()); + conf->ui->spinMarginT->setValue(margins_.height()); + conf->ui->spinMarginR->setValue(margins_.width()); + conf->ui->spinMarginB->setValue(margins_.top()); + conf->readParams(); + if (conf->exec() == QDialog::Rejected) return; + grid_pen = QPen(conf->ui->colorGrid->color(), conf->ui->spinWidthGrid->value(), (Qt::PenStyle)conf->ui->comboStyleGrid->currentIndex()); + back_color = conf->ui->colorBackground->color(); + text_color = conf->ui->colorText->color(); + grad_x = conf->ui->checkGridAutoX->isChecked() ? Auto : Fixed; + grad_y = conf->ui->checkGridAutoY->isChecked() ? Auto : Fixed; + gridx = conf->ui->spinGridStepX->value(); + gridy = conf->ui->spinGridStepY->value(); + setOpenGL(conf->ui->checkOGL->isChecked()); + setAntialiasing(conf->ui->checkAAlias->isChecked()); + setBorderInputsVisible(conf->ui->checkInputs->isChecked()); + setStatusVisible(conf->ui->checkStatus->isChecked()); + setLegendVisible(conf->ui->checkLegend->isChecked()); + setMargins(conf->ui->spinMarginL->value(), conf->ui->spinMarginR->value(), conf->ui->spinMarginT->value(), conf->ui->spinMarginB->value()); + updateLegend(); + update(); +} + + +void Graphic::on_checkGuides_toggled(bool checked) { + guides = checked; + if (guides) setCanvasCursor(Qt::BlankCursor); + else setCanvasCursor(Qt::ArrowCursor); + update(); +} + + +void Graphic::updateLegend() { + if (!ui->widgetLegend->isVisible()) return; + leg_update = false; + int ps = 100; + for (int i = 0; i < graphics.size(); i++) { + while (!graphics[i].pb->actions().isEmpty()) graphics[i].pb->removeAction(graphics[i].pb->actions()[0]); + delete graphics[i].pb; + QPixmap pix(60, 22); + pix.fill(back_color); + QPainter p(&pix); + p.setPen(graphics[i].pen); + p.drawLine(0, pix.height() / 2, pix.width(), pix.height() / 2); + p.end(); + graphics[i].icon = QIcon(pix); + graphics[i].pb = new QCheckBox(graphics[i].name); + graphics[i].pb->setIconSize(pix.size()); + //graphics[i].pb->setFlat(true); + graphics[i].pb->setIcon(graphics[i].icon); + graphics[i].pb->setChecked(graphics[i].visible); + graphics[i].pb->setProperty("graphic_num", i); + graphics[i].pb->setContextMenuPolicy(Qt::ActionsContextMenu); + //qDebug() << graphics[i].pb->actions(); + QAction * act = new QAction(trUtf8("Check all"), 0); + act->setCheckable(true); + act->setChecked(true); + graphics[i].pb->addAction(act); + connect(act, SIGNAL(triggered(bool)), this, SLOT(graphicAllVisibleChange(bool))); + connect(graphics[i].pb, SIGNAL(toggled(bool)), this, SLOT(graphicVisibleChange(bool))); + int cps = graphics[i].pb->sizeHint().width() + 4; + if (cps > ps) ps = cps; + } + int maxcol = qMax(ui->widgetLegend->width() / ps - 1, 1); + int row = 0, col = 0; + bool lv = ui->widgetLegend->isVisible(); + ui->widgetLegend->hide(); + for (int i = 0; i < graphics.size(); i++) { + ui->layoutLegend->addWidget(graphics[i].pb,row,col); + col++; + if (col > maxcol) {col = 0; row++;} + } + ui->widgetLegend->setVisible(lv); + leg_update = true; +} + + +void Graphic::graphicVisibleChange(bool checked) { + if (visible_update) return; + QCheckBox * cb = qobject_cast(sender()); + int i = cb->property("graphic_num").toInt(); + graphics[i].visible = checked; + if (isFit) on_buttonAutofit_clicked(); + else update(); +// update(); +} + + +void Graphic::graphicAllVisibleChange(bool checked) { + visible_update = true; + for (int i=0; isetChecked(checked); + } + visible_update = false; + if (isFit) on_buttonAutofit_clicked(); + else update(); +} + + +void Graphic::enterFullscreen() { + if (fullscr) return; + ui->layoutCanvas->removeWidget(canvas); + canvas->setParent(0); + canvas->showFullScreen(); + canvas->setFocus(); + canvas->raise(); + fullscr = true; +} + + +void Graphic::leaveFullscreen() { + if (!fullscr) return; + canvas->setWindowFlags(canvas->windowFlags() & ~Qt::WindowFullScreen); + ui->layoutCanvas->addWidget(canvas); + canvas->show(); + fullscr = false; +} + + +QString Graphic::caption() const { + return ui->labelCaption->text(); +} + + +bool Graphic::borderInputsVisible() const { + return ui->widgetLX->isVisible(); +} + + +bool Graphic::statusVisible() const { + return ui->status->isVisible(); +} + + +bool Graphic::legendVisible() const { + return ui->widgetLegend->isVisible(); +} + + +QByteArray Graphic::save() { + QByteArray ba; + QDataStream s(&ba, QIODevice::ReadWrite); + s << openGL() << antialiasing() << borderInputsVisible() << statusVisible() << legendVisible(); + s << graphics; + return ba; +} + + +void Graphic::load(QByteArray ba) { + if (ba.isEmpty()) return; + QDataStream s(ba); + bool a; + s >> a; setOpenGL(a); + s >> a; setAntialiasing(a); + s >> a; setBorderInputsVisible(a); + s >> a; setStatusVisible(a); + s >> a; setLegendVisible(a); + s >> graphics; +} + + +void Graphic::setCaption(const QString & str) { + ui->labelCaption->setText(str); + ui->labelCaption->setVisible(str.length() > 0); + if (aupdate) update(); +} + + +void Graphic::setGridEnabled(bool enabled) { + ui->checkGrid->setChecked(enabled); +} + + +void Graphic::setBorderInputsVisible(bool visible) { + ui->widgetLX->setVisible(visible); + ui->widgetLY->setVisible(visible); + ui->checkBorderInputs->setChecked(visible); +} + + +void Graphic::setStatusVisible(bool visible) { + ui->status->setVisible(visible); +} + + +void Graphic::setLegendVisible(bool visible) { + ui->widgetLegend->setVisible(visible); + ui->checkLegend->setChecked(visible); + updateLegend(); +} + + +void Graphic::on_checkExpandY_toggled(bool checked) { + only_expand_y = checked; + ui->checkExpandY->setIcon(checked ? icon_exp_y : icon_exp_sy); +} + + +void Graphic::on_checkExpandX_toggled(bool checked) { + only_expand_x = checked; + ui->checkExpandX->setIcon(checked ? icon_exp_x : icon_exp_sx); +} diff --git a/qad/graphic/graphic.h b/qad/graphic/graphic.h new file mode 100644 index 0000000..8a1688f --- /dev/null +++ b/qad/graphic/graphic.h @@ -0,0 +1,459 @@ +#ifndef GRAPHIC_H +#define GRAPHIC_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "graphic_conf.h" +#include "clineedit.h" +#include "qpievaluator.h" +#if QT_VERSION >= 0x050100 +# include +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class ELineEdit: public CLineEdit { + Q_OBJECT +public: + explicit ELineEdit(QWidget * parent = 0); + //void setText(const QString & v) {if (!is_auto) is_reset = false; CLineEdit::setText(v); setDefaultText(v, is_reset); last_ret = complexd(v.toDouble(), 0.); emit valueChanged(last_ret.real());} + void setValue(const int & v) {if (is_reset) setDefaultText(QString::number(v).toUpper(), is_reset); else setText(QString::number(v).toUpper()); last_ret = complexd(v, 0.); if (!is_auto) emit valueChanged(last_ret.real());} + void setValue(const double & v) {if (is_reset) setDefaultText(QString::number(v).toUpper(), is_reset); else setText(QString::number(v).toUpper()); last_ret = complexd(v, 0.); if (!is_auto) emit valueChanged(last_ret.real());} + double value() const {return last_ret.real();} + bool isDefault() const {return !cw->isVisible();} + bool is_reset, is_auto; +protected: + void wheelEvent(QWheelEvent * e); + QPIEvaluator evaluator; + complexd last_ret; +private slots: + void toDefaultClicked() {is_reset = true; calculate();} + void calculate(); +signals: + void valueChanged(double value); +}; + + +namespace Ui { + class Graphic; +}; + + +class Graphic: public QFrame +{ + Q_OBJECT + Q_FLAGS(Buttons) + Q_ENUMS(Alignment Graduation AxisType) + + Q_PROPERTY(QString caption READ caption WRITE setCaption) + Q_PROPERTY(QString labelX READ labelX WRITE setLabelX) + Q_PROPERTY(QString labelY READ labelY WRITE setLabelY) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor) + Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor) + + Q_PROPERTY(int currentGraphic READ currentGraphic WRITE setCurrentGraphic) + Q_PROPERTY(int graphicsCount READ graphicsCount WRITE setGraphicsCount) + Q_PROPERTY(QString graphicName READ graphicName WRITE setGraphicName) + Q_PROPERTY(QPen graphicPen READ graphicPen WRITE setGraphicPen) + Q_PROPERTY(QColor graphicColor READ graphicColor WRITE setGraphicColor) + Q_PROPERTY(Qt::PenStyle graphicStyle READ graphicStyle WRITE setGraphicStyle) + Q_PROPERTY(double graphicLineWidth READ graphicLineWidth WRITE setGraphicLineWidth) + Q_PROPERTY(double graphicPointWidth READ graphicPointWidth WRITE setGraphicPointWidth) + Q_PROPERTY(QColor graphicFillColor READ graphicFillColor WRITE setGraphicFillColor) + Q_PROPERTY(bool graphicLinesEnabled READ graphicLinesEnabled WRITE setGraphicLinesEnabled) + Q_PROPERTY(bool graphicPointsEnabled READ graphicPointsEnabled WRITE setGraphicPointsEnabled) + Q_PROPERTY(bool graphicFillEnabled READ graphicFillEnabled WRITE setGraphicFillEnabled) + + Q_PROPERTY(bool gridEnabled READ gridEnabled WRITE setGridEnabled) + Q_PROPERTY(QPen gridPen READ gridPen WRITE setGridPen) + Q_PROPERTY(QColor gridColor READ gridColor WRITE setGridColor) + Q_PROPERTY(Qt::PenStyle gridStyle READ gridStyle WRITE setGridStyle) + + Q_PROPERTY(QPen selectionPen READ selectionPen WRITE setSelectionPen) + Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor) + Q_PROPERTY(Qt::PenStyle selectionStyle READ selectionStyle WRITE setSelectionStyle) + Q_PROPERTY(QBrush selectionBrush READ selectionBrush WRITE setSelectionBrush) + + Q_PROPERTY(Alignment buttonsPosition READ buttonsPosition WRITE setButtonsPosition) + Q_PROPERTY(Buttons buttons READ buttons WRITE setButtons) + Q_PROPERTY(bool navigationEnabled READ navigationEnabled WRITE setNavigationEnabled) + Q_PROPERTY(bool openGL READ openGL WRITE setOpenGL) + Q_PROPERTY(bool antialiasing READ antialiasing WRITE setAntialiasing) + Q_PROPERTY(bool autoUpdate READ autoUpdate WRITE setAutoUpdate) + Q_PROPERTY(bool borderInputsVisible READ borderInputsVisible WRITE setBorderInputsVisible) + Q_PROPERTY(bool statusVisible READ statusVisible WRITE setStatusVisible) + Q_PROPERTY(bool legendVisible READ legendVisible WRITE setLegendVisible) + Q_PROPERTY(bool paused READ paused WRITE setPaused) + Q_PROPERTY(bool onlyExpandY READ onlyExpandY WRITE setOnlyExpandY) + Q_PROPERTY(bool onlyExpandX READ onlyExpandX WRITE setOnlyExpandX) + Q_PROPERTY(double historySize READ historySize WRITE setHistorySize) + Q_PROPERTY(double maxVisibleTime READ maxVisibleTime WRITE setMaxVisibleTime) + Q_PROPERTY(double autoXIncrement READ autoXIncrement WRITE setAutoXIncrement) + Q_PROPERTY(QRectF limit READ limit WRITE setLimit) + Q_PROPERTY(QRect margins READ margins WRITE setMargins) + Q_PROPERTY(QRectF visualRect READ visualRect WRITE setVisualRect) + Q_PROPERTY(QRectF defaultRect READ defaultRect WRITE setDefaultRect) + Q_PROPERTY(int minimumRepaintInterval READ minimumRepaintInterval WRITE setMinimumRepaintInterval) + + Q_PROPERTY(double gridNumbersMultiplierX READ gridNumbersMultiplierX WRITE setGridNumbersMultiplierX) + Q_PROPERTY(double gridNumbersMultiplierY READ gridNumbersMultiplierY WRITE setGridNumbersMultiplierY) + Q_PROPERTY(Graduation graduationX READ graduationX WRITE setGraduationX) + Q_PROPERTY(Graduation graduationY READ graduationY WRITE setGraduationY) + Q_PROPERTY(double graduationStepX READ graduationStepX WRITE setGraduationStepX) + Q_PROPERTY(double graduationStepY READ graduationStepY WRITE setGraduationStepY) + Q_PROPERTY(AxisType axisType READ axisType WRITE setAxisType) + + Q_PROPERTY(int histogramMinIntervals READ histogramMinIntervals WRITE setHistogramMinIntervals) + Q_PROPERTY(int histogramMaxIntervals READ histogramMaxIntervals WRITE setHistogramMaxIntervals) + Q_PROPERTY(double histogramMinDeltaMultiplier READ histogramMinDeltaMultiplier WRITE setHistogramMinDeltaMultiplier) + + Q_PROPERTY(Graphic::GraphicsData graphicsData READ graphicsData WRITE setGraphicsData) + +public: + Graphic(QWidget * parent = 0); + ~Graphic(); + + typedef QVector > GraphicsData; + enum GraphicAction {gaNone, gaZoomInRect, gaZoomRangeX, gaZoomRangeY, gaMove}; + enum Button {NoButtons = 0x0, + AllButtons = 0xFFFFFFFF, + Autofit = 0x01, + Grid = 0x02, + CursorAxis = 0x04, + OnlyExpandY = 0x08, + OnlyExpandX = 0x10, + Fullscreen = 0x20, + BorderInputs = 0x40, + Legend = 0x80, + Configure = 0x100, + Save = 0x200, + Clear = 0x800, + Close = 0x1000, + Pause = 0x2000 + }; + enum Alignment {Left, Right}; + enum Graduation {Auto, Fixed}; + enum AxisType {Numeric, DateTime}; + Q_DECLARE_FLAGS(Buttons, Button) + + QString caption() const; + QString labelX() const {return label_x;} + QString labelY() const {return label_y;} + QString graphicName() const {return graphics[curGraphic].name;} + QColor backgroundColor() const {return back_color;} + QColor textColor() const {return text_color;} + QColor graphicColor() const {return graphics[curGraphic].pen.color();} + QColor gridColor() const {return grid_pen.color();} + QColor selectionColor() const {return selpen.color();} + Qt::PenStyle graphicStyle() const {return graphics[curGraphic].pen.style();} + Qt::PenStyle gridStyle() const {return grid_pen.style();} + Qt::PenStyle selectionStyle() const {return selpen.style();} + double graphicLineWidth() const {return graphics[curGraphic].pen.widthF();} + double graphicPointWidth() const {return graphics[curGraphic].pointWidth;} + QColor graphicFillColor() const {return graphics[curGraphic].fill_color;} + bool graphicVisible() const {return graphics[curGraphic].visible;} + bool graphicLinesEnabled() const {return graphics[curGraphic].lines;} + bool graphicPointsEnabled() const {return graphics[curGraphic].points;} + bool graphicFillEnabled() const {return graphics[curGraphic].fill;} + QPen graphicPen() const {return graphics[curGraphic].pen;} + QPen gridPen() const {return grid_pen;} + QPen selectionPen() const {return selpen;} + QBrush selectionBrush() const {return selbrush;} + bool navigationEnabled() const {return navigation;} + bool openGL() const {return isOGL;} + bool antialiasing() const {return aalias;} + bool autoUpdate() const {return aupdate;} + bool gridEnabled() const {return grid;} + bool borderInputsVisible() const; + bool statusVisible() const; + bool legendVisible() const; + bool paused() const {return pause_;} + bool onlyExpandY() const {return only_expand_y;} + bool onlyExpandX() const {return only_expand_x;} + int currentGraphic() const {return curGraphic;} + int graphicsCount() const {return graphics.size();} + Graphic::Buttons buttons() const {return buttons_;} + Graphic::Alignment buttonsPosition() const {return align;} + double historySize() const {return history;} + double maxVisibleTime() const {return visible_time;} + double autoXIncrement() const {return inc_x;} + QRectF visualRect() const {return selrect;} + QRectF defaultRect() const {return def_rect;} + QRectF limit() const {return limit_;} + QRect margins() const {return margins_;} + int minimumRepaintInterval() const {return min_repaint_int;} + int histogramMinIntervals() const {return min_int;} + int histogramMaxIntervals() const {return max_int;} + double histogramMinDeltaMultiplier() const {return mdm;} + double gridNumbersMultiplierX() const {return grid_numbers_x;} + double gridNumbersMultiplierY() const {return grid_numbers_y;} + Graduation graduationX() const {return grad_x;} + Graduation graduationY() const {return grad_y;} + double graduationStepX() const {return gridx;} + double graduationStepY() const {return gridy;} + AxisType axisType() const {return axis_type_x;} + QVector graphicData(const int index = 0) const {return graphics[index].polyline;} + GraphicsData graphicsData() const; + QWidget * viewport() const {return canvas;} + QByteArray save(); + void load(QByteArray ba); + void lock() {mutex_.lock();} + void unlock() {mutex_.unlock();} + + void reset() {mutex.lock(); clear(); mutex.unlock();} + + GraphicType graphic(int arg) {if (arg < 0 || arg >= graphics.size()) return GraphicType(); return graphics[arg];} + const QVector & allGraphics() const {return graphics;} + void setAllGraphics(const QVector & g, bool update = true) {graphics = g; if (update) updateLegend();} + void setHistogramData(const QVector & g, int graphic); + void setHistogramData(const QVector & g) {setHistogramData(g, curGraphic);} + + double canvas2realX(double px) const; + double canvas2realY(double py) const; + double real2canvasX(double px) const; + double real2canvasY(double py) const; + QPointF canvas2real(QPointF canvas_point) const {return QPointF(canvas2realX(canvas_point.x()), canvas2realY(canvas_point.y()));} + QPointF real2canvas(QPointF real_point) const {return QPointF(real2canvasX(real_point.x()), real2canvasY(real_point.y()));} + double getScaleX() const {return real2canvasX(1.) - real2canvasX(0.);} + double getScaleY() const {return real2canvasY(1.) - real2canvasY(0.);} + QPointF getScale() const {return QPointF(getScaleX(), getScaleY());} + +public slots: + void setCaption(const QString & str); + void setLabelX(const QString & str) {label_x = str; hasLblX = (str.length() > 0); if (aupdate) update();} + void setLabelY(const QString & str) {label_y = str; hasLblY = (str.length() > 0); if (aupdate) update();} + void setGraphicName(const QString & str, int index) {graphics[index].name = str; updateLegend(); if (aupdate) update();} + void setGraphicName(const QString & str) {graphics[curGraphic].name = str; updateLegend(); if (aupdate) update();} + void setBackgroundColor(const QColor & color) {back_color = color; if (aupdate) update(); updateLegend();} + void setTextColor(const QColor & color) {text_color = color; if (aupdate) update();} + void setGraphicColor(const QColor & color, int index) {graphics[index].pen.setColor(color); updateLegend(); if (aupdate) update();} + void setGraphicColor(const QColor & color) {setGraphicColor(color, curGraphic);} + void setGridColor(const QColor & color) {grid_pen.setColor(color); if (aupdate) update();} + void setSelectionColor(const QColor & color) {selpen.setColor(color);} + void setGraphicStyle(const Qt::PenStyle & style) {graphics[curGraphic].pen.setStyle(style); updateLegend(); if (aupdate) update();} + void setGridStyle(const Qt::PenStyle & style) {grid_pen.setStyle(style); if (aupdate) update();} + void setSelectionStyle(const Qt::PenStyle & style) {selpen.setStyle(style);} + void setGraphicVisible(bool visible, int index) {graphics[index].visible = visible; updateLegend(); if (aupdate) update();} + void setGraphicVisible(bool visible) {setGraphicVisible(visible, curGraphic);} + void setGraphicLineWidth(double w, int index) {if (qRound(w) == w) graphics[index].pen.setWidth(qRound(w)); else graphics[index].pen.setWidthF(w); updateLegend(); if (aupdate) update();} + void setGraphicLineWidth(double w) {setGraphicLineWidth(w, curGraphic);} + void setGraphicPointWidth(double w, int index) {graphics[index].pointWidth = w; updateLegend(); if (aupdate) update();} + void setGraphicPointWidth(double w) {setGraphicPointWidth(w, curGraphic);} + void setGraphicFillColor(const QColor & w, int index) {graphics[index].fill_color = w; updateLegend(); if (aupdate) update();} + void setGraphicFillColor(const QColor & w) {setGraphicFillColor(w, curGraphic);} + void setGraphicLinesEnabled(bool w, int index) {graphics[index].lines = w; updateLegend(); if (aupdate) update();} + void setGraphicLinesEnabled(bool w) {setGraphicLinesEnabled(w, curGraphic);} + void setGraphicPointsEnabled(bool w, int index) {graphics[index].points = w; updateLegend(); if (aupdate) update();} + void setGraphicPointsEnabled(bool w) {setGraphicPointsEnabled(w, curGraphic);} + void setGraphicFillEnabled(bool w, int index) {graphics[index].fill = w; updateLegend(); if (aupdate) update();} + void setGraphicFillEnabled(bool w) {setGraphicFillEnabled(w, curGraphic);} + void setGraphicPen(const QPen & pen, int index) {graphics[index].pen = pen; updateLegend(); if (aupdate) update();} + void setGraphicPen(const QPen & pen) {setGraphicPen(pen, curGraphic);} + void setGridPen(const QPen & pen) {grid_pen = pen; if (aupdate) update();} + void setSelectionPen(const QPen & pen) {selpen = pen;} + void setSelectionBrush(const QBrush & brush) {selbrush = brush;} + void setNavigationEnabled(bool on) {navigation = on;} + void setOpenGL(bool on); + void setAntialiasing(bool enabled); + void setAutoUpdate(bool enabled) {aupdate = enabled;} + void setGridEnabled(bool enabled); + void setBorderInputsVisible(bool visible); + void setStatusVisible(bool visible); + void setLegendVisible(bool visible); + void setPaused(bool yes); + void setButtons(Graphic::Buttons b); + void setButtonsPosition(Graphic::Alignment a); + void setHistorySize(double val); + void setMaxVisibleTime(double val) {visible_time = val;} + void setAutoXIncrement(double val) {inc_x = val;} + void setLimit(const QRectF & val) {limit_ = val;} + void setMargins(const QRect & val) {margins_ = val; update();} + void setMargins(int left_, int right_, int top_, int bottom_) {setMargins(QRect(left_, bottom_, right_, top_));} + void setLeftMargin(int value) {margins_.moveLeft(value); setMargins(margins_);} + void setRightMargin(int value) {margins_.setWidth(value); setMargins(margins_);} + void setTopMargin(int value) {margins_.setHeight(value); setMargins(margins_);} + void setBottomMargin(int value) {margins_.moveTop(value); setMargins(margins_);} + void setMinimumRepaintInterval(const int & val) {min_repaint_int = val;} + void setOnlyExpandY(bool yes); + void setOnlyExpandX(bool yes); + void setHistogramMinIntervals(int value) {min_int = value; updateGraphics();} + void setHistogramMaxIntervals(int value) {max_int = value; updateGraphics();} + void setHistogramMinDeltaMultiplier(double value) {mdm = value; updateGraphics();} + void setGraphicsData(const GraphicsData & gd); + + void setGridNumbersMultiplierX(double value) {grid_numbers_x = value; updateGraphics();} + void setGridNumbersMultiplierY(double value) {grid_numbers_y = value; updateGraphics();} + void setGraduationX(Graduation value) {grad_x = value; if (aupdate) update();;} + void setGraduationY(Graduation value) {grad_y = value; if (aupdate) update();;} + void setGraduationStepX(double sx) {gridx = sx; if (aupdate) update();} + void setGraduationStepY(double sy) {gridy = sy; if (aupdate) update();} + void setGraduationSteps(double sx, double sy) {gridx = sx; gridy = sy; if (aupdate) update();} + void setAxisType(AxisType t) {axis_type_x = t; if (aupdate) update();} + + void addPoint(const QPointF & p, int graphic, bool update_ = true); + void addPoint(const QPointF & p, bool update = true) {addPoint(p, curGraphic, update);} + void addPoint(double x, double y, int graphic, bool update = true) {addPoint(QPointF(x, y), graphic, update);} + void addPoint(double x, double y, bool update = true) {addPoint(QPointF(x, y), update);} + void addPoint(double y, int graphic, bool update = true) {addPoint(QPointF(graphics.at(graphic).max_x + inc_x, y), graphic, update);} + void addPoint(double y, bool update = true) {addPoint(QPointF(graphics[curGraphic].max_x + inc_x, y), update);} + void setGraphicData(const QVector & g, int graphic, bool update_ = true); + void setGraphicData(const QVector & g) {setGraphicData(g, curGraphic);} + void setGraphicProperties(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true) {setGraphicProperties(curGraphic, name, color, style, width, visible);} + void setGraphicProperties(int graphic, const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true); + void addGraphic(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true); + void addGraphic(const GraphicType & gd, bool update = true) {graphics << gd; if (update) updateLegend();} + void setVisualRect(const QRectF & rect); + void setDefaultRect(const QRectF & rect); + void autofit() {on_buttonAutofit_clicked();} + void saveImage(); + void clear(); + void update(bool force = false); + void updateGraphics() {findGraphicsRect(); update();} + void setCurrentGraphic(int arg) {if (arg < 0 || arg >= graphics.size()) return; curGraphic = arg;} + void setGraphicsCount(int arg, bool update = true); + + void zoom(float factor); + void zoomIn() {zoom(1. / 1.2);} + void zoomOut() {zoom(1.2);} + void fullscreen(); + +protected: + virtual void changeEvent(QEvent * e); + virtual void resizeEvent(QResizeEvent * ) {if (leg_update) updateLegend();} + virtual QSize sizeHint() const {return QSize(400, 300);} + virtual void timerEvent(QTimerEvent * ); + virtual bool eventFilter(QObject * o, QEvent * e); + + void procGesture(QGesture * g); + void setCurrentAction(GraphicAction action); + void findGraphicsRect(double start_x = 0., double end_x = 0., double start_y = 0., double end_y = 0.); + void tick(int index, bool slide = true, bool update = true); + void repaintCanvas(bool force = false) {if (tm.elapsed() < min_repaint_int && !force) return; tm.restart(); canvas->update();} + void drawGraphics(); + void drawGrid(); + void drawGuides(); + void drawPause(); + void drawAction(); + void updateLegend(); + void setCanvasCursor(QCursor cursor); + void swapToBuffer(); + void swapToNormal() {bufferActive = false;} + void setRectToLines(); + void checkLines(); + double splitRange(double range, int count = 1); + double splitRangeDate(double range, int count = 1, QString * format = 0, int step[7] = 0); + double roundTo(double value, double round_to); + void roundDateTime(QDateTime & dt, int c[7]); + void addDateTime(QDateTime & dt, int c[7], int mul = 1); + QPointF absPoint(QPointF point) {return QPointF(qAbs(point.x()), qAbs(point.y()));} + QString pointCoords(QPointF point); + QPair gridMark(double v) const; + + Ui::Graphic * ui; + QMutex mutex, mutex_; + QWidget * canvas; + QImage * buffer; + QPainter * painter; + QBrush selbrush; + QPen grid_pen, selpen; + QColor back_color, text_color; + QVector graphics; + int curGraphic; + GraphicAction curaction, prevaction; + QRectF grect, rrect, selrect, limit_, def_rect; + QRect margins_; + QSize font_sz; + QPoint startpos, curpos, prevpos, gridborder; + QString label_x, label_y, ppath; + Graphic::Buttons buttons_; + Graphic::Alignment align; + GraphicConf * conf; + ELineEdit line_x_min, line_x_max, line_y_min, line_y_max; + QTime tm; + QIcon icon_exp_x, icon_exp_y, icon_exp_sx, icon_exp_sy; + QImage icon_pause_b, icon_pause_f; + Graduation grad_x, grad_y; + AxisType axis_type_x; + double gridx, gridy, history, visible_time, inc_x, mdm, grid_numbers_x, grid_numbers_y, LN2, LN5, LN10; + double eminx, eminy, emaxx, emaxy, pause_phase; + int legy, lastw, lasth, min_repaint_int, min_int, max_int, timer_pause, thick; + bool aalias, aupdate, mupdate, grid, guides, isFit, isEmpty, isOGL, isHover, bufferActive, cancel, pause_, isPrinting; + bool hasLblX, hasLblY, navigation, only_expand_y, only_expand_x, is_lines_update, leg_update, visible_update, fullscr; + +protected slots: + void canvasPaintEvent(QPaintEvent * ); + void canvasMouseMoveEvent(QMouseEvent * ); + void canvasMousePressEvent(QMouseEvent * ); + void canvasMouseReleaseEvent(QMouseEvent * ); + void canvasMouseDoubleClickEvent(QMouseEvent * ); + void canvasWheelEvent(QWheelEvent * ); + void canvasLeaveEvent(QEvent * ); + void canvasKeyPressEvent(QKeyEvent * ); + void graphicVisibleChange(bool checked); + void graphicAllVisibleChange(bool checked); + void lineXMinChanged(double value) {selrect.setLeft(value); checkLines();} + void lineXMaxChanged(double value) {selrect.setRight(value); checkLines();} + void lineYMinChanged(double value) {selrect.setBottom(value); checkLines();} + void lineYMaxChanged(double value) {selrect.setTop(value); checkLines();} + void on_buttonClose_clicked() {emit closeRequest(this);} + void on_buttonClear_clicked() {reset(); emit cleared();} + void on_buttonAutofit_clicked(); + void on_buttonConfigure_clicked(); + void on_buttonFullscreen_clicked() {fullscreen();} + void on_buttonSave_clicked() {saveImage();} + void on_checkGrid_toggled(bool checked) {grid = checked; update();} + void on_checkGuides_toggled(bool checked); + void on_checkExpandY_toggled(bool checked); + void on_checkExpandX_toggled(bool checked); + void on_checkBorderInputs_toggled(bool checked) {setBorderInputsVisible(checked);} + void on_checkLegend_toggled(bool checked) {setLegendVisible(checked);} + void on_checkPause_toggled(bool checked) {setPaused(checked);} + void enterFullscreen(); + void leaveFullscreen(); + +signals: + void graphicPaintEvent(QPainter * ); + void graphicMouseMoveEvent(QPointF point, int buttons); + void graphicMousePressEvent(QPointF point, int buttons); + void graphicMouseReleaseEvent(QPointF point, int buttons); + void graphicWheelEvent(QPointF point, int delta); + void closeRequest(QWidget * ); + void cleared(); + void visualRectChanged(); + +}; + +Q_DECLARE_METATYPE(Graphic::GraphicsData) + +Q_DECLARE_OPERATORS_FOR_FLAGS(Graphic::Buttons) + +//inline QDataStream & operator <<(QDataStream & s, const Graphic::GraphicsData & v) {s << v; return s;} +//inline QDataStream & operator >>(QDataStream & s, Graphic::GraphicsData & v) {s >> v; return s;} + +class __GraphicRegistrator__ { +public: + __GraphicRegistrator__() { + qRegisterMetaType("Graphic::GraphicsData"); + qRegisterMetaTypeStreamOperators("Graphic::GraphicsData"); + } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // GRAPHIC_H diff --git a/qad/graphic/graphic.ui b/qad/graphic/graphic.ui new file mode 100644 index 0000000..b86c538 --- /dev/null +++ b/qad/graphic/graphic.ui @@ -0,0 +1,485 @@ + + + Graphic + + + + 0 + 0 + 564 + 433 + + + + + 150 + 150 + + + + + 0 + + + 2 + + + + + + + -10 + 0 + 28 + 361 + + + + + 2 + + + + + Autofit + + + + :/icons/zoom-fit-best.png:/icons/zoom-fit-best.png + + + + 16 + 16 + + + + + + + + Grid + + + + :/icons/view-grid.png:/icons/view-grid.png + + + + 16 + 16 + + + + true + + + true + + + + + + + Cursor axis + + + + :/icons/edit-guides.png:/icons/edit-guides.png + + + + 16 + 16 + + + + true + + + + + + + Only expand Y + + + + :/icons/expand_s_y.png:/icons/expand_s_y.png + + + + 16 + 16 + + + + true + + + + + + + Only expand X + + + + :/icons/expand_s_x.png:/icons/expand_s_x.png + + + + 16 + 16 + + + + true + + + + + + + Fullscreen + + + + :/icons/view-fullscreen.png:/icons/view-fullscreen.png + + + + 16 + 16 + + + + + + + + Border inputs + + + + :/icons/border-line.png:/icons/border-line.png + + + + 16 + 16 + + + + true + + + true + + + + + + + Legend + + + + :/icons/legend.png:/icons/legend.png + + + + 16 + 16 + + + + true + + + false + + + + + + + Pause + + + + :/icons/media-playback-pause.png:/icons/media-playback-pause.png + + + + 16 + 16 + + + + true + + + + + + + Configure ... + + + + :/icons/configure.png:/icons/configure.png + + + + 16 + 16 + + + + + + + + Save image ... + + + + :/icons/document-save.png:/icons/document-save.png + + + + 16 + 16 + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 0 + 30 + + + + + + + + Clear + + + + :/icons/edit-clear.png:/icons/edit-clear.png + + + + 16 + 16 + + + + + + + + Close + + + + :/icons/dialog-close.png:/icons/dialog-close.png + + + + 16 + 16 + + + + + + + + Qt::Vertical + + + + 0 + 79 + + + + + + + + + + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Sunken + + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 2 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + + + true + + + + + + + true + + + + + + + + + + 0 + 0 + + + + + 0 + + + 2 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Cursor: ( ; ) + + + + + + + + 0 + 0 + + + + + 4 + + + 1 + + + + + + + + + UWidget + QWidget +
uwidget.h
+
+ + UGLWidget + QWidget +
uglwidget.h
+
+
+ + + + +
diff --git a/qad/graphic/graphic_conf.cpp b/qad/graphic/graphic_conf.cpp new file mode 100644 index 0000000..1fe4421 --- /dev/null +++ b/qad/graphic/graphic_conf.cpp @@ -0,0 +1,103 @@ +#include "graphic_conf.h" +#include "ui_graphic_conf.h" + + +GraphicConf::GraphicConf(QVector & graphics_, QWidget * parent): QDialog(parent), graphics(graphics_) { + ui = new Ui::GraphicConf(); + ui->setupUi(this); + QStringList styles; + styles << tr("NoPen") << tr("Solid") << tr("Dash") + << tr("Dot") << tr("Dash-Dot") << tr("Dash-Dot-Dot"); + ui->comboStyleGrid->setIconSize(QSize(60, 22)); + ui->comboStyleGraphic->setIconSize(QSize(60, 22)); + ui->cbGraphicNames->setIconSize(QSize(60, 22)); + for (int i = 0; i < 6; i++) { + QPixmap pix(60, 22); + pix.fill(); + QPainter p(&pix); + p.setPen(QPen(Qt::black, 1, (Qt::PenStyle)i)); + p.drawLine(0, pix.height() / 2, pix.width(), pix.height() / 2); + p.end(); + ui->comboStyleGraphic->addItem(QIcon(pix), styles[i]); + ui->comboStyleGrid->addItem(QIcon(pix), styles[i]); + } +} + + +void GraphicConf::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + return; + } + QDialog::changeEvent(e); +} + + +void GraphicConf::readParams() { + ui->cbGraphicNames->clear(); + for (int i = 0; i < graphicItems.size(); i++) + ui->cbGraphicNames->addItem(graphicItems[i].icon, graphicItems[i].name); +} + + +void GraphicConf::on_cbGraphicNames_currentIndexChanged(int i) { + if (i < 0) return; + if (graphicItems.isEmpty()) return; + ui->comboStyleGraphic->setCurrentIndex((int)graphics[i].pen.style()); + ui->colorGraphic->setColor(graphics[i].pen.color()); + ui->colorFill->setColor(graphics[i].fill_color); + ui->spinLineWidthGraphic->setValue(graphics[i].pen.widthF()); + ui->spinPointWidthGraphic->setValue(graphics[i].pointWidth); + ui->checkLines->setChecked(graphics[i].lines); + ui->checkPoints->setChecked(graphics[i].points); + ui->checkFill->setChecked(graphics[i].fill); +} + + +void GraphicConf::on_colorGraphic_colorChanged(const QColor & c) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].pen.setColor(c); +} + + +void GraphicConf::on_comboStyleGraphic_currentIndexChanged(int index) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].pen.setStyle((Qt::PenStyle)index); +} + + +void GraphicConf::on_spinLineWidthGraphic_valueChanged(double value) { + if (graphicItems.isEmpty()) return; + if (qRound(value) == value) graphics[ui->cbGraphicNames->currentIndex()].pen.setWidth(qRound(value)); + else graphics[ui->cbGraphicNames->currentIndex()].pen.setWidthF(value); +} + + +void GraphicConf::on_spinPointWidthGraphic_valueChanged(double value) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].pointWidth = value; +} + + +void GraphicConf::on_checkLines_toggled(bool on) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].lines = on; +} + + +void GraphicConf::on_checkPoints_toggled(bool on) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].points = on; +} + + +void GraphicConf::on_checkFill_toggled(bool on) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].fill = on; +} + + +void GraphicConf::on_colorFill_colorChanged(const QColor & color) { + if (graphicItems.isEmpty()) return; + graphics[ui->cbGraphicNames->currentIndex()].fill_color = color; +} diff --git a/qad/graphic/graphic_conf.h b/qad/graphic/graphic_conf.h new file mode 100644 index 0000000..6d926a6 --- /dev/null +++ b/qad/graphic/graphic_conf.h @@ -0,0 +1,90 @@ +#ifndef GRAPHIC_CONF_H +#define GRAPHIC_CONF_H + +#include +#include +#include +#include + + +namespace Ui { + class GraphicConf; +}; + + +struct GraphicType { + GraphicType(QString name_ = "y(x)", QColor color = Qt::red, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible_ = true) { + pen.setColor(color); + pen.setStyle(style); + lines = true; + points = false; + fill = false; + fill_color = Qt::yellow; + if (qRound(width) == width) pen.setWidth(qRound(width)); + else pen.setWidthF(width); + pen.setWidth(1); + pen.setCosmetic(true); + max_x = 0.; + name = name_; + visible = visible_; + pointWidth = 2.; + pb = new QCheckBox(name); + } + //~GraphicType() {delete pb;} + QString name; + QPolygonF polyline; + QPolygonF polyline_pause; + QPen pen; + QColor fill_color; + bool lines; + bool points; + bool fill; + double pointWidth; + double max_x; + double max_x_pause; + QCheckBox * pb; + QIcon icon; + bool visible; +}; + + +inline QDataStream & operator <<(QDataStream & s, const GraphicType & v) {s << v.name << v.pen << v.fill_color << v.lines << v.points << v.fill << v.pointWidth << v.visible; return s;} +inline QDataStream & operator >>(QDataStream & s, GraphicType & v) {s >> v.name >> v.pen >> v.fill_color >> v.lines >> v.points >> v.fill >> v.pointWidth >> v.visible; return s;} + + +class GraphicConf: public QDialog +{ + Q_OBJECT + friend class Graphic; +public: + explicit GraphicConf(QVector & graphics_, QWidget * parent = 0); + + struct GraphicItem { + QString name; + QIcon icon; + }; + + void readParams(); + + QVector & graphics; + QVector graphicItems; + +protected: + void changeEvent(QEvent * e); + + Ui::GraphicConf * ui; + +private slots: + void on_cbGraphicNames_currentIndexChanged(int index); + void on_colorGraphic_colorChanged(const QColor &); + void on_colorFill_colorChanged(const QColor &); + void on_comboStyleGraphic_currentIndexChanged(int index); + void on_spinLineWidthGraphic_valueChanged(double value); + void on_spinPointWidthGraphic_valueChanged(double value); + void on_checkLines_toggled(bool on); + void on_checkPoints_toggled(bool on); + void on_checkFill_toggled(bool on); + +}; + +#endif // GRAPHIC_CONF_H diff --git a/qad/graphic/graphic_conf.ui b/qad/graphic/graphic_conf.ui new file mode 100644 index 0000000..de95034 --- /dev/null +++ b/qad/graphic/graphic_conf.ui @@ -0,0 +1,678 @@ + + + GraphicConf + + + Qt::WindowModal + + + + 0 + 0 + 448 + 513 + + + + Graphic parameters + + + true + + + + 2 + + + 2 + + + + + Appearance + + + + 2 + + + 2 + + + + + + + Border inputs + + + + + + + Antialiasing + + + + + + + Status bar + + + + + + + OpenGL + + + + + + + Legend + + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + 0 + 0 + + + + Background color: + + + + + + + true + + + + + + + + 0 + 0 + + + + Text color: + + + + + + + true + + + + + + + + + + + + Graphics + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + + + + Color: + + + + + + + true + + + + + + + Style: + + + + + + + + + + Lines width: + + + true + + + + + + + 2 + + + 1.000000000000000 + + + + + + + Points width: + + + true + + + + + + + 2 + + + 1.000000000000000 + + + + + + + Fill: + + + true + + + + + + + true + + + + + + + + + + Grid + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 2 + + + + + Color: + + + + + + + true + + + + + + + Style: + + + + + + + + + + Width: + + + + + + + 2 + + + + + + + 3 + + + 0.001000000000000 + + + 9999999.000000000000000 + + + 50.000000000000000 + + + + + + + Step X: + + + + + + + Step Y: + + + + + + + 3 + + + 0.001000000000000 + + + 9999999.000000000000000 + + + 30.000000000000000 + + + + + + + Auto X + + + true + + + + + + + Auto Y + + + true + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Margins + + + + 2 + + + 2 + + + + + px + + + 100 + + + + + + + px + + + 100 + + + + + + + All: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + px + + + 100 + + + + + + + Right: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Left: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Bottom: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + px + + + 100 + + + + + + + Top: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + px + + + 100 + + + + + + + + + + + ColorButton + QPushButton +
colorbutton.h
+ + colorChanged(QColor) + +
+
+ + checkAAlias + checkOGL + colorBackground + colorText + colorGrid + comboStyleGrid + spinWidthGrid + cbGraphicNames + colorGraphic + comboStyleGraphic + checkLines + spinLineWidthGraphic + checkPoints + spinPointWidthGraphic + buttonBox + + + + + buttonBox + rejected() + GraphicConf + reject() + + + 255 + 641 + + + 245 + 207 + + + + + checkLines + toggled(bool) + spinLineWidthGraphic + setEnabled(bool) + + + 322 + 410 + + + 415 + 411 + + + + + checkPoints + toggled(bool) + spinPointWidthGraphic + setEnabled(bool) + + + 322 + 434 + + + 415 + 435 + + + + + buttonBox + accepted() + GraphicConf + accept() + + + 294 + 641 + + + 288 + 268 + + + + + checkFill + toggled(bool) + colorFill + setEnabled(bool) + + + 322 + 458 + + + 415 + 460 + + + + + spinMarginT_2 + valueChanged(int) + spinMarginT + setValue(int) + + + 259 + 221 + + + 249 + 191 + + + + + spinMarginT_2 + valueChanged(int) + spinMarginR + setValue(int) + + + 268 + 220 + + + 371 + 220 + + + + + spinMarginT_2 + valueChanged(int) + spinMarginB + setValue(int) + + + 233 + 230 + + + 234 + 252 + + + + + spinMarginT_2 + valueChanged(int) + spinMarginL + setValue(int) + + + 213 + 230 + + + 133 + 229 + + + + +
diff --git a/qad/graphic/lang/qad_graphic_ru.qm b/qad/graphic/lang/qad_graphic_ru.qm new file mode 100644 index 0000000..8ed99a4 Binary files /dev/null and b/qad/graphic/lang/qad_graphic_ru.qm differ diff --git a/qad/graphic/lang/qad_graphic_ru.ts b/qad/graphic/lang/qad_graphic_ru.ts new file mode 100644 index 0000000..bd68abf --- /dev/null +++ b/qad/graphic/lang/qad_graphic_ru.ts @@ -0,0 +1,351 @@ + + + + + Graphic + + + + Autofit + Автомасштаб + + + + + Grid + Сетка + + + + + Cursor axis + Плавающие оси + + + + + Only expand Y + Только расширять Y + + + + + Only expand X + Только расширять X + + + + + Fullscreen + Во весь экран + + + + + Border inputs + Граничные поля ввода + + + + + Legend + Легенда + + + + + Configure ... + Настроить ... + + + + + Save image ... + Сохранить изображение ... + + + + + Clear + Очистить + + + + + Close + Закрыть + + + + + Cursor: ( ; ) + Курсор: ( ; ) + + + + + Cursor: + Курсор: + + + + Selection + Выделение + + + + Size + Размер + + + + + Range + Диапазон + + + + + Length + Длина + + + + + Cursor + Курсор + + + + Save Image + Сохранить изображение + + + + y(x) + + + + + Check all + Выбрать все + + + + GraphicConf + + + + Graphic parameters + Параметры графика + + + + + Appearance + Внешний вид + + + + + Border inputs + Граничные поля ввода + + + + + Antialiasing + Сглаживание + + + + + Status bar + Панель статуса + + + + + OpenGL + + + + + + Legend + Легенда + + + + + Background color: + Цвет фона: + + + + + Text color: + Цвет текста: + + + + + Graphics + Графики + + + + + + + Color: + Цвет: + + + + + + + Style: + Стиль: + + + + + Lines width: + Толщина линий: + + + + + Points width: + Толщина точек: + + + + + Fill: + Заливка: + + + + + Grid + Сетка + + + + + Width: + Толщина: + + + + + Step X: + Шаг X: + + + + + Step Y: + Шаг Y: + + + + + Auto X + Авто X + + + + + Auto Y + Авто Y + + + Auto step + Автоматический шаг + + + + + Margins + Поля + + + + + + + + + + + + + px + пикс + + + + + All: + Все: + + + + + Right: + Правое: + + + + + Left: + Левое: + + + + + Bottom: + Нижнее: + + + + + Top: + Верхнее: + + + + NoPen + НетЛинии + + + + Solid + Сплошная + + + + Dash + Штриховая + + + + Dot + Пунктирная + + + + Dash-Dot + ШтрихПунктирная + + + + Dash-Dot-Dot + ШтрихПунктирПунктирная + + + diff --git a/qad/graphic/plugin/CMakeLists.txt b/qad/graphic/plugin/CMakeLists.txt new file mode 100644 index 0000000..61032be --- /dev/null +++ b/qad/graphic/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(graphic "") diff --git a/qad/graphic/plugin/graphicplugin.cpp b/qad/graphic/plugin/graphicplugin.cpp new file mode 100644 index 0000000..c4ff495 --- /dev/null +++ b/qad/graphic/plugin/graphicplugin.cpp @@ -0,0 +1,69 @@ +#include "graphic.h" +#include "graphicplugin.h" +#include + + +GraphicPlugin::GraphicPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void GraphicPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool GraphicPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * GraphicPlugin::createWidget(QWidget * parent) { + return new Graphic(parent); +} + + +QString GraphicPlugin::name() const { + return QLatin1String("Graphic"); +} + + +QString GraphicPlugin::group() const { + return QLatin1String("Display Widgets"); +} + + +QIcon GraphicPlugin::icon() const { + return QIcon(":/icons/graphic.png"); +} + + +QString GraphicPlugin::toolTip() const { + return QLatin1String("");//QLatin1String("Widget for display any math graphics with grid and navigation"); +} + + +QString GraphicPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool GraphicPlugin::isContainer() const { + return false; +} + + +QString GraphicPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString GraphicPlugin::includeFile() const { + return QLatin1String("graphic.h"); +} + diff --git a/qad/graphic/plugin/graphicplugin.h b/qad/graphic/plugin/graphicplugin.h new file mode 100644 index 0000000..9d1bc2e --- /dev/null +++ b/qad/graphic/plugin/graphicplugin.h @@ -0,0 +1,31 @@ +#ifndef GRAPHICPLUGIN_H +#define GRAPHICPLUGIN_H + +#include + +class GraphicPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + GraphicPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif diff --git a/qad/graphic/plugin/qad_graphic.cpp b/qad/graphic/plugin/qad_graphic.cpp new file mode 100644 index 0000000..391255c --- /dev/null +++ b/qad/graphic/plugin/qad_graphic.cpp @@ -0,0 +1,14 @@ +#include "graphicplugin.h" +#include "qad_graphic.h" + +QADGraphic::QADGraphic(QObject * parent): QObject(parent) +{ + m_widgets.append(new GraphicPlugin(this)); +} + + +QList QADGraphic::customWidgets() const { + return m_widgets; +} + +Q_EXPORT_PLUGIN2(qad_graphic_plugin, QADGraphic) diff --git a/qad/graphic/plugin/qad_graphic.h b/qad/graphic/plugin/qad_graphic.h new file mode 100644 index 0000000..0bda0bb --- /dev/null +++ b/qad/graphic/plugin/qad_graphic.h @@ -0,0 +1,21 @@ +#ifndef QAD_GRAPHIC_H +#define QAD_GRAPHIC_H + +#include +#include + +class QADGraphic: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit QADGraphic(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; + +}; + +#endif // QAD_GRAPHIC_H diff --git a/qad/graphic/qad_graphic.qrc b/qad/graphic/qad_graphic.qrc new file mode 100644 index 0000000..4deb98b --- /dev/null +++ b/qad/graphic/qad_graphic.qrc @@ -0,0 +1,32 @@ + + + lang/qad_graphic_ru.qm + ../icons/media-playback-pause.png + ../icons/dialog-close.png + ../icons/edit-clear.png + ../icons/edit-guides.png + ../icons/view-grid.png + ../icons/zoom-fit-best.png + ../icons/configure.png + ../icons/document-save.png + ../icons/edit-clear-locationbar-rtl.png + ../icons/edit-find.png + ../icons/list-add.png + ../icons/edit-delete.png + ../icons/item.png + ../icons/node-add.png + ../icons/node.png + ../icons/edit-copy.png + ../icons/edit-paste.png + ../icons/expand_s_x.png + ../icons/expand_s_y.png + ../icons/expand_x.png + ../icons/expand_y.png + ../icons/border-line.png + ../icons/legend.png + ../icons/graphic.png + ../icons/view-fullscreen.png + ../icons/pause-back.png + ../icons/pause-front.png + + diff --git a/qad/graphic/uglwidget.h b/qad/graphic/uglwidget.h new file mode 100644 index 0000000..c3391eb --- /dev/null +++ b/qad/graphic/uglwidget.h @@ -0,0 +1,48 @@ +#ifndef UGLWIDGET_H +#define UGLWIDGET_H + +#include +#ifndef GL_MULTISAMPLE +#define GL_MULTISAMPLE 0x809D +#endif + + +class UGLWidget: public QGLWidget +{ + Q_OBJECT +public: + UGLWidget(QWidget * parent = 0): QGLWidget(QGLFormat(QGL::DoubleBuffer | QGL::AlphaChannel | QGL::DirectRendering | QGL::SampleBuffers), parent) {}; + UGLWidget(QGLContext * context, QWidget * parent = 0): QGLWidget(context, parent) {}; + +signals: + void closeEvent(QCloseEvent * e); + void dragEnterEvent(QDragEnterEvent * e); + void dragLeaveEvent(QDragLeaveEvent * e); + void dragMoveEvent(QDragMoveEvent * e); + void dropEvent(QDropEvent * e); + void enterEvent(QEvent * e); + void hideEvent(QHideEvent * e); + void keyPressEvent(QKeyEvent * e); + void keyReleaseEvent(QKeyEvent * e); + void leaveEvent(QEvent * e); + void mouseDoubleClickEvent(QMouseEvent * e); + void mouseMoveEvent(QMouseEvent * e); + void mousePressEvent(QMouseEvent * e); + void mouseReleaseEvent(QMouseEvent * e); + void moveEvent(QMoveEvent * e); + void resizeEvent(QResizeEvent * e); + void showEvent(QShowEvent * e); + void wheelEvent(QWheelEvent * e); + void paintEvent(QPaintEvent * e); + void glDraw(); + void glInit(); + void initializeGL(); + void initializeOverlayGL(); + void paintGL(); + void paintOverlayGL(); + void resizeGL(int width, int height); + void resizeOverlayGL(int width, int height); + +}; + +#endif diff --git a/qad/graphic/uwidget.h b/qad/graphic/uwidget.h new file mode 100644 index 0000000..1d7f3bc --- /dev/null +++ b/qad/graphic/uwidget.h @@ -0,0 +1,52 @@ +#ifndef UWIDGET_H +#define UWIDGET_H + +#include +#include +#include +#include +#include + + +class UWidget: public QWidget +{ + Q_OBJECT +public: + UWidget(QWidget * parent = 0): QWidget(parent) {}; + +private: + virtual bool event(QEvent * e) { + if (e->type() != QEvent::Paint) return QWidget::event(e); + e->accept(); + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + emit paintEvent((QPaintEvent * )e); + return true; + } + +signals: + void closeEvent(QCloseEvent * e); + void dragEnterEvent(QDragEnterEvent * e); + void dragLeaveEvent(QDragLeaveEvent * e); + void dragMoveEvent(QDragMoveEvent * e); + void dropEvent(QDropEvent * e); + void enterEvent(QEvent * e); + void hideEvent(QHideEvent * e); + void keyPressEvent(QKeyEvent * e); + void keyReleaseEvent(QKeyEvent * e); + void leaveEvent(QEvent * e); + void mouseDoubleClickEvent(QMouseEvent * e); + void mouseMoveEvent(QMouseEvent * e); + void mousePressEvent(QMouseEvent * e); + void mouseReleaseEvent(QMouseEvent * e); + void moveEvent(QMoveEvent * e); + void resizeEvent(QResizeEvent * e); + void showEvent(QShowEvent * e); + void wheelEvent(QWheelEvent * e); + void paintEvent(QPaintEvent * e); + +}; + +#endif diff --git a/qad/icons/align-bottom-center.png b/qad/icons/align-bottom-center.png new file mode 100644 index 0000000..8678b5d Binary files /dev/null and b/qad/icons/align-bottom-center.png differ diff --git a/qad/icons/align-bottom-left.png b/qad/icons/align-bottom-left.png new file mode 100644 index 0000000..b25edc0 Binary files /dev/null and b/qad/icons/align-bottom-left.png differ diff --git a/qad/icons/align-bottom-right.png b/qad/icons/align-bottom-right.png new file mode 100644 index 0000000..dea560e Binary files /dev/null and b/qad/icons/align-bottom-right.png differ diff --git a/qad/icons/align-center-center.png b/qad/icons/align-center-center.png new file mode 100644 index 0000000..0054ee3 Binary files /dev/null and b/qad/icons/align-center-center.png differ diff --git a/qad/icons/align-center-left.png b/qad/icons/align-center-left.png new file mode 100644 index 0000000..ccc2e95 Binary files /dev/null and b/qad/icons/align-center-left.png differ diff --git a/qad/icons/align-center-right.png b/qad/icons/align-center-right.png new file mode 100644 index 0000000..0e9335c Binary files /dev/null and b/qad/icons/align-center-right.png differ diff --git a/qad/icons/align-hor.png b/qad/icons/align-hor.png new file mode 100644 index 0000000..a477a99 Binary files /dev/null and b/qad/icons/align-hor.png differ diff --git a/qad/icons/align-top-center.png b/qad/icons/align-top-center.png new file mode 100644 index 0000000..5dc912f Binary files /dev/null and b/qad/icons/align-top-center.png differ diff --git a/qad/icons/align-top-left.png b/qad/icons/align-top-left.png new file mode 100644 index 0000000..38b22a1 Binary files /dev/null and b/qad/icons/align-top-left.png differ diff --git a/qad/icons/align-top-right.png b/qad/icons/align-top-right.png new file mode 100644 index 0000000..2232cac Binary files /dev/null and b/qad/icons/align-top-right.png differ diff --git a/qad/icons/align-ver.png b/qad/icons/align-ver.png new file mode 100644 index 0000000..75ad0c1 Binary files /dev/null and b/qad/icons/align-ver.png differ diff --git a/qad/icons/alpha.png b/qad/icons/alpha.png new file mode 100644 index 0000000..5435669 Binary files /dev/null and b/qad/icons/alpha.png differ diff --git a/qad/icons/archive-extract.png b/qad/icons/archive-extract.png new file mode 100644 index 0000000..aa7b1fa Binary files /dev/null and b/qad/icons/archive-extract.png differ diff --git a/qad/icons/archive-insert-directory.png b/qad/icons/archive-insert-directory.png new file mode 100644 index 0000000..0672205 Binary files /dev/null and b/qad/icons/archive-insert-directory.png differ diff --git a/qad/icons/archive-insert.png b/qad/icons/archive-insert.png new file mode 100644 index 0000000..193c25c Binary files /dev/null and b/qad/icons/archive-insert.png differ diff --git a/qad/icons/arrow-down.png b/qad/icons/arrow-down.png new file mode 100644 index 0000000..03f2014 Binary files /dev/null and b/qad/icons/arrow-down.png differ diff --git a/qad/icons/arrow-up.png b/qad/icons/arrow-up.png new file mode 100644 index 0000000..5e42321 Binary files /dev/null and b/qad/icons/arrow-up.png differ diff --git a/qad/icons/axis_x.png b/qad/icons/axis_x.png new file mode 100644 index 0000000..321899c Binary files /dev/null and b/qad/icons/axis_x.png differ diff --git a/qad/icons/axis_y.png b/qad/icons/axis_y.png new file mode 100644 index 0000000..7d4d9ec Binary files /dev/null and b/qad/icons/axis_y.png differ diff --git a/qad/icons/blockview.png b/qad/icons/blockview.png new file mode 100644 index 0000000..6e25090 Binary files /dev/null and b/qad/icons/blockview.png differ diff --git a/qad/icons/border-line.png b/qad/icons/border-line.png new file mode 100644 index 0000000..dbae386 Binary files /dev/null and b/qad/icons/border-line.png differ diff --git a/touch_widgets/icons/button.png b/qad/icons/button.png similarity index 100% rename from touch_widgets/icons/button.png rename to qad/icons/button.png diff --git a/qad/icons/case-sensitive.png b/qad/icons/case-sensitive.png new file mode 100644 index 0000000..39c5c5a Binary files /dev/null and b/qad/icons/case-sensitive.png differ diff --git a/qad/icons/chardialog.png b/qad/icons/chardialog.png new file mode 100644 index 0000000..5c39db0 Binary files /dev/null and b/qad/icons/chardialog.png differ diff --git a/qad/icons/checkbox-unchecked.png b/qad/icons/checkbox-unchecked.png new file mode 100644 index 0000000..01a7307 Binary files /dev/null and b/qad/icons/checkbox-unchecked.png differ diff --git a/qad/icons/checkbox.png b/qad/icons/checkbox.png new file mode 100644 index 0000000..1c311e2 Binary files /dev/null and b/qad/icons/checkbox.png differ diff --git a/qad/icons/clear-history.png b/qad/icons/clear-history.png new file mode 100644 index 0000000..805631f Binary files /dev/null and b/qad/icons/clear-history.png differ diff --git a/qad/icons/clineedit.png b/qad/icons/clineedit.png new file mode 100644 index 0000000..b2d95ee Binary files /dev/null and b/qad/icons/clineedit.png differ diff --git a/qad/icons/code-error.png b/qad/icons/code-error.png new file mode 100644 index 0000000..5b4c488 Binary files /dev/null and b/qad/icons/code-error.png differ diff --git a/qad/icons/code-parents.png b/qad/icons/code-parents.png new file mode 100644 index 0000000..7c14d40 Binary files /dev/null and b/qad/icons/code-parents.png differ diff --git a/qad/icons/code-struct.png b/qad/icons/code-struct.png new file mode 100644 index 0000000..61544a8 Binary files /dev/null and b/qad/icons/code-struct.png differ diff --git a/qad/icons/code-union.png b/qad/icons/code-union.png new file mode 100644 index 0000000..2f4567a Binary files /dev/null and b/qad/icons/code-union.png differ diff --git a/qad/icons/code-variable.png b/qad/icons/code-variable.png new file mode 100644 index 0000000..d202a74 Binary files /dev/null and b/qad/icons/code-variable.png differ diff --git a/qad/icons/code-word.png b/qad/icons/code-word.png new file mode 100644 index 0000000..e61f08f Binary files /dev/null and b/qad/icons/code-word.png differ diff --git a/qad/icons/colorbutton.png b/qad/icons/colorbutton.png new file mode 100644 index 0000000..7df718d Binary files /dev/null and b/qad/icons/colorbutton.png differ diff --git a/qad/icons/configure.png b/qad/icons/configure.png new file mode 100644 index 0000000..5ce478b Binary files /dev/null and b/qad/icons/configure.png differ diff --git a/qad/icons/database.png b/qad/icons/database.png new file mode 100644 index 0000000..3041814 Binary files /dev/null and b/qad/icons/database.png differ diff --git a/qad/icons/dialog-close.png b/qad/icons/dialog-close.png new file mode 100644 index 0000000..2c2f99e Binary files /dev/null and b/qad/icons/dialog-close.png differ diff --git a/qad/icons/dialog-ok-apply.png b/qad/icons/dialog-ok-apply.png new file mode 100644 index 0000000..b86f473 Binary files /dev/null and b/qad/icons/dialog-ok-apply.png differ diff --git a/qad/icons/document-edit-.png b/qad/icons/document-edit-.png new file mode 100644 index 0000000..e8fe097 Binary files /dev/null and b/qad/icons/document-edit-.png differ diff --git a/qad/icons/document-edit.png b/qad/icons/document-edit.png new file mode 100644 index 0000000..84e345d Binary files /dev/null and b/qad/icons/document-edit.png differ diff --git a/qad/icons/document-new.png b/qad/icons/document-new.png new file mode 100644 index 0000000..8431237 Binary files /dev/null and b/qad/icons/document-new.png differ diff --git a/qad/icons/document-open.png b/qad/icons/document-open.png new file mode 100644 index 0000000..3432ed2 Binary files /dev/null and b/qad/icons/document-open.png differ diff --git a/qad/icons/document-open_16.png b/qad/icons/document-open_16.png new file mode 100644 index 0000000..17076a3 Binary files /dev/null and b/qad/icons/document-open_16.png differ diff --git a/qad/icons/document-print.png b/qad/icons/document-print.png new file mode 100644 index 0000000..8eb1c67 Binary files /dev/null and b/qad/icons/document-print.png differ diff --git a/qad/icons/document-save.png b/qad/icons/document-save.png new file mode 100644 index 0000000..cc380a0 Binary files /dev/null and b/qad/icons/document-save.png differ diff --git a/qad/icons/draw-ellipse.png b/qad/icons/draw-ellipse.png new file mode 100644 index 0000000..6aa51ef Binary files /dev/null and b/qad/icons/draw-ellipse.png differ diff --git a/qad/icons/draw-line.png b/qad/icons/draw-line.png new file mode 100644 index 0000000..fff6f25 Binary files /dev/null and b/qad/icons/draw-line.png differ diff --git a/qad/icons/draw-rectangle.png b/qad/icons/draw-rectangle.png new file mode 100644 index 0000000..2e0e1ca Binary files /dev/null and b/qad/icons/draw-rectangle.png differ diff --git a/qad/icons/draw-text.png b/qad/icons/draw-text.png new file mode 100644 index 0000000..b653b25 Binary files /dev/null and b/qad/icons/draw-text.png differ diff --git a/qad/icons/ecombobox.png b/qad/icons/ecombobox.png new file mode 100644 index 0000000..f0a2d17 Binary files /dev/null and b/qad/icons/ecombobox.png differ diff --git a/qad/icons/edit-clear-locationbar-rtl.png b/qad/icons/edit-clear-locationbar-rtl.png new file mode 100644 index 0000000..6c4b83b Binary files /dev/null and b/qad/icons/edit-clear-locationbar-rtl.png differ diff --git a/qad/icons/edit-clear.png b/qad/icons/edit-clear.png new file mode 100644 index 0000000..cee7af6 Binary files /dev/null and b/qad/icons/edit-clear.png differ diff --git a/qad/icons/edit-copy.png b/qad/icons/edit-copy.png new file mode 100644 index 0000000..5cdeb5f Binary files /dev/null and b/qad/icons/edit-copy.png differ diff --git a/qad/icons/edit-delete.png b/qad/icons/edit-delete.png new file mode 100644 index 0000000..49fd217 Binary files /dev/null and b/qad/icons/edit-delete.png differ diff --git a/qad/icons/edit-find.png b/qad/icons/edit-find.png new file mode 100644 index 0000000..9a462c0 Binary files /dev/null and b/qad/icons/edit-find.png differ diff --git a/qad/icons/edit-guides.png b/qad/icons/edit-guides.png new file mode 100644 index 0000000..d264839 Binary files /dev/null and b/qad/icons/edit-guides.png differ diff --git a/qad/icons/edit-paste.png b/qad/icons/edit-paste.png new file mode 100644 index 0000000..a4e0a02 Binary files /dev/null and b/qad/icons/edit-paste.png differ diff --git a/qad/icons/edit-table-insert-row-below.png b/qad/icons/edit-table-insert-row-below.png new file mode 100644 index 0000000..a194a68 Binary files /dev/null and b/qad/icons/edit-table-insert-row-below.png differ diff --git a/qad/icons/edockwidget.png b/qad/icons/edockwidget.png new file mode 100644 index 0000000..9eee04f Binary files /dev/null and b/qad/icons/edockwidget.png differ diff --git a/qad/icons/etabwidget.png b/qad/icons/etabwidget.png new file mode 100644 index 0000000..4fe88c6 Binary files /dev/null and b/qad/icons/etabwidget.png differ diff --git a/qad/icons/expand_s_x.png b/qad/icons/expand_s_x.png new file mode 100644 index 0000000..b66cb40 Binary files /dev/null and b/qad/icons/expand_s_x.png differ diff --git a/qad/icons/expand_s_y.png b/qad/icons/expand_s_y.png new file mode 100644 index 0000000..c2e8f78 Binary files /dev/null and b/qad/icons/expand_s_y.png differ diff --git a/qad/icons/expand_x.png b/qad/icons/expand_x.png new file mode 100644 index 0000000..217e3ea Binary files /dev/null and b/qad/icons/expand_x.png differ diff --git a/qad/icons/expand_y.png b/qad/icons/expand_y.png new file mode 100644 index 0000000..fedf936 Binary files /dev/null and b/qad/icons/expand_y.png differ diff --git a/qad/icons/f1.png b/qad/icons/f1.png new file mode 100644 index 0000000..fc3aeae Binary files /dev/null and b/qad/icons/f1.png differ diff --git a/qad/icons/format-fill-color.png b/qad/icons/format-fill-color.png new file mode 100644 index 0000000..ba56d74 Binary files /dev/null and b/qad/icons/format-fill-color.png differ diff --git a/qad/icons/format-stroke-color.png b/qad/icons/format-stroke-color.png new file mode 100644 index 0000000..b174057 Binary files /dev/null and b/qad/icons/format-stroke-color.png differ diff --git a/qad/icons/format-text-subscript.png b/qad/icons/format-text-subscript.png new file mode 100644 index 0000000..206b147 Binary files /dev/null and b/qad/icons/format-text-subscript.png differ diff --git a/qad/icons/games-solve.png b/qad/icons/games-solve.png new file mode 100644 index 0000000..1fcac96 Binary files /dev/null and b/qad/icons/games-solve.png differ diff --git a/qad/icons/go-next.png b/qad/icons/go-next.png new file mode 100644 index 0000000..aa7cbb9 Binary files /dev/null and b/qad/icons/go-next.png differ diff --git a/qad/icons/go-previous.png b/qad/icons/go-previous.png new file mode 100644 index 0000000..8230340 Binary files /dev/null and b/qad/icons/go-previous.png differ diff --git a/qad/icons/graphic.png b/qad/icons/graphic.png new file mode 100644 index 0000000..677fa54 Binary files /dev/null and b/qad/icons/graphic.png differ diff --git a/qad/icons/graphics.png b/qad/icons/graphics.png new file mode 100644 index 0000000..64abcb5 Binary files /dev/null and b/qad/icons/graphics.png differ diff --git a/qad/icons/historyview.png b/qad/icons/historyview.png new file mode 100644 index 0000000..cf3ede9 Binary files /dev/null and b/qad/icons/historyview.png differ diff --git a/touch_widgets/icons/icons.xcf b/qad/icons/icons.xcf similarity index 100% rename from touch_widgets/icons/icons.xcf rename to qad/icons/icons.xcf diff --git a/qad/icons/item-add.png b/qad/icons/item-add.png new file mode 100644 index 0000000..8a422c7 Binary files /dev/null and b/qad/icons/item-add.png differ diff --git a/qad/icons/item.png b/qad/icons/item.png new file mode 100644 index 0000000..50bfddb Binary files /dev/null and b/qad/icons/item.png differ diff --git a/qad/icons/lastmoves.png b/qad/icons/lastmoves.png new file mode 100644 index 0000000..4454bca Binary files /dev/null and b/qad/icons/lastmoves.png differ diff --git a/qad/icons/layer-visible-off.png b/qad/icons/layer-visible-off.png new file mode 100644 index 0000000..03ca47d Binary files /dev/null and b/qad/icons/layer-visible-off.png differ diff --git a/qad/icons/layer-visible-on.png b/qad/icons/layer-visible-on.png new file mode 100644 index 0000000..11fad5e Binary files /dev/null and b/qad/icons/layer-visible-on.png differ diff --git a/qad/icons/led_3.png b/qad/icons/led_3.png new file mode 100644 index 0000000..604c241 Binary files /dev/null and b/qad/icons/led_3.png differ diff --git a/qad/icons/led_off.png b/qad/icons/led_off.png new file mode 100644 index 0000000..fe60f36 Binary files /dev/null and b/qad/icons/led_off.png differ diff --git a/qad/icons/led_on.png b/qad/icons/led_on.png new file mode 100644 index 0000000..946ba73 Binary files /dev/null and b/qad/icons/led_on.png differ diff --git a/qad/icons/legend.png b/qad/icons/legend.png new file mode 100644 index 0000000..02ca274 Binary files /dev/null and b/qad/icons/legend.png differ diff --git a/qad/icons/list-add.png b/qad/icons/list-add.png new file mode 100644 index 0000000..af5b56e Binary files /dev/null and b/qad/icons/list-add.png differ diff --git a/qad/icons/list-remove.png b/qad/icons/list-remove.png new file mode 100644 index 0000000..5a4d15b Binary files /dev/null and b/qad/icons/list-remove.png differ diff --git a/qad/icons/log_parser.png b/qad/icons/log_parser.png new file mode 100644 index 0000000..cf0ca98 Binary files /dev/null and b/qad/icons/log_parser.png differ diff --git a/qad/icons/mail.png b/qad/icons/mail.png new file mode 100644 index 0000000..81adbf9 Binary files /dev/null and b/qad/icons/mail.png differ diff --git a/qad/icons/media-playback-pause.png b/qad/icons/media-playback-pause.png new file mode 100644 index 0000000..d133bdc Binary files /dev/null and b/qad/icons/media-playback-pause.png differ diff --git a/qad/icons/media-playback-stop.png b/qad/icons/media-playback-stop.png new file mode 100644 index 0000000..4ecbdf6 Binary files /dev/null and b/qad/icons/media-playback-stop.png differ diff --git a/qad/icons/media-record.png b/qad/icons/media-record.png new file mode 100644 index 0000000..73688e8 Binary files /dev/null and b/qad/icons/media-record.png differ diff --git a/qad/icons/node-add.png b/qad/icons/node-add.png new file mode 100644 index 0000000..80b5c61 Binary files /dev/null and b/qad/icons/node-add.png differ diff --git a/qad/icons/node.png b/qad/icons/node.png new file mode 100644 index 0000000..fc8194e Binary files /dev/null and b/qad/icons/node.png differ diff --git a/qad/icons/pause-back.png b/qad/icons/pause-back.png new file mode 100644 index 0000000..d3407e2 Binary files /dev/null and b/qad/icons/pause-back.png differ diff --git a/qad/icons/pause-front.png b/qad/icons/pause-front.png new file mode 100644 index 0000000..448bb6a Binary files /dev/null and b/qad/icons/pause-front.png differ diff --git a/qad/icons/qcodeedit.png b/qad/icons/qcodeedit.png new file mode 100644 index 0000000..4299440 Binary files /dev/null and b/qad/icons/qcodeedit.png differ diff --git a/qad/icons/qpiconsole.png b/qad/icons/qpiconsole.png new file mode 100644 index 0000000..9555ab8 Binary files /dev/null and b/qad/icons/qpiconsole.png differ diff --git a/qad/icons/quickopen.png b/qad/icons/quickopen.png new file mode 100644 index 0000000..22927ed Binary files /dev/null and b/qad/icons/quickopen.png differ diff --git a/qad/icons/qvariantedit.png b/qad/icons/qvariantedit.png new file mode 100644 index 0000000..9376a9f Binary files /dev/null and b/qad/icons/qvariantedit.png differ diff --git a/qad/icons/run-build.png b/qad/icons/run-build.png new file mode 100644 index 0000000..d5fa88f Binary files /dev/null and b/qad/icons/run-build.png differ diff --git a/qad/icons/spinslider.png b/qad/icons/spinslider.png new file mode 100644 index 0000000..3a5e639 Binary files /dev/null and b/qad/icons/spinslider.png differ diff --git a/qad/icons/sql_table.png b/qad/icons/sql_table.png new file mode 100644 index 0000000..9da26eb Binary files /dev/null and b/qad/icons/sql_table.png differ diff --git a/qad/icons/tools-wizard.png b/qad/icons/tools-wizard.png new file mode 100644 index 0000000..f67fb4c Binary files /dev/null and b/qad/icons/tools-wizard.png differ diff --git a/touch_widgets/icons/touchbuttframe.png b/qad/icons/touchbuttframe.png similarity index 100% rename from touch_widgets/icons/touchbuttframe.png rename to qad/icons/touchbuttframe.png diff --git a/touch_widgets/icons/touchbutton.png b/qad/icons/touchbutton.png similarity index 100% rename from touch_widgets/icons/touchbutton.png rename to qad/icons/touchbutton.png diff --git a/touch_widgets/icons/touchslider.png b/qad/icons/touchslider.png similarity index 100% rename from touch_widgets/icons/touchslider.png rename to qad/icons/touchslider.png diff --git a/qad/icons/transform-move.png b/qad/icons/transform-move.png new file mode 100644 index 0000000..0bd8d04 Binary files /dev/null and b/qad/icons/transform-move.png differ diff --git a/qad/icons/variable-add.png b/qad/icons/variable-add.png new file mode 100644 index 0000000..0a551b1 Binary files /dev/null and b/qad/icons/variable-add.png differ diff --git a/qad/icons/variable-copy.png b/qad/icons/variable-copy.png new file mode 100644 index 0000000..42d91c3 Binary files /dev/null and b/qad/icons/variable-copy.png differ diff --git a/qad/icons/variable-edit.png b/qad/icons/variable-edit.png new file mode 100644 index 0000000..420ace3 Binary files /dev/null and b/qad/icons/variable-edit.png differ diff --git a/qad/icons/variable-remove.png b/qad/icons/variable-remove.png new file mode 100644 index 0000000..0686e7c Binary files /dev/null and b/qad/icons/variable-remove.png differ diff --git a/qad/icons/view-fullscreen.png b/qad/icons/view-fullscreen.png new file mode 100644 index 0000000..75f8a59 Binary files /dev/null and b/qad/icons/view-fullscreen.png differ diff --git a/qad/icons/view-grid.png b/qad/icons/view-grid.png new file mode 100644 index 0000000..0f1d70c Binary files /dev/null and b/qad/icons/view-grid.png differ diff --git a/qad/icons/view-preview.png b/qad/icons/view-preview.png new file mode 100644 index 0000000..92d802a Binary files /dev/null and b/qad/icons/view-preview.png differ diff --git a/qad/icons/view-refresh.png b/qad/icons/view-refresh.png new file mode 100644 index 0000000..45b5535 Binary files /dev/null and b/qad/icons/view-refresh.png differ diff --git a/qad/icons/z-bottom.png b/qad/icons/z-bottom.png new file mode 100644 index 0000000..89c3eff Binary files /dev/null and b/qad/icons/z-bottom.png differ diff --git a/qad/icons/z-down.png b/qad/icons/z-down.png new file mode 100644 index 0000000..abe0017 Binary files /dev/null and b/qad/icons/z-down.png differ diff --git a/qad/icons/z-top.png b/qad/icons/z-top.png new file mode 100644 index 0000000..309b458 Binary files /dev/null and b/qad/icons/z-top.png differ diff --git a/qad/icons/z-up.png b/qad/icons/z-up.png new file mode 100644 index 0000000..c5b574e Binary files /dev/null and b/qad/icons/z-up.png differ diff --git a/qad/icons/zoom-fit-best.png b/qad/icons/zoom-fit-best.png new file mode 100644 index 0000000..07cfc98 Binary files /dev/null and b/qad/icons/zoom-fit-best.png differ diff --git a/qad/icons/zoom-in.png b/qad/icons/zoom-in.png new file mode 100644 index 0000000..8393e28 Binary files /dev/null and b/qad/icons/zoom-in.png differ diff --git a/qad/icons/zoom-out.png b/qad/icons/zoom-out.png new file mode 100644 index 0000000..f66575e Binary files /dev/null and b/qad/icons/zoom-out.png differ diff --git a/qad/icons/zoom-range.png b/qad/icons/zoom-range.png new file mode 100644 index 0000000..c052512 Binary files /dev/null and b/qad/icons/zoom-range.png differ diff --git a/qad/icons/zoom-rect.png b/qad/icons/zoom-rect.png new file mode 100644 index 0000000..da44fd5 Binary files /dev/null and b/qad/icons/zoom-rect.png differ diff --git a/qad/sql_table/CMakeLists.txt b/qad/sql_table/CMakeLists.txt new file mode 100644 index 0000000..9789a1c --- /dev/null +++ b/qad/sql_table/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTSQL_LIBRARY} qad_widgets qad_utils) +qad_project(sql_table "${LIBS}") diff --git a/qad/sql_table/lang/qad_sql_table_ru.qm b/qad/sql_table/lang/qad_sql_table_ru.qm new file mode 100644 index 0000000..cf36ae5 Binary files /dev/null and b/qad/sql_table/lang/qad_sql_table_ru.qm differ diff --git a/qad/sql_table/lang/qad_sql_table_ru.ts b/qad/sql_table/lang/qad_sql_table_ru.ts new file mode 100644 index 0000000..6a96bff --- /dev/null +++ b/qad/sql_table/lang/qad_sql_table_ru.ts @@ -0,0 +1,58 @@ + + + + + SQLFilterEdit + + ≈ + + + + ≠ + + + + ≥ + + + + ≤ + + + + + SQLTableWidget + + Table doesn`t exists! + Таблица не существует! + + + Add record + Добавить запись + + + Configure filters + Настроить фильтры + + + Clear + Очистить + + + Operator AND + Операция И + + + Operator OR + Операция ИЛИ + + + Remove selected + Удалить выделенные + + + Table "%1" doesn`t exists! + Таблица "%1" не существует! + + + diff --git a/qad/sql_table/plugin/CMakeLists.txt b/qad/sql_table/plugin/CMakeLists.txt new file mode 100644 index 0000000..65de9df --- /dev/null +++ b/qad/sql_table/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(sql_table "") diff --git a/qad/sql_table/plugin/qad_sql_table.cpp b/qad/sql_table/plugin/qad_sql_table.cpp new file mode 100644 index 0000000..1d4704e --- /dev/null +++ b/qad/sql_table/plugin/qad_sql_table.cpp @@ -0,0 +1,17 @@ +#include "qad_sql_table.h" +#include "sql_table_plugin.h" +#include "sql_record_plugin.h" + + +QADSQLTable::QADSQLTable(QObject * parent): QObject(parent) { + m_widgets.append(new SQLTablePlugin(this)); + m_widgets.append(new SQLRecordPlugin(this)); +} + + +QList QADSQLTable::customWidgets() const { + return m_widgets; +} + + +Q_EXPORT_PLUGIN2(qad_sql_table_plugin, QADSQLTable) diff --git a/qad/sql_table/plugin/qad_sql_table.h b/qad/sql_table/plugin/qad_sql_table.h new file mode 100644 index 0000000..64009eb --- /dev/null +++ b/qad/sql_table/plugin/qad_sql_table.h @@ -0,0 +1,21 @@ +#ifndef QAD_SQL_TABLE_H +#define QAD_SQL_TABLE_H + +#include +#include + +class QADSQLTable: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit QADSQLTable(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; + +}; + +#endif // QAD_SQL_TABLE_H diff --git a/qad/sql_table/plugin/sql_record_plugin.cpp b/qad/sql_table/plugin/sql_record_plugin.cpp new file mode 100644 index 0000000..031977d --- /dev/null +++ b/qad/sql_table/plugin/sql_record_plugin.cpp @@ -0,0 +1,69 @@ +#include "sql_record_widget.h" +#include "sql_record_plugin.h" +#include + + +SQLRecordPlugin::SQLRecordPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void SQLRecordPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool SQLRecordPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * SQLRecordPlugin::createWidget(QWidget * parent) { + return new SQLRecordWidget(parent); +} + + +QString SQLRecordPlugin::name() const { + return QLatin1String("SQLRecordWidget"); +} + + +QString SQLRecordPlugin::group() const { + return QLatin1String("Editor Widgets"); +} + + +QIcon SQLRecordPlugin::icon() const { + return QIcon(":/icons/sql_table.png"); +} + + +QString SQLRecordPlugin::toolTip() const { + return QLatin1String(""); +} + + +QString SQLRecordPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool SQLRecordPlugin::isContainer() const { + return false; +} + + +QString SQLRecordPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString SQLRecordPlugin::includeFile() const { + return QLatin1String("sql_record_widget.h"); +} + diff --git a/qad/sql_table/plugin/sql_record_plugin.h b/qad/sql_table/plugin/sql_record_plugin.h new file mode 100644 index 0000000..2504493 --- /dev/null +++ b/qad/sql_table/plugin/sql_record_plugin.h @@ -0,0 +1,31 @@ +#ifndef SQLRECORDPLUGIN_H +#define SQLRECORDPLUGIN_H + +#include + +class SQLRecordPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + SQLRecordPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // SQLRECORDPLUGIN_H diff --git a/qad/sql_table/plugin/sql_table_plugin.cpp b/qad/sql_table/plugin/sql_table_plugin.cpp new file mode 100644 index 0000000..50e0969 --- /dev/null +++ b/qad/sql_table/plugin/sql_table_plugin.cpp @@ -0,0 +1,69 @@ +#include "sql_table_widget.h" +#include "sql_table_plugin.h" +#include + + +SQLTablePlugin::SQLTablePlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void SQLTablePlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool SQLTablePlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * SQLTablePlugin::createWidget(QWidget * parent) { + return new SQLTableWidget(parent); +} + + +QString SQLTablePlugin::name() const { + return QLatin1String("SQLTableWidget"); +} + + +QString SQLTablePlugin::group() const { + return QLatin1String("Editor Widgets"); +} + + +QIcon SQLTablePlugin::icon() const { + return QIcon(":/icons/sql_table.png"); +} + + +QString SQLTablePlugin::toolTip() const { + return QLatin1String(""); +} + + +QString SQLTablePlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool SQLTablePlugin::isContainer() const { + return false; +} + + +QString SQLTablePlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString SQLTablePlugin::includeFile() const { + return QLatin1String("sql_table_widget.h"); +} + diff --git a/qad/sql_table/plugin/sql_table_plugin.h b/qad/sql_table/plugin/sql_table_plugin.h new file mode 100644 index 0000000..671bfdf --- /dev/null +++ b/qad/sql_table/plugin/sql_table_plugin.h @@ -0,0 +1,31 @@ +#ifndef SQLTABLEPLUGIN_H +#define SQLTABLEPLUGIN_H + +#include + +class SQLTablePlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + SQLTablePlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // SQLTABLEPLUGIN_H diff --git a/qad/sql_table/qad_sql_table.qrc b/qad/sql_table/qad_sql_table.qrc new file mode 100644 index 0000000..bb36759 --- /dev/null +++ b/qad/sql_table/qad_sql_table.qrc @@ -0,0 +1,25 @@ + + + ../icons/dialog-close.png + ../icons/edit-clear.png + ../icons/edit-guides.png + ../icons/view-grid.png + ../icons/zoom-fit-best.png + ../icons/configure.png + ../icons/document-save.png + ../icons/edit-clear-locationbar-rtl.png + ../icons/edit-find.png + ../icons/list-add.png + ../icons/edit-delete.png + ../icons/item.png + ../icons/node-add.png + ../icons/node.png + ../icons/edit-copy.png + ../icons/edit-paste.png + ../icons/expand_s_x.png + ../icons/expand_s_y.png + ../icons/expand_x.png + ../icons/expand_y.png + ../icons/sql_table.png + + diff --git a/qad/sql_table/sql_record_widget.cpp b/qad/sql_table/sql_record_widget.cpp new file mode 100644 index 0000000..eac9bdc --- /dev/null +++ b/qad/sql_table/sql_record_widget.cpp @@ -0,0 +1,352 @@ +#include "sql_record_widget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SQLRecordWidget::SQLRecordWidget(QWidget * parent): QWidget(parent) { + setLayout(new QFormLayout()); + ro = false; +} + + +SQLRecordWidget::~SQLRecordWidget() { +} + + +void SQLRecordWidget::setRecord(const QSqlRecord & q, bool full_update) { + //qDebug() << (q.count() - hidden.size()) << (layout()->count() / 2); + if (full_update || (q.count() - hidden.size()) != (layout()->count() / 2)) createWidgets(q); + for (int i = 0; i < q.count(); ++i) { + QSqlField f = q.field(i); + QWidget * val = 0; + for (int w = 0; w < cws.size(); ++w) + if (cws[w]->objectName() == f.name()) { + val = cws[w]; + break; + } + if (val == 0) continue; + if (qobject_cast(val)) { + if (relations.contains(f.name())) { + bool ok = false; + int sv(f.value().toInt(&ok)); + if (!ok) + qobject_cast(val)->setText(""); + else { + QList > & rv(relations[f.name()]); + for (int j = 0; j < rv.size(); ++j) { + if (sv == rv[j].first) { + qobject_cast(val)->setText(rv[j].second); + break; + } + } + } + } else + qobject_cast(val)->setText(f.value().toString()); + } + if (qobject_cast(val)) qobject_cast(val)->setChecked(f.value().toBool()); + if (qobject_cast(val)) qobject_cast(val)->setValue(f.value().toDouble()); + if (qobject_cast(val)) qobject_cast(val)->setColor(QColor::fromRgba(f.value().toUInt())); + if (qobject_cast(val)) { + QString s = f.value().toString(); + qobject_cast(val)->setValue(s.isEmpty() ? QStringList() : s.split(";")); + } + if (qobject_cast(val)) { + bool ok = false; + int sv(f.value().toInt(&ok)); + if (!ok) + ((QComboBox*)val)->setCurrentIndex(-1); + else { + QList > & rv(relations[f.name()]); + for (int j = 0; j < rv.size(); ++j) { + if (sv == rv[j].first) { + ((QComboBox*)val)->setCurrentIndex(j); + break; + } + } + } + } + } +} + + +void SQLRecordWidget::setFixedValue(const QString & name, const QVariant & value) { + foreach (QWidget * w, cws) { + if (w->objectName() != name) continue; + if (qobject_cast(w)) {qobject_cast(w)->setText(value.toString()); qobject_cast(w)->setReadOnly(true);} + if (qobject_cast(w)) {qobject_cast(w)->setChecked(value.toBool()); w->setEnabled(false);} + if (qobject_cast(w)) {qobject_cast(w)->setValue(value.toDouble()); qobject_cast(w)->setReadOnly(true);} + if (qobject_cast(w)) {qobject_cast(w)->setColor(QColor::fromRgba(value.toUInt())); qobject_cast(w)->setEnabled(false);} + if (qobject_cast(w)) {qobject_cast(w)->setValue(QStringList()); qobject_cast(w)->setEnabled(false);} + } + +} + + +void SQLRecordWidget::clearValues() { + foreach (QWidget * w, cws) { + if (qobject_cast(w)) qobject_cast(w)->setText(QString()); + if (qobject_cast(w)) qobject_cast(w)->setChecked(false); + if (qobject_cast(w)) qobject_cast(w)->setValue(0.); + if (qobject_cast(w)) qobject_cast(w)->setColor(Qt::black); + if (qobject_cast(w)) qobject_cast(w)->setValue(QStringList()); + } +} + + +void SQLRecordWidget::createWidgets(const QSqlRecord & q) { + qDeleteAll(cws); + cws.clear(); + delete layout(); + QFormLayout * lay = new QFormLayout(); + lay->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + lay->setLabelAlignment(Qt::AlignRight); + lay->setContentsMargins(0, 0, 0, 0); + setLayout(lay); + //qDebug() << "createWidgets" << q.count(); + for (int i = 0; i < q.count(); ++i) { + QSqlField f = q.field(i); + if (hidden.contains(f.name())) continue; + QPair ctr = trColumn(f.name()); + QWidget * val = 0; + if (relations.contains(f.name())) { + if (ro) { + val = new QLineEdit(); + } else { + val = new QComboBox(); + QList > & rv(relations[f.name()]); + bool ok = false; + int sv(f.value().toInt(&ok)); + for (int j = 0; j < rv.size(); ++j) { + ((QComboBox*)val)->addItem(rv[j].second, rv[j].first); + if (ok) + if (sv == rv[j].first) + ((QComboBox*)val)->setCurrentIndex(j); + } + if (!ok) + ((QComboBox*)val)->setCurrentIndex(-1); + } + } else { + switch (fieldType(f)) { + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Double: + val = new QDoubleSpinBox(); + ((QDoubleSpinBox*)val)->setRange(-1E+99, 1E+99); + ((QDoubleSpinBox*)val)->setDecimals(3); break; + case QVariant::String: + val = new QLineEdit(); break; + case QVariant::Bool: + val = new QCheckBox(); break; + case QVariant::Color: + val = new ColorButton(); + ((ColorButton*)val)->setUseAlphaChannel(true); + ((ColorButton*)val)->setUseNativeDialog(true); + break; + case QVariant::StringList: + val = new StringListEdit(); + break; + default: break; + } + if (f.type() == QVariant::String || f.type() == QVariant::StringList) val->setProperty("_string", true); + } + if (val != 0) { + QString lt = ctr.first.left(1).toUpper() + ctr.first.right(ctr.first.length() - 1); + while (lt.endsWith("_")) lt.chop(1); + QLabel * lbl = new QLabel(lt + ":"); + lbl->setToolTip(ctr.second); + cws << lbl; + val->setObjectName(f.name()); + cws << val; + lay->addRow(lbl, val); + } else { + if (!hidden.contains(ctr.first)) + hidden << ctr.first; + } + } + updateWidgets(); + emit widgetsCreated(); +} + + +void SQLRecordWidget::updateWidgets() { + foreach (QWidget * w, cws) { + if (qobject_cast(w)) qobject_cast(w)->setReadOnly(ro); + if (qobject_cast(w)) qobject_cast(w)->setEnabled(!ro); + if (qobject_cast(w)) qobject_cast(w)->setReadOnly(ro); + if (qobject_cast(w)) qobject_cast(w)->setEnabled(!ro); + if (qobject_cast(w)) qobject_cast(w)->setEnabled(!ro); + if (qobject_cast(w)) qobject_cast(w)->setEnabled(!ro); + } +} + + +QVariant::Type SQLRecordWidget::fieldType(const QSqlField & f) { + QString ft = ftypes.value(f.name()); + if (ft.isEmpty()) return f.type(); + if (ft == "l") return QVariant::StringList; + if (ft == "b") return QVariant::Bool; + if (ft == "n") return QVariant::Int; + if (ft == "f") return QVariant::Double; + if (ft == "c") return QVariant::Color; + if (ft == "r") return QVariant::Rect; + if (ft == "a") return QVariant::RectF; + if (ft == "p") return QVariant::Point; + if (ft == "v") return QVariant::PointF; + return QVariant::String; +} + + +void SQLRecordWidget::addTranslation(const QString & file) { + QPIConfig conf(file, QIODevice::ReadOnly, QPIConfig::Config); + QPIConfig::Branch ae = conf.allLeaves(); + foreach (QPIConfig::Entry * e, ae) + translates[e->name()] = QPair(e->value(), e->comment()); +} + + +QString SQLRecordWidget::getValuesQuery() const { + QString ret("("); + bool first = true; + foreach (QWidget * w, cws) { + QWidget * vw(0); + if (qobject_cast(w)) {if (!qobject_cast(w)->text().isEmpty()) vw = w;} + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (vw == 0) continue; + if (!first) ret += ","; + first = false; + ret += vw->objectName(); + } + ret += ") VALUES ("; + foreach (QWidget * w, cws) { + QWidget * vw(0); + if (qobject_cast(w)) { + if (!qobject_cast(w)->text().isEmpty()) { + vw = w; + bool q = w->property("_string").toBool(); + if (q) ret += "'"; + ret += qobject_cast(w)->text(); + if (q) ret += "'"; + } + } + if (qobject_cast(w)) { + vw = w; + ret += qobject_cast(w)->isChecked() ? "1" : "0"; + } + if (qobject_cast(w)) { + vw = w; + ret += QString::number(qobject_cast(w)->value()); + } + if (qobject_cast(w)) { + vw = w; + ret += QString::number(qobject_cast(w)->color().rgba()); + } + if (qobject_cast(w)) { + vw = w; + ret += "'" + qobject_cast(w)->value().join(";") + "'"; + } + if (qobject_cast(w)) { + vw = w; + ret += ((QComboBox*)w)->itemData(((QComboBox*)w)->currentIndex(), Qt::UserRole).toString(); + } + if (vw == 0) continue; + ret += ","; + } + if (ret.endsWith(",")) ret.chop(1); + ret += ")"; + return ret; +} + + +QString SQLRecordWidget::getUpdateQuery() const { + QString ret; + bool first = true; + foreach (QWidget * w, cws) { + QWidget * vw(0); + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (qobject_cast(w)) vw = w; + if (vw == 0) continue; + if (!first) ret += ","; + first = false; + ret += vw->objectName() + "="; + if (qobject_cast(w)) { + if (qobject_cast(w)->text().isEmpty()) + ret += "null"; + else { + bool q = w->property("_string").toBool(); + if (q) ret += "'"; + ret += qobject_cast(w)->text(); + if (q) ret += "'"; + } + } + if (qobject_cast(w)) + ret += qobject_cast(w)->isChecked() ? "1" : "0"; + if (qobject_cast(w)) + ret += QString::number(qobject_cast(w)->value()); + if (qobject_cast(w)) + ret += QString::number(qobject_cast(w)->color().rgba()); + if (qobject_cast(w)) + ret += "'" + qobject_cast(w)->value().join(";") + "'"; + if (qobject_cast(w)) { + QString cd = ((QComboBox*)w)->itemData(((QComboBox*)w)->currentIndex(), Qt::UserRole).toString(); + ret += cd.isEmpty() ? "null" : cd; + } + } + return ret; +} + + +bool SQLRecordWidget::isEmpty() const { + return layout()->count() < 2; +} + + +void SQLRecordWidget::updateRelations() { + relations.clear(); + for (int i = 0; i < relations_src.size(); ++i) { + QSqlQuery q(QString("SELECT %1,%2 FROM %3").arg(relations_src[i].key, relations_src[i].ocol, relations_src[i].table), QSqlDatabase::database(connection_name)); + QList > cr; + while (q.next()) + cr << QPair(q.value(0).toInt(), q.value(1).toString()); + relations[relations_src[i].tcol] = cr; + } + QFormLayout * lay = (QFormLayout*)layout(); + if (!lay) return; + for (int i = 0; i < lay->rowCount(); ++i) { + QString name = lay->itemAt(i, QFormLayout::FieldRole)->widget()->objectName(); + if (hidden.contains(name)) continue; + QComboBox * val = qobject_cast(lay->itemAt(i, QFormLayout::FieldRole)->widget()); + if (!val) continue; + if (!relations.contains(name)) continue; + QList > & rv(relations[name]); + bool ok = false; + int sv(val->itemData(val->currentIndex()).toInt()); + val->clear(); + for (int j = 0; j < rv.size(); ++j) { + val->addItem(rv[j].second, rv[j].first); + if (sv == rv[j].first) + val->setCurrentIndex(j); + } + if (!ok) + val->setCurrentIndex(-1); + } +} diff --git a/qad/sql_table/sql_record_widget.h b/qad/sql_table/sql_record_widget.h new file mode 100644 index 0000000..68903fa --- /dev/null +++ b/qad/sql_table/sql_record_widget.h @@ -0,0 +1,74 @@ +#ifndef SQL_RECORD_WIDGET_H +#define SQL_RECORD_WIDGET_H + +#include +#include +#include +#include +#include +#include + +class SQLRecordWidget: public QWidget { + Q_OBJECT +public: + SQLRecordWidget(QWidget * parent = 0); + ~SQLRecordWidget(); + + void setRecord(const QSqlRecord & q, bool full_update = false); + void setReadOnly(bool yes) {ro = yes; updateWidgets();} + void setFixedValue(const QString & name, const QVariant & value); + void setTypeForName(const QString & name, const QString & type) {ftypes[name] = type;} + void clearValues(); + void removeWidgets() {qDeleteAll(cws); cws.clear();} + + void hideColumn(const QString & col) {hidden << col;} + void showColumn(const QString & col) {hidden.remove(col);} + void showColumns() {hidden.clear();} + void addRelation(const QString & this_column, const QString & other_table, const QString & other_key, const QString & other_column) {relations_src << RelationSrc(this_column, other_table, other_key, other_column); updateRelations();} + void removeRelations() {relations_src.clear(); updateRelations();} + void addTranslation(const QString & file); + void setConnectionName(const QString &conn_name) {connection_name = conn_name;} + QString connectionName() const {return connection_name;} + + QString getValuesQuery() const; + QString getUpdateQuery() const; + bool isEmpty() const; + QWidget * valueWidget(const QString & name) const {foreach (QWidget * w, cws) if (w->objectName() == name) return w; return 0;} + + void updateRelations(); + +protected: + QPair trColumn(const QString & n) {QPair trn = translates.value(n); if (trn.first.isEmpty()) return QPair(n, ""); return trn;} + void createWidgets(const QSqlRecord & q); + void updateWidgets(); + QVariant::Type fieldType(const QSqlField & f); + + struct RelationSrc { + RelationSrc(const QString & v0 = QString(), const QString & v1 = QString(), const QString & v2 = QString(), const QString & v3 = QString()): + tcol(v0), + table(v1), + key(v2), + ocol(v3) + {} + QString tcol; + QString table; + QString key; + QString ocol; + }; + + QMap > translates; + QVector relations_src; + QMap > > relations; + QMap ftypes; + QSet hidden; + QWidgetList cws; + bool ro; + QString connection_name; + +signals: + void updateRequest(); + void widgetsCreated(); + +}; + +#endif // SQL_RECORD_WIDGET_H diff --git a/qad/sql_table/sql_table_widget.cpp b/qad/sql_table/sql_table_widget.cpp new file mode 100644 index 0000000..c83b267 --- /dev/null +++ b/qad/sql_table/sql_table_widget.cpp @@ -0,0 +1,1067 @@ +#include "sql_table_widget.h" +#include "ui_sql_table_widget.h" +#include +#include +#include +#include +#include + + +QString SQLTableWidget::_dir; + + +ColumnProperties::ColumnProperties(const QString & table_, const QString & type_, const QString & name_, const QString & def_, bool auto_, bool prim_, bool option_) { + visible = true; + table = table_; + name = name_; + def = def_; + auto_increment = auto_; + primary = prim_; + optional = option_; + int bs = type_.indexOf("("), bf = type_.indexOf(")"); + size = type_.mid(bs + 1, bf - bs - 1).toInt(); + key_column = 0; + type = typeFromString(type_.toLower()); + is_text = (type == ColumnProperties::Chars || type == ColumnProperties::Text); +} + + +ColumnProperties::DataType ColumnProperties::typeFromString(const QString & n) { + if (n.indexOf("datetime") >= 0 || n.indexOf("timestamp") >= 0) return ColumnProperties::DateTime; + if (n.indexOf("date") >= 0) return ColumnProperties::Date; + if (n.indexOf("time") >= 0) return ColumnProperties::Time; + if (n.indexOf("int") >= 0) return ColumnProperties::Int; + if (n.indexOf("char") >= 0) return ColumnProperties::Chars; + if (n.indexOf("dec") >= 0 || n.indexOf("numeric") >= 0 || n.indexOf("real") >= 0 || + n.indexOf("float") >= 0 || n.indexOf("double") >= 0) return ColumnProperties::Float; + if (n.indexOf("text") >= 0) return ColumnProperties::Text; + if (n.indexOf("blob") >= 0) return ColumnProperties::Binary; + return ColumnProperties::Unknown; +} + + + + +QVariant SQLQueryModel::data(const QModelIndex & item, int role) const { + QVariant var = QSqlQueryModel::data(item, role); + //QVariant::Type t = var.type(); + /*if (t == QVariant::Date) return var.toDate().toString("dd.MM.yyyy"); + if (t == QVariant::Time) return var.toTime().toString("hh:mm:ss"); + if (t == QVariant::DateTime) return var.toDateTime().toString("dd.MM.yyyy hh:mm:ss");*/ + return var; +} + + +bool SQLQueryModel::setData(const QModelIndex& index, const QVariant & value, int role) { + if (value.isValid() && role == Qt::EditRole) { + QSqlQuery q(QSqlDatabase::database(conn_name)); + int col = mapColumn(index.column()); + ColumnProperties::DataType t = column_props[col].type; + bool quotes = (t == ColumnProperties::Chars || t == ColumnProperties::Text || + t == ColumnProperties::Date || t == ColumnProperties::Time || + t == ColumnProperties::ColumnProperties::DateTime); + QString val = value.toString(); + if (t == ColumnProperties::Date) val = value.toDate().toString("yyyy-MM-dd"); + if (t == ColumnProperties::Time) val = value.toTime().toString("hh:mm:ss"); + if (t == ColumnProperties::DateTime) val = value.toDateTime().toString("yyyy-MM-dd hh:mm:ss"); + if (!q.exec("UPDATE " + table_ + " SET " + column_props[col].name + "=" + + (quotes ? "'" : "") + val + (quotes ? "'" : "") + + " WHERE " + column_props[0].name + "=" + record(index.row()).value(0).toString() + ";")) { + qDebug() << "[UPDATE]" << q.lastQuery() << "Error:" << q.lastError(); + return false; + } + //qDebug() << "[UPDATE]" << q.lastQuery(); + dataChanged(index, index); + updateTable(true); + emit tableChanged(); + return true; + } + return false; +} + + + + +SQLUniEdit::SQLUniEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent): QWidget(parent), prop_(prop), connection_name(conn_name) { + wtext = 0; wint = 0; wfloat = 0; wdate = 0; wtime = 0; wdatetime = 0; wrelation = 0; + setProp(prop_); + w_ << (QWidget **)&wtext << (QWidget **)&wint << (QWidget **)&wfloat << (QWidget **)&wdate << (QWidget **)&wtime << (QWidget **)&wdatetime << (QWidget **)&wrelation; +} + + +void SQLUniEdit::setProp(const ColumnProperties & p) { + for (int i = 0; i < w_.size(); ++i) deleteW(*w_[i]); + wtext = 0; wint = 0; wfloat = 0; wdate = 0; wtime = 0; wdatetime = 0; wrelation = 0; + prop_ = p; + if (prop_.isRelation()) { + wrelation = new QComboBox(this); + wrelation->installEventFilter(this); + for (int i = 0; i < prop_.relation_list.size(); ++i) + wrelation->addItem(prop_.relation_list[i].second, prop_.relation_list[i].first); + connect(wrelation, SIGNAL(currentIndexChanged(int)), this, SLOT(value_int(int))); + } else { + ColumnProperties::DataType t = prop_.getType(); + switch (t) { + case ColumnProperties::Int: wint = new QSpinBox(this); wint->setRange(-0x7FFFFFFF, 0x7FFFFFFF); connect(wint, SIGNAL(valueChanged(int)), this, SLOT(value_int(int))); break; + case ColumnProperties::Float: wfloat = new QDoubleSpinBox(this); wfloat->setRange(-1E+300, 1E+300); wfloat->setDecimals(2); connect(wfloat, SIGNAL(valueChanged(double)), this, SLOT(value_float(double))); break; + case ColumnProperties::Date: wdate = new QDateEdit(this); wdate->setDisplayFormat("dd.MM.yyyy"); wdate->setCalendarPopup(true); wdate->setDate(QDate::currentDate()); connect(wdate, SIGNAL(dateChanged(QDate)), this, SLOT(value_date(QDate))); break; + case ColumnProperties::Time: wtime = new QTimeEdit(this); wtime->setDisplayFormat("hh:mm:ss"); wtime->setTime(QTime::currentTime()); connect(wtime, SIGNAL(timeChanged(QTime)), this, SLOT(value_time(QTime))); break; + case ColumnProperties::DateTime: wdatetime = new QDateTimeEdit(this); wdatetime->setDisplayFormat("dd.MM.yyyy hh:mm:ss"); wdatetime->setCalendarPopup(true); wdatetime->setDateTime(QDateTime::currentDateTime()); connect(wdatetime, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(value_datetime(QDateTime))); break; + case ColumnProperties::Chars: + case ColumnProperties::Text: + case ColumnProperties::Unknown: + default: wtext = new QLineEdit(this); connect(wtext, SIGNAL(textChanged(QString)), this, SLOT(value_text(QString))); break; + } + } + for (int i = 0; i < w_.size(); ++i) + if (*w_[i]) (*w_[i])->setHidden(false); + resizeEvent(0); +} + + +QString SQLUniEdit::value(bool for_insert) { + QString ret; + ColumnProperties::DataType t = (for_insert ? prop_.type : prop_.getType()); + bool quotes = (t == ColumnProperties::Chars || t == ColumnProperties::Text || + t == ColumnProperties::Date || t == ColumnProperties::Time || + t == ColumnProperties::ColumnProperties::DateTime); + if (quotes) ret = "'"; + if (prop_.isRelation()) + if (for_insert) + ret += wrelation->itemData(wrelation->currentIndex()).toString(); + else + ret += wrelation->currentText(); + else { + if (wint != 0) ret += QString::number(wint->value()); + else { + if (wfloat != 0) ret += QString::number(wfloat->value()); + else { + if (wdate != 0) ret += wdate->date().toString("yyyy-MM-dd"); + else { + if (wtime != 0) ret += wtime->time().toString("hh:mm:ss"); + else { + if (wdatetime != 0) ret += wdatetime->dateTime().toString("yyyy-MM-dd hh:mm:ss"); + else { + ret += wtext->text(); + } + } + } + } + } + } + if (quotes) ret += "'"; + if (ret == "''") ret.clear(); + return ret; +} + + +bool SQLUniEdit::eventFilter(QObject * o, QEvent * e) { + if (e->type() == QEvent::MouseButtonPress) + updateRelation(); + return QWidget::eventFilter(o, e); +} + + +void SQLUniEdit::setValue(const QVariant & value) { + if (prop_.isRelation()) return; + if (wint != 0) wint->setValue(value.toInt()); + else { + if (wfloat != 0) wfloat->setValue(value.toDouble()); + else { + if (wdate != 0) wdate->setDate(value.toDate()); + else { + if (wtime != 0) wtime->setTime(value.toTime()); + else { + if (wdatetime != 0) wdatetime->setDateTime(value.toDateTime()); + else { + wtext->setText(value.toString()); + } + } + } + } + } + +} + + +void SQLUniEdit::updateRelation() { + prop_.relation_list = SQLTableWidget::getColumnValues(prop_.relation_table, prop_.relation_key, prop_.relation_column, connection_name); + int pi = wrelation->currentIndex(); + wrelation->blockSignals(true); + wrelation->clear(); + for (int i = 0; i < prop_.relation_list.size(); ++i) + wrelation->addItem(prop_.relation_list[i].second, prop_.relation_list[i].first); + wrelation->setCurrentIndex(pi); + wrelation->blockSignals(false); +} + + + +SQLNewEdit::SQLNewEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent): QWidget(parent), prop_(prop) { + line = new SQLUniEdit(prop, conn_name); + line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + check = new QCheckBox(); + check->setChecked(true); + check->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + connect(check, SIGNAL(toggled(bool)), line, SLOT(setEnabled(bool))); + QLayout * lay = new QHBoxLayout(); + lay->addWidget(check); + lay->addWidget(line); + lay->setContentsMargins(0, 0, 0, 0); + lay->setSpacing(0); + setLayout(lay); + setProp(prop); + check->setChecked(!prop.primary); +} + + +void SQLNewEdit::setProp(const ColumnProperties & p) { + prop_ = p; + line->setProp(p); + check->setEnabled(p.optional); + if (!check->isEnabled()) check->setChecked(true); +} + + + +SQLFilterEdit::SQLFilterEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent): QWidget(parent), prop_(prop) { + line = new SQLUniEdit(prop, conn_name); + line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + combo = new QComboBox(); + combo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + QStringList sl; + sl << " " << "=" << trUtf8("≈") << trUtf8("≠") << ">" << trUtf8("≥") << "<" << trUtf8("≤"); + combo->addItems(sl); + combo->setCurrentIndex(0); + connect(line, SIGNAL(valueChanged(QVariant)), this, SIGNAL(filterChanged())); + connect(line, SIGNAL(valueChanged(QVariant)), this, SLOT(value_changed())); + connect(combo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(filterChanged())); + QLayout * lay = new QHBoxLayout(); + lay->addWidget(combo); + lay->addWidget(line); + lay->setContentsMargins(0, 0, 0, 0); + lay->setSpacing(2); + setLayout(lay); + setProp(prop); +} + + +QString SQLFilterEdit::filter() const { + QString ret; + if (combo->currentIndex() == 0) return ret; + ret = prop_.fullName(); + switch (combo->currentIndex()) { + case 1: ret.append("="); break; + case 2: ret.append("="); break; + case 3: ret.append("!="); break; + case 4: ret.append(">"); break; + case 5: ret.append(">="); break; + case 6: ret.append("<"); break; + case 7: ret.append("<="); break; + }; + QString val = line->value(); + if (prop_.is_text && combo->currentIndex() == 2) { + ret.chop(1); + ret.append(" LIKE '%"); + ret.append(val.mid(1, val.length() - 2)); + ret.append("%'"); + } else + ret.append(val); + return ret; +} + + +void SQLFilterEdit::clear() { + line->setValue(QVariant()); + combo->setCurrentIndex(0); + +} + + + + +SQLItemDelegate::SQLItemDelegate(QList & cp, QVector & ci, bool & ro, const QString & conn_name, QObject * parent): + QStyledItemDelegate(parent), column_props(cp), column_indexes(ci), read_only(ro), connection_name(conn_name) {;} + + +QWidget * SQLItemDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { + if (read_only) return 0; + ColumnProperties & cp(column_props[mapColumn(index.column())]); + if (cp.isRelation()) { + cp.relation_list = SQLTableWidget::getColumnValues(cp.relation_table, cp.relation_key, cp.relation_column, connection_name); + QComboBox * w = new QComboBox(parent); + w->setGeometry(option.rect); + for (int i = 0; i < cp.relation_list.size(); ++i) { + w->addItem(cp.relation_list[i].second, cp.relation_list[i].first); + if (index.data().toString() == cp.relation_list[i].second) + w->setCurrentIndex(i); + } + return w; + } else { + QWidget * w = QStyledItemDelegate::createEditor(parent, option, index); + if (qobject_cast(w)) {qobject_cast(w)->setDisplayFormat("hh:mm:ss");} + else if (qobject_cast(w)) {qobject_cast(w)->setCalendarPopup(true); qobject_cast(w)->setDisplayFormat("dd.MM.yyyy");} + else if (qobject_cast(w)) {qobject_cast(w)->setCalendarPopup(true); qobject_cast(w)->setDisplayFormat("dd.MM.yyyy hh:mm:ss");} + return w; + } + return 0; +} + + +QString SQLItemDelegate::displayText(const QVariant & value, const QLocale & locale) const { + QVariant::Type t = value.type(); + if (t == QVariant::Date) return value.toDate().toString("dd.MM.yyyy"); + if (t == QVariant::Time) return value.toTime().toString("hh:mm:ss"); + if (t == QVariant::DateTime) return value.toDateTime().toString("dd.MM.yyyy hh:mm:ss"); + return QStyledItemDelegate::displayText(value, locale); +} + + +void SQLItemDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { + if (qobject_cast(editor)) { + model->setData(index, qobject_cast(editor)->itemData(qobject_cast(editor)->currentIndex())); + return; + } + QStyledItemDelegate::setModelData(editor, model, index); +} + + + +SQLTableWidget::SQLTableWidget(QWidget * parent): QWidget(parent), filters_group(this) { + ui = new Ui::SQLTableWidget(); + ui->setupUi(this); + model = 0; + timer = 0; + connection_name = QSqlDatabase::defaultConnection; + filters_active = first_update = true; + table_opened = read_only = false; + ui->view->installEventFilter(this); + ui->view->viewport()->installEventFilter(this); + ui->view->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder); + ui->view->horizontalHeader()->viewport()->installEventFilter(this); + ui->view->setItemDelegate(new SQLItemDelegate(column_props, column_indexes, read_only, connection_name)); + ui->view->horizontalHeader()->setItemDelegate(new QItemDelegate()); + //qDebug() << view->horizontalHeader()->itemDelegate(); + //qDebug() << fontMetrics().elidedText(, Qt::ElideNone, 30, Qt::TextWordWrap); + setTableVisible(false); + connect(ui->view->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), this, SLOT(header_sectionResized(int, int, int))); + connect(ui->view->horizontalHeader(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(header_sortIndicatorChanged(int, Qt::SortOrder))); + connect(ui->view->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(scrolled(int))); + + + //act_add.setText(trUtf8("Add ...")); + //act_del.setText(trUtf8("Remove selected")); + action_del = new QAction(QIcon(":/icons/edit-delete.png"), trUtf8("Remove selected"), this); + connect(action_del, SIGNAL(triggered(bool)), this, SLOT(del_triggered())); + popup_menu.addAction(action_del); + ui->actionFilter_AND->setChecked(true); + filters_group.addAction(ui->actionFilter_AND); + filters_group.addAction(ui->actionFilter_OR); + connect(&filters_group, SIGNAL(triggered(QAction * )), this, SLOT(updateTable())); + popup_filter.addAction(ui->actionFiltersClear); + popup_filter.addSeparator(); + popup_filter.addAction(ui->actionFilter_AND); + popup_filter.addAction(ui->actionFilter_OR); + ui->buttonFilterConfig->setMenu(&popup_filter); + //connect(&act_add, SIGNAL(triggered(bool)), this, SLOT(add_triggered())); + //connect(&act_del, SIGNAL(triggered(bool)), this, SLOT(del_triggered())); +} + + +SQLTableWidget::~SQLTableWidget() { + stopTimer(); + if (model != 0) delete model; +} + + +bool SQLTableWidget::eventFilter(QObject * o, QEvent * e) { + if (o == ui->view) { + if (e->type() == QEvent::KeyPress) { + QKeyEvent * ke = (QKeyEvent * )e; + if (ke->key() == Qt::Key_Home) {ui->view->selectRow(0); return true;} + if (ke->key() == Qt::Key_End) {ui->view->selectRow(ui->view->verticalHeader()->count() - 1); return true;} + } + } + if (o == ui->view->viewport()) { + if (e->type() == QEvent::MouseButtonPress) { + QMouseEvent * me = (QMouseEvent * )e; + if (me->button() == Qt::RightButton) { + action_del->setVisible(!read_only); + popup_menu.popup(me->globalPos()); + } + } + } + if (o == ui->view->horizontalHeader()->viewport()) { + QMouseEvent * me = (QMouseEvent * )e; + if (e->type() == QEvent::MouseButtonPress) + pp = me->pos(); + if (e->type() == QEvent::MouseButtonRelease) { + if ((me->pos() - pp).manhattanLength() < QApplication::startDragDistance()) { + if (me->button() == Qt::LeftButton) { + int ci = ui->view->horizontalHeader()->logicalIndexAt(me->pos()), + ri = ui->view->horizontalHeader()->logicalIndexAt(me->pos() + QPoint(3, 0)), + li = ui->view->horizontalHeader()->logicalIndexAt(me->pos() - QPoint(3, 0)); + //qDebug() << ci << ri << li; + if ((ci < 0) || (ci >= ui->view->horizontalHeader()->count()) || (ci != ri) || (ci != li) || (tm.elapsed() <= QApplication::doubleClickInterval())) { + tm.restart(); + return QObject::eventFilter(o, e); + } + tm.restart(); + Qt::SortOrder o = Qt::AscendingOrder; + if (ui->view->horizontalHeader()->sortIndicatorSection() == ci && + ui->view->horizontalHeader()->sortIndicatorOrder() == Qt::AscendingOrder) + o = Qt::DescendingOrder; + ui->view->horizontalHeader()->setSortIndicator(ci, o); + return true; + } + if (me->button() == Qt::RightButton) { + popup_col.clear(); + for (int i = 0; i < column_props.size(); ++i) { + QPair ctr = trColumn(column_props[i].name); + QAction * a = popup_col.addAction(ctr.first, this, SLOT(column_triggered(bool))); + a->setToolTip(ctr.second); + a->setCheckable(true); + a->setChecked(column_props[i].visible); + a->setData(i); + } + popup_col.popup(me->globalPos()); + return true; + } + } else return true; + } + } + return QWidget::eventFilter(o, e); +} + + +void SQLTableWidget::timerEvent(QTimerEvent * ) { + setTableName(table_); +} + + +void SQLTableWidget::setTableName(const QString & t) { + ui->labelEmpty->setText(tr("Table \"%1\" doesn`t exists!").arg(t)); + stopTimer(); + table_opened = false; + first_update = true; + table_ = t; + if (!QSqlDatabase::database(connection_name).isOpen()) { + qDebug() << "[setTableName] Database in not opened!"; + setTableVisible(false); + timer = startTimer(1000); + return; + } + model = new SQLQueryModel(table_, connection_name, column_props, column_indexes, this); + connect(model, SIGNAL(updateTable(bool)), this, SLOT(updateTable(bool))); + connect(model, SIGNAL(tableChanged()), this, SIGNAL(tableChanged())); + //model->setTable(table_); + cquery = "SELECT * FROM " + table_ + ";"; + model->setQuery(cquery, QSqlDatabase::database(connection_name)); + ui->view->setModel(model); + connect(ui->view->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), this, SIGNAL(selectionChanged()), Qt::UniqueConnection); + //((QSqlQueryModel * )model)->setQuery(QSqlQuery("SELECT id FROM " + table_ + ";")); + setTableVisible(checkTable()); + updateTable(); + foreach (const QString & wr, wait_rels) { + QStringList wrl = wr.split(";"); + addRelation(wrl[0], wrl[1], wrl[2], wrl[3]); + } + QMapIterator cnit(col_vis); + while (cnit.hasNext()) { + cnit.next(); + setColumnVisible(cnit.key(), cnit.value()); + } +} + + +bool SQLTableWidget::checkTable() { + table_opened = false; + QSqlDatabase db = QSqlDatabase::database(connection_name); + if (db.driver() == 0) return false; + bool te = db.tables(QSql::Tables).contains(table_, Qt::CaseInsensitive ); + //qDebug() << "tables:" << db.tables(QSql::Tables) << table_ << table_opened; + if (!te) { + timer = startTimer(1000); + return false; + } + /*if (!q.exec("SHOW TABLES")) { + qDebug() << "[SHOW TABLES]" << q.lastError(); + timer = startTimer(1000); + return false; + } + while (q.next()) { + //qDebug() << q.value(0); + if (q.value(0) == table_) + {table_opened = true; break;} + } + if (!table_opened) { + timer = startTimer(1000); + return false; + }*/ + QSqlRecord header = db.record(table_); + QString pin = db.primaryIndex(table_).fieldName(0); + table_opened = true; + column_props.clear(); + for (int i = 0; i < header.count(); ++i) { + QSqlField f = header.field(i); + column_props << ColumnProperties(table_, + f.type() == QVariant::String ? "text" : QVariant::typeToName(f.type()), + f.name(), + f.defaultValue().toString(), + f.isAutoValue(), + f.name() == pin, + f.requiredStatus() == QSqlField::Optional + ); + } + /*if (!q.exec("DESCRIBE " + table_ + ";")) { + qDebug() << "[DESCRIBE " + table_ + "]" << q.lastError(); + timer = startTimer(1000); + return false; + } + while (q.next()) { + column_props << ColumnProperties(table_, + q.value(1).toString().toLower(), + q.value(0).toString().toLower(), + q.value(4).toString().toLower(), + q.value(5).toString().toLower().indexOf("auto_increment") >= 0, + q.value(3).toString().toLower().indexOf("pri") >= 0); + }*/ + ui->labelNew->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); + ui->labelFilter->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); + ui->scrollAreaNew->setFixedHeight(QLineEdit().sizeHint().height() + 2); + ui->scrollAreaFilter->setFixedHeight(QLineEdit().sizeHint().height() + 2); + qDeleteAll(column_news); + qDeleteAll(column_filters); + column_news.clear(); + column_filters.clear(); + SQLNewEdit * le = 0; + for (int i = 0; i < column_props.size(); ++i) { + le = new SQLNewEdit(column_props[i], connection_name); + le->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); + column_news.push_back(le); + ui->layoutNew->insertWidget(i, le); + } + for (int i = 0; i < column_props.size(); ++i) { + SQLFilterEdit * fe = new SQLFilterEdit(column_props[i], connection_name); + fe->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); + column_filters.push_back(fe); + ui->layoutFilter->insertWidget(i, fe); + connect(fe, SIGNAL(filterChanged()), this, SLOT(updateTable())); + } + return true; +} + + +QStringList SQLTableWidget::getTableColumns(const QString & t) { + QStringList ret; + QSqlDatabase db = QSqlDatabase::database(connection_name); + QSqlRecord header = db.record(t); + for (int i = 0; i < header.count(); ++i) + ret << header.field(i).name(); + return ret; +} + + +QString SQLTableWidget::getColumnType(const QString & t, const QString & c) { + QSqlDatabase db = QSqlDatabase::database(connection_name); + QSqlRecord header = db.record(t); + for (int i = 0; i < header.count(); ++i) { + QSqlField f = header.field(i); + if (f.name() != c) continue; + return (f.type() == QVariant::String ? "text" : QVariant::typeToName(f.type())); + } + return QString(); +} + + +QList > SQLTableWidget::getColumnValues(const QString &t, const QString &k, const QString &c, const QString &conn_name) { + QList > ret; + QSqlQuery q(QSqlDatabase::database(conn_name)); + if (!q.exec("SELECT " + t + "." + k + "," + t + "." + c + " FROM " + t + ";")) + return ret; + while (q.next()) + ret << QPair(q.value(0).toString(), q.value(1).toString()); + return ret; +} + + +QPair SQLTableWidget::trColumn(const QString & n) { + QPair ftr = fixed_translates.value(n); + if (!ftr.first.isEmpty()) + return ftr; + QPair trn = translates.value(n); + if (trn.first.isEmpty()) return QPair(n, ""); + return trn; +} + + +void SQLTableWidget::updateTable(bool save_selection) { + if (!filters_active || !table_opened) return; + int vp = ui->view->verticalScrollBar()->value(); + int hp = ui->view->horizontalScrollBar()->value(); + //bool focus = view->hasFocus(); + QModelIndex csi; + QModelIndexList sl; + if (save_selection) { + csi = ui->view->selectionModel()->currentIndex(); + sl = ui->view->selectionModel()->selectedRows(); + } + if (custom_query.isEmpty()) { + QString cr = columnRelations(), cf = columnFilters(); + bool where = !cr.isEmpty() || !cf.isEmpty(), and_ = !cr.isEmpty() && !cf.isEmpty(); + cquery = "SELECT " + columnNames() + " FROM " + tableNames() + + (where ? " WHERE " : "") + cr + (and_ ? " AND " : "") + cf + " ORDER BY " + + column_props[ui->view->horizontalHeader()->sortIndicatorSection()].fullName() + + (ui->view->horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder ? " DESC" : " ASC") + ";"; + } else + cquery = custom_query; + //qDebug() << cquery; + model->setQuery(cquery, QSqlDatabase::database(connection_name)); + if (model->lastError().isValid()) + qDebug() << model->lastError(); + if (first_update) { + ui->view->resizeColumnsToContents(); + for (int i = 0; i < ui->view->horizontalHeader()->count(); ++i) + if (ui->view->horizontalHeader()->sectionSize(i) < 100) + ui->view->horizontalHeader()->resizeSection(i, 100); + first_update = false; + } + ui->labelNew->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); + ui->labelFilter->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); + ui->layoutNew->invalidate(); + if (save_selection) { + QItemSelectionModel * sm = ui->view->selectionModel(); + foreach (const QModelIndex & i, sl) + sm->select(i, QItemSelectionModel::Select | QItemSelectionModel::Rows); + sm->setCurrentIndex(csi, QItemSelectionModel::Select); + //ui->view->setFocus(); + } + if (custom_query.isEmpty()) { + for (int i = 0; i < model->columnCount(); ++i) { + QPair ctr = trColumn(column_props[mapColumn(i)].name); + model->setHeaderData(i, Qt::Horizontal, ctr.first, Qt::DisplayRole); + model->setHeaderData(i, Qt::Horizontal, ctr.second, Qt::ToolTipRole); + } + } else { + if (custom_col_names.isEmpty()) { + QSqlRecord header = model->record(); + for (int i = 0; i < header.count(); ++i) { + QSqlField f = header.field(i); + QPair ctr = trColumn(f.name()); + model->setHeaderData(i, Qt::Horizontal, ctr.first, Qt::DisplayRole); + model->setHeaderData(i, Qt::Horizontal, ctr.second, Qt::ToolTipRole); + } + } else { + for (int i = 0; i < qMin(custom_col_names.size(), model->columnCount()); ++i) { + QPair ctr = trColumn(custom_col_names[i]); + model->setHeaderData(i, Qt::Horizontal, ctr.first, Qt::DisplayRole); + model->setHeaderData(i, Qt::Horizontal, ctr.second, Qt::ToolTipRole); + } + } + } + ui->view->verticalScrollBar()->setValue(vp); + ui->view->horizontalScrollBar()->setValue(hp); + //if (focus) view->setFocus(); +} + + +void SQLTableWidget::setConnectionName(const QString & conn_name) { + connection_name = conn_name; + ui->view->setItemDelegate(new SQLItemDelegate(column_props, column_indexes, read_only, connection_name)); +} + + +QString SQLTableWidget::tableNames() { + QString ret = table_; + QSet rtables; + for (int i = 0; i < column_props.size(); ++i) { + ColumnProperties & cp(column_props[i]); + if (!cp.visible || cp.relation_key.isEmpty() || cp.relation_column.isEmpty()) + continue; + if (rtables.contains(cp.relation_table)) + continue; + rtables << cp.relation_table; + ret.append("," + cp.relation_table); + } + return ret; +} + + +QString SQLTableWidget::columnNames() { + QString ret; + bool first = true; + column_indexes.clear(); + for (int i = 0; i < column_props.size(); ++i) { + ColumnProperties & cp(column_props[i]); + column_news[i]->setVisible(cp.visible); + column_filters[i]->setVisible(cp.visible); + if (!cp.visible && !cp.primary) + continue; + if (!first) ret.append(","); + first = false; + ret.append(cp.fullName()); + if (i > 0) column_indexes.push_back(i); + } + //qDebug() << column_indexes; + return ret; +} + + +QString SQLTableWidget::columnFilters() { + QString ret; + bool and_ = ui->actionFilter_AND->isChecked(); + for (int i = 0; i < column_props.size(); ++i) { + if (!column_filters[i]->isVisible() || column_filters[i]->isEmpty()) + continue; + if (!ret.isEmpty()) + ret.append(and_ ? " AND " : " OR "); + ret.append(column_filters[i]->filter()); + } + if (!ret.isEmpty()) { + ret.prepend("("); + ret.append(")"); + } + return ret; +} + + +QString SQLTableWidget::columnRelations() { + QString ret; + for (int i = 0; i < column_props.size(); ++i) { + ColumnProperties & cp(column_props[i]); + if (!cp.visible || cp.relation_key.isEmpty() || cp.relation_column.isEmpty()) + continue; + if (!ret.isEmpty()) + ret.append(" AND "); + ret.append(table_ + "." + cp.name + "="); + ret.append(cp.relation_table + "." + cp.relation_key); + } + if (!ret.isEmpty()) { + ret.prepend("("); + ret.append(")"); + } + return ret; +} + + +void SQLTableWidget::on_buttonAdd_clicked() { + QStringList values; + bool at_least = false; + for (int i = 0; i < column_props.size(); ++i) { + values.append(column_news[i]->value()); + if (!values.back().isEmpty()) at_least = true; + } + if (!at_least) return; + QString qs("INSERT INTO " + table_ + " ("); + bool first = true; + for (int i = 0; i < column_props.size(); ++i) { + if (values[i].isEmpty() || !column_news[i]->isEnabled()) continue; + if (!first) qs.append(","); + qs.append(column_props[i].name); + first = false; + } + qs.append(") VALUES("); + first = true; + for (int i = 0; i < column_props.size(); ++i) { + if (values[i].isEmpty() || !column_news[i]->isEnabled()) continue; + if (!first) qs.append(","); + qs.append(values[i]); + first = false; + } + qs.append(");"); + QSqlQuery q(QSqlDatabase::database(connection_name)); + if (q.exec(qs)) { + updateTable(); + emit tableChanged(); + } else + qDebug() << q.lastError(); + //qDebug() << q.lastQuery(); +} + + +void SQLTableWidget::on_actionFiltersClear_triggered() { + filters_active = false; + foreach (SQLFilterEdit * l, column_filters) + l->clear(); + filters_active = true; + updateTable(); +} + + +void SQLTableWidget::on_view_clicked(const QModelIndex & index) { + emit rowClicked(index.row()); + emit recordClicked(model->record(index.row())); +} + + +void SQLTableWidget::del_triggered() { + QModelIndexList si = ui->view->selectionModel()->selectedIndexes(); + QSet ids; + foreach (const QModelIndex & i, si) + ids << model->index(i.row(), 0).data().toInt(); + if (ids.isEmpty()) return; + QString qs("DELETE FROM " + table_ + " WHERE " + column_props[0].name + " IN ("); + bool first = true; + foreach (int i, ids) { + if (!first) qs.append(","); + qs.append(QString::number(i)); + first = false; + } + qs.append(");"); + //qDebug() << qs; return; + QSqlQuery q(QSqlDatabase::database(connection_name)); + if (q.exec(qs)) { + updateTable(); + emit tableChanged(); + } else + qDebug() << q.lastError(); +} + + +void SQLTableWidget::setColumnVisible(int ind, bool visible) { + if (!columnExists(ind)) return; + column_props[ind].visible = visible; + if (ind == 0) { + ui->view->setColumnHidden(0, !visible); + if (visible) ui->view->horizontalHeader()->resizeSection(0, ui->view->horizontalHeader()->defaultSectionSize()); + } + //qDebug() << ind << on; + updateTable(); + for (int i = 0; i < ui->view->horizontalHeader()->count(); ++i) { + column_news[mapColumn(i)]->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); + column_filters[mapColumn(i)]->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); + } +} + + +bool SQLTableWidget::addRelation(const QString & this_column, const QString & other_table, const QString & other_key, const QString & other_column) { + QString wr = this_column + ";" + other_table + ";" + other_key + ";" + other_column; + if (!wait_rels.contains(wr)) wait_rels << wr; + ColumnProperties * cp = const_cast(columnProperty(this_column)); + if (cp == 0) return false; + cp->relation_table = other_table; + cp->relation_key = other_key; + cp->relation_column = other_column; + cp->relation_type = ColumnProperties::typeFromString(getColumnType(other_table, other_column)); + cp->relation_list = getColumnValues(other_table, other_key, other_column, connection_name); + for (int i = 0; i < column_props.size(); ++i) + column_news[i]->setProp(column_props[i]); + for (int i = 0; i < column_props.size(); ++i) + column_filters[i]->setProp(column_props[i]); + updateTable(); + return true; +} + + +void SQLTableWidget::addTranslation(const QString & file) { + QPIConfig conf(file, QIODevice::ReadOnly, QPIConfig::Config); + QPIConfig::Branch ae = conf.allLeaves(); + foreach (QPIConfig::Entry * e, ae) + translates[e->name()] = QPair(e->value(), e->comment()); +} + + +void SQLTableWidget::addFixedColumnTranslation(const QString & col_name, const QString & col_tr, const QString & col_tt) { + fixed_translates[col_name] = QPair(col_tr, col_tt); + updateTable(); +} + + +void SQLTableWidget::setAdditionalActions(QList a) { + foreach (QAction * i, add_actions) + popup_menu.removeAction(i); + add_actions = a; + popup_menu.addActions(a); +} + + +void SQLTableWidget::setCustomQuery(const QString & q) { + custom_query = q; + updateTable(); +} + + +QString SQLTableWidget::preprocessScript(QString text) { + QTextStream s(&text, QIODevice::ReadOnly); + QString out; + int ce = 0; + while (!s.atEnd()) { + QString line = s.readLine(); + ce = line.indexOf("--"); + if (ce >= 0) + line.chop(line.length() - ce); + out.append(line).append("\n"); + } + int cs = out.indexOf("/*"); + while (cs >= 0) { + ce = out.indexOf("*/", cs); + if (ce > cs) + out.remove(cs, ce - cs + 2); + cs = out.indexOf("/*"); + } + //qDebug() << out; + return out; +} + + +bool SQLTableWidget::executeScript(const QString & text_, QSqlDatabase db, bool skip_errors, bool sqlite) { + QString text = preprocessScript(text_); + int ls = 0, le = text.indexOf(';'); + QSqlQuery q(db); + db.transaction(); + while (le > 0) { + QString line = text.mid(ls, le - ls + 1).trimmed(), fword; + if (sqlite) line.replace("auto_increment", "autoincrement"); + QTextStream(&line, QIODevice::ReadOnly) >> fword; + fword = fword.trimmed().toLower(); + if (fword == "exec" || fword == "execute") { + line = line.right(line.length() - fword.length()).trimmed(); + if (line.endsWith(";")) line.chop(1); + line = line.trimmed(); + if (line.endsWith("'") || line.endsWith("\"")) line.chop(1); + if (line.startsWith("'") || line.startsWith("\"")) line.remove(0, 1); + executeScriptFile(line, db, skip_errors, sqlite); + } else { + if (!q.exec(line)) { + qDebug() << q.lastError(); + if (!skip_errors) + return false; + } + } + ls = le + 1; + le = text.indexOf(';', ls); + } + db.commit(); + return true; +} + + +bool SQLTableWidget::executeScriptFile(const QString & file, QSqlDatabase db, bool skip_errors, bool sqlite) { + QFile f(_dir + file); + if (!f.open(QIODevice::ReadOnly)) { + qDebug() << "Can`t open file" << file << "!"; + return false; + } + QString pd = _dir; + _dir = QFileInfo(f).absolutePath() + "/"; + QByteArray ba = f.readAll(); + bool ok = executeScript(QString::fromUtf8(ba.data(), ba.size()), db, skip_errors, sqlite); + f.close(); + _dir = pd; + return ok; +} + + +void SQLTableWidget::column_triggered(bool on) { + setColumnVisible(((QAction * )sender())->data().toInt(), on); +} + + +void SQLTableWidget::header_sectionResized(int logicalIndex, int oldSize, int newSize) { + column_news[mapColumn(logicalIndex)]->setFixedWidth(newSize); + column_filters[mapColumn(logicalIndex)]->setFixedWidth(newSize); +} + + +void SQLTableWidget::header_sortIndicatorChanged(int logicalIndex, Qt::SortOrder order) { + updateTable(); +} + + +bool SQLTableWidget::connectToDatabase(const QString & config, const QString & conn_name) { + bool ok = true; + { + QPIConfig conf(config, QIODevice::ReadOnly, QPIConfig::Config); + if (!conf.isOpen()) + ok = false; + else { + QSqlDatabase base = QSqlDatabase::addDatabase(conf.getValue("driver", "QMYSQL").stringValue(), conn_name); + if (!base.isValid()) { + qDebug() << "[QSqlDatabase::addDatabase] Error:" << base.lastError(); + ok = false; + } else { + base.setHostName(conf.getValue("host", "").stringValue()); + base.setPort(conf.getValue("port", -1)); + base.setDatabaseName(conf.getValue("database", "").stringValue()); + if (!base.open(conf.getValue("login", "").stringValue(), conf.getValue("password", "").stringValue())) { + qDebug() << "[QSqlDatabase::open] Error:" << base.lastError(); + ok = false; + } + } + } + } + if (!ok) + QSqlDatabase::removeDatabase(conn_name); + /*QSqlQuery q; + QString dbname = conf.getValue("database", "").stringValue(); + bool dbex = false; + if (!q.exec("SHOW DATABASES;")) { + qDebug() << "[SHOW DATABASES]" << q.lastError(); + return false; + } + while (q.next()) + if (q.value(0) == dbname) + {dbex = true; break;} + if (!dbex) { + if (!q.exec("CREATE DATABASE " + dbname + ";")) { + qDebug() << "[CREATE DATABASE]" << q.lastError(); + return false; + } + } + if (!q.exec("USE " + dbname + ";")) { + qDebug() << "[USE]" << q.lastError(); + return false; + }*/ + return ok; +} + + +QTableView * SQLTableWidget::tableView() { + return ui->view; +} + + +bool SQLTableWidget::lineNewVisible() const { + return ui->widgetNew->isVisibleTo(ui->pageTable); +} + + +bool SQLTableWidget::lineFilterVisible() const { + return ui->widgetFilter->isVisibleTo(ui->pageTable); +} + + +QSqlRecord SQLTableWidget::currentRecord() const { + if (model) return model->record(ui->view->currentIndex().row()); + return QSqlRecord(); +} + + +void SQLTableWidget::setTableVisible(bool on) { + ui->stackedWidget->setCurrentIndex(on ? 1 : 0); +} + + +void SQLTableWidget::setLineNewVisible(bool on) { + ui->widgetNew->setVisible(on); + ui->buttonAdd->setVisible(on); +} + + +void SQLTableWidget::setLineFilterVisible(bool on) { + ui->widgetFilter->setVisible(on); + ui->buttonFilterConfig->setVisible(on); +} + + +void SQLTableWidget::setReadOnly(bool yes) { + read_only = yes; + ui->scrollAreaNew->setDisabled(yes); + ui->buttonAdd->setDisabled(yes); +} + + +void SQLTableWidget::scrolled(int value) { + ui->scrollAreaNew->horizontalScrollBar()->setValue(value); + ui->scrollAreaFilter->horizontalScrollBar()->setValue(value); +} diff --git a/qad/sql_table/sql_table_widget.h b/qad/sql_table/sql_table_widget.h new file mode 100644 index 0000000..8dd80f4 --- /dev/null +++ b/qad/sql_table/sql_table_widget.h @@ -0,0 +1,334 @@ +#ifndef MYSQLTABLE_H +#define MYSQLTABLE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qpiconfig.h" + + +struct ColumnProperties { + enum DataType {Unknown, Int, Float, Chars, Text, Binary, Date, Time, DateTime}; + ColumnProperties(const QString & table_, const QString & type_, const QString & name_, const QString & def_, bool auto_, bool prim_, bool option_); + bool isRelation() const {return (!relation_key.isEmpty() && !relation_column.isEmpty());} + QString shortName() const {if (!isRelation()) return name; return relation_column;} + QString fullName() const {if (!isRelation()) return table + "." + name; return (relation_table.isEmpty() ? "" : relation_table + ".") + relation_column;} + DataType getType() const {if (!isRelation()) return type; return relation_type;} + static DataType typeFromString(const QString & n); + + DataType type; + int size; + bool auto_increment; + bool primary; + bool optional; + bool visible; + bool is_text; + QString table; + QString name; + QString relation_table; + QString relation_key; + QString relation_column; + QList > relation_list; // + DataType relation_type; + int key_column; + QString def; +}; + + + + +struct TableColumns { + int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];} + QVector column_indexes; + QList columns; +}; + + + + +class SQLQueryModel: public QSqlQueryModel { + Q_OBJECT +public: + explicit SQLQueryModel(QString & t, QString & conn, QList & cp, QVector & ci, QObject* parent = 0): QSqlQueryModel(parent), table_(t), column_props(cp), column_indexes(ci), conn_name(conn) {;} +protected: + virtual Qt::ItemFlags flags(const QModelIndex & ) const {return (Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);} + virtual QVariant data(const QModelIndex & item, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex & index, const QVariant& value, int role = Qt::EditRole); + int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];} + QString & table_; + QList & column_props; + QVector & column_indexes; + QString & conn_name; +signals: + void updateTable(bool save_selection); + void tableChanged(); +}; + + + + +class SQLUniEdit: public QWidget { + Q_OBJECT +public: + explicit SQLUniEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent = 0); + ~SQLUniEdit() {for (int i = 0; i < w_.size(); ++i) deleteW(*w_[i]);} + void setProp(const ColumnProperties & p); + QString value(bool for_insert = false); + void clear() {setValue(QVariant());} +private: + void deleteW(QWidget * w) {if (w != 0) delete w;} + void resizeW(QWidget * w) {if (w != 0) w->setGeometry(QRect(0, 0, width(), height()));} + void resizeEvent(QResizeEvent * ) {for (int i = 0; i < w_.size(); ++i) resizeW(*w_[i]);} + bool eventFilter(QObject * o, QEvent * e); + QLineEdit * wtext; + QSpinBox * wint; + QDoubleSpinBox * wfloat; + QDateEdit * wdate; + QTimeEdit * wtime; + QDateTimeEdit * wdatetime; + QComboBox * wrelation; + QList w_; + ColumnProperties prop_; + QString connection_name; +private slots: + void value_text(QString value) {valueChanged(value);} + void value_int(int value) {valueChanged(value);} + void value_float(double value) {valueChanged(value);} + void value_date(QDate value) {valueChanged(value);} + void value_time(QTime value) {valueChanged(value);} + void value_datetime(QDateTime value) {valueChanged(value);} +public slots: + void setValue(const QVariant & value); + void updateRelation(); +signals: + void valueChanged(const QVariant & ); +}; + + + + +class SQLNewEdit: public QWidget { + Q_OBJECT + friend class SQLTableWidget; +public: + explicit SQLNewEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent = 0); + ~SQLNewEdit() {delete line; delete check;} + void setProp(const ColumnProperties & p); + bool isEnabled() const {return check->isChecked();} + QString value() const {return line->value(true);} + void clear() {line->clear();} +private: + ColumnProperties prop_; + SQLUniEdit * line; + QCheckBox * check; +}; + + + + +class SQLFilterEdit: public QWidget { + Q_OBJECT + friend class SQLTableWidget; +public: + explicit SQLFilterEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent = 0); + ~SQLFilterEdit() {delete line; delete combo;} + void setProp(const ColumnProperties & p) {prop_ = p; line->setProp(p);} + QString filter() const; + bool isEmpty() const {return line->value().isEmpty() || combo->currentIndex() == 0;} + void clear(); +private: + ColumnProperties prop_; + SQLUniEdit * line; + QComboBox * combo; +private slots: + void value_changed() {if (combo->currentIndex() == 0) combo->setCurrentIndex(prop_.is_text ? 2 : 1);} +public slots: +signals: + void filterChanged(); +}; + + + + +class SQLItemDelegate: public QStyledItemDelegate { + Q_OBJECT +public: + explicit SQLItemDelegate(QList & cp, QVector & ci, bool & ro, const QString & conn_name, QObject * parent = 0); + ~SQLItemDelegate() {;} +private: + QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const; + QString displayText(const QVariant & value, const QLocale & locale) const; + void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const; + int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];} + void setConnectionName(const QString & conn_name) {connection_name = conn_name;} + QList & column_props; + QVector & column_indexes; + bool & read_only; + QString connection_name; +private slots: +public slots: +signals: +}; + + + + +namespace Ui { + class SQLTableWidget; +}; + + +class SQLTableWidget: public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString tableName READ tableName WRITE setTableName) + Q_PROPERTY(QString connectionName READ connectionName WRITE setConnectionName) + Q_PROPERTY(bool lineNewVisible READ lineNewVisible WRITE setLineNewVisible) + Q_PROPERTY(bool lineFilterVisible READ lineFilterVisible WRITE setLineFilterVisible) + Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly) + friend class SQLItemDelegate; + friend class SQLUniEdit; +public: + SQLTableWidget(QWidget * parent = 0); + virtual ~SQLTableWidget(); + + bool isTableExists() const {return table_opened;} + const QString & tableName() const {return table_;} + + QTableView * tableView(); + bool readOnly() const {return read_only;} + + const ColumnProperties * columnProperty(int index) const {if (index < 0 || index >= column_props.count()) return 0; return &(column_props[index]);} + const ColumnProperties * columnProperty(const QString & name) const {return columnProperty(columnByName(name));} + const QList & columnProperties() const {return column_props;} + QStringList columnNames() const {QStringList sl; foreach (const ColumnProperties & i, column_props) sl << i.name; return sl;} + int columnsCount() const {return column_props.size();} + bool isColumnVisible(int ind) {if (!columnExists(ind)) return false; return column_props[ind].visible;} + bool isColumnVisible(const QString & name) {if (!columnExists(name)) return false; return column_props[columnByName(name)].visible;} + bool isColumnHidden(int ind) {if (!columnExists(ind)) return true; return !column_props[ind].visible;} + bool isColumnHidden(const QString & name) {if (!columnExists(name)) return true; return !column_props[columnByName(name)].visible;} + void setColumnVisible(int ind, bool visible); + void setColumnVisible(const QString & name, bool visible) {col_vis[name] = visible; setColumnVisible(columnByName(name), visible);} + void setColumnHidden(int ind, bool hidden) {setColumnVisible(ind, !hidden);} + void setColumnHidden(const QString & name, bool hidden) {col_vis[name] = !hidden; setColumnVisible(columnByName(name), !hidden);} + + bool lineNewVisible() const; + bool lineFilterVisible() const; + bool addRelation(const QString & this_column, const QString & other_table, const QString & other_key, const QString & other_column); + void addTranslation(const QString & file); + void addFixedColumnTranslation(const QString & col_name, const QString & col_tr, const QString & col_tt = QString()); + void fetchMore() {if (model) model->fetchMore();} + void fetchAll() {if (model) while (model->canFetchMore()) model->fetchMore();} + + void setAdditionalActions(QList a); + + QSqlRecord headerRecord() const {if (model) return model->record(); return QSqlRecord();} + QSqlRecord currentRecord() const; + + void setCustomQuery(const QString & q); + void setCustomColumnNames(const QStringList & cn) {custom_col_names = cn; updateTable();} + + static bool isTableExists(const QString & table, const QString & conn_name = QLatin1String(QSqlDatabase::defaultConnection)) {return QSqlDatabase::database(conn_name).tables().contains(table, Qt::CaseInsensitive);} + + static bool executeScript(const QString & text, QSqlDatabase db = QSqlDatabase::database(), bool skip_errors = false, bool sqlite = false); + static bool executeScriptFile(const QString & file, QSqlDatabase db = QSqlDatabase::database(), bool skip_errors = false, bool sqlite = false); + + static bool isConnectedToDatabase(const QString & conn_name = QLatin1String(QSqlDatabase::defaultConnection)) {return QSqlDatabase::database(conn_name, false).isOpen();} + static bool connectToDatabase(const QString & config, const QString & conn_name = QLatin1String(QSqlDatabase::defaultConnection)); + + QString connectionName() const {return connection_name;} + +private: + static QString preprocessScript(QString text); + + bool eventFilter(QObject * o, QEvent * e); + void timerEvent(QTimerEvent * ); + void stopTimer() {if (timer != 0) killTimer(timer); timer = 0;} + bool checkTable(); + QStringList getTableColumns(const QString & t); + QString getColumnType(const QString & t, const QString & c); + static QList > getColumnValues(const QString & t, const QString & k, const QString & c, const QString & conn_name); + void setTableVisible(bool on); + int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];} + int columnByName(const QString & name) const {for (int i = 0; i < column_props.size(); ++i) if (column_props[i].name == name) return i; return -1;} + bool columnExists(int index) const {return (index >= 0 && index < column_props.size());} + bool columnExists(const QString & name) const {for (int i = 0; i < column_props.size(); ++i) if (column_props[i].name == name) return true; return false;} + QPair trColumn(const QString & n); + QString tableNames(); + QString columnNames(); + QString columnFilters(); + QString columnRelations(); + + Ui::SQLTableWidget * ui; + QString table_, cquery, custom_query; + QStringList custom_col_names; + SQLQueryModel * model; + //QAction act_add, act_del; + QList column_props; + QList column_news; + QList column_filters; + QVector column_indexes; + QStringList wait_rels; + QMenu popup_menu, popup_col, popup_filter; + QTime tm; + QActionGroup filters_group; + QAction * action_del; + QList add_actions; + QMap > translates, fixed_translates; + QMap col_vis; + int timer; + bool filters_active, table_opened, read_only, first_update; + static QString _dir; + QPoint pp; + QString connection_name; + + +public slots: + void setTableName(const QString & t); + void setLineNewVisible(bool on); + void setLineFilterVisible(bool on); + void setReadOnly(bool yes); + void updateTable(bool save_selection = false); + void setConnectionName(const QString &conn_name); + +private slots: + void on_buttonAdd_clicked(); + void on_actionFiltersClear_triggered(); + void on_view_clicked(const QModelIndex & index); + void header_sectionResized(int logicalIndex, int oldSize, int newSize); + void header_sortIndicatorChanged(int logicalIndex, Qt::SortOrder order); + void scrolled(int value); + void del_triggered(); + void column_triggered(bool on); + +signals: + void rowClicked(int row); + void recordClicked(QSqlRecord rec); + void selectionChanged(); + void tableChanged(); + +}; + + +#endif // MYSQLTABLE_H diff --git a/qad/sql_table/sql_table_widget.ui b/qad/sql_table/sql_table_widget.ui new file mode 100644 index 0000000..ae856e7 --- /dev/null +++ b/qad/sql_table/sql_table_widget.ui @@ -0,0 +1,310 @@ + + + SQLTableWidget + + + + 0 + 0 + 445 + 422 + + + + SQLTableWidget + + + + 0 + + + + + + + 0 + + + + + Table doesn`t exists! + + + Qt::AlignCenter + + + + + + + + + 0 + + + 2 + + + + + + 0 + + + 0 + + + + + + 16 + 0 + + + + :/icons/edit-table-insert-row-below.png + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 401 + 87 + + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 1 + 10 + + + + + + + + + + + + + + + Add record + + + + :/icons/list-add.png:/icons/list-add.png + + + + 16 + 16 + + + + + + + + + 0 + + + 0 + + + + + + 16 + 0 + + + + :/icons/edit-find.png + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 401 + 87 + + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 1 + 10 + + + + + + + + + + + + + + + Configure filters + + + + :/icons/configure.png:/icons/configure.png + + + + 16 + 16 + + + + QToolButton::InstantPopup + + + + + + + true + + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + true + + + true + + + 24 + + + + + + + + + + + + :/icons/edit-clear.png:/icons/edit-clear.png + + + Clear + + + + + true + + + Operator AND + + + Operator AND + + + + + true + + + Operator OR + + + Operator OR + + + + + + diff --git a/qad/touch_widgets/CMakeLists.txt b/qad/touch_widgets/CMakeLists.txt new file mode 100644 index 0000000..3d35da3 --- /dev/null +++ b/qad/touch_widgets/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) +qad_project(touch_widgets "${LIBS}") diff --git a/qad/touch_widgets/plugin/CMakeLists.txt b/qad/touch_widgets/plugin/CMakeLists.txt new file mode 100644 index 0000000..879009e --- /dev/null +++ b/qad/touch_widgets/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(touch_widgets "") diff --git a/touch_widgets/plugin/touch_widgets.cpp b/qad/touch_widgets/plugin/touch_widgets.cpp similarity index 100% rename from touch_widgets/plugin/touch_widgets.cpp rename to qad/touch_widgets/plugin/touch_widgets.cpp diff --git a/touch_widgets/plugin/touch_widgets.h b/qad/touch_widgets/plugin/touch_widgets.h similarity index 100% rename from touch_widgets/plugin/touch_widgets.h rename to qad/touch_widgets/plugin/touch_widgets.h diff --git a/touch_widgets/plugin/touchbuttframeplugin.cpp b/qad/touch_widgets/plugin/touchbuttframeplugin.cpp similarity index 100% rename from touch_widgets/plugin/touchbuttframeplugin.cpp rename to qad/touch_widgets/plugin/touchbuttframeplugin.cpp diff --git a/touch_widgets/plugin/touchbuttframeplugin.h b/qad/touch_widgets/plugin/touchbuttframeplugin.h similarity index 100% rename from touch_widgets/plugin/touchbuttframeplugin.h rename to qad/touch_widgets/plugin/touchbuttframeplugin.h diff --git a/touch_widgets/plugin/touchbuttonplugin.cpp b/qad/touch_widgets/plugin/touchbuttonplugin.cpp similarity index 100% rename from touch_widgets/plugin/touchbuttonplugin.cpp rename to qad/touch_widgets/plugin/touchbuttonplugin.cpp diff --git a/touch_widgets/plugin/touchbuttonplugin.h b/qad/touch_widgets/plugin/touchbuttonplugin.h similarity index 100% rename from touch_widgets/plugin/touchbuttonplugin.h rename to qad/touch_widgets/plugin/touchbuttonplugin.h diff --git a/touch_widgets/plugin/touchsliderplugin.cpp b/qad/touch_widgets/plugin/touchsliderplugin.cpp similarity index 100% rename from touch_widgets/plugin/touchsliderplugin.cpp rename to qad/touch_widgets/plugin/touchsliderplugin.cpp diff --git a/touch_widgets/plugin/touchsliderplugin.h b/qad/touch_widgets/plugin/touchsliderplugin.h similarity index 100% rename from touch_widgets/plugin/touchsliderplugin.h rename to qad/touch_widgets/plugin/touchsliderplugin.h diff --git a/touch_widgets/touch_bar.h b/qad/touch_widgets/touch_bar.h similarity index 100% rename from touch_widgets/touch_bar.h rename to qad/touch_widgets/touch_bar.h diff --git a/qad/touch_widgets/touch_widgets.qrc b/qad/touch_widgets/touch_widgets.qrc new file mode 100644 index 0000000..cfb77f1 --- /dev/null +++ b/qad/touch_widgets/touch_widgets.qrc @@ -0,0 +1,7 @@ + + + ../icons/touchbuttframe.png + ../icons/touchbutton.png + ../icons/touchslider.png + + diff --git a/touch_widgets/touchbuttframe.cpp b/qad/touch_widgets/touchbuttframe.cpp similarity index 100% rename from touch_widgets/touchbuttframe.cpp rename to qad/touch_widgets/touchbuttframe.cpp diff --git a/touch_widgets/touchbuttframe.h b/qad/touch_widgets/touchbuttframe.h similarity index 100% rename from touch_widgets/touchbuttframe.h rename to qad/touch_widgets/touchbuttframe.h diff --git a/touch_widgets/touchbutton.cpp b/qad/touch_widgets/touchbutton.cpp similarity index 100% rename from touch_widgets/touchbutton.cpp rename to qad/touch_widgets/touchbutton.cpp diff --git a/touch_widgets/touchbutton.h b/qad/touch_widgets/touchbutton.h similarity index 100% rename from touch_widgets/touchbutton.h rename to qad/touch_widgets/touchbutton.h diff --git a/touch_widgets/touchslider.cpp b/qad/touch_widgets/touchslider.cpp similarity index 100% rename from touch_widgets/touchslider.cpp rename to qad/touch_widgets/touchslider.cpp diff --git a/touch_widgets/touchslider.h b/qad/touch_widgets/touchslider.h similarity index 100% rename from touch_widgets/touchslider.h rename to qad/touch_widgets/touchslider.h diff --git a/touch_widgets/touchslider.ui b/qad/touch_widgets/touchslider.ui similarity index 100% rename from touch_widgets/touchslider.ui rename to qad/touch_widgets/touchslider.ui diff --git a/qad/utils/CMakeLists.txt b/qad/utils/CMakeLists.txt new file mode 100644 index 0000000..c799395 --- /dev/null +++ b/qad/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) +qad_project(utils "${LIBS}") diff --git a/qad/utils/chunkstream.cpp b/qad/utils/chunkstream.cpp new file mode 100644 index 0000000..8c30120 --- /dev/null +++ b/qad/utils/chunkstream.cpp @@ -0,0 +1,38 @@ +#include "chunkstream.h" + + +void ChunkStream::setSource(const QByteArray & data) { + stream_.setVersion(QDataStream::Qt_4_8); + data_ = const_cast(&data); + _init(); +} + + +void ChunkStream::setSource(QByteArray * data) { + stream_.setVersion(QDataStream::Qt_4_8); + data_ = (data ? data : &tmp_data); + _init(); +} + + +void ChunkStream::setSource(QDataStream & str) { + stream_.setVersion(QDataStream::Qt_4_8); + str >> tmp_data; + data_ = &tmp_data; + _init(); +} + + +ChunkStream::~ChunkStream() { + +} + + +void ChunkStream::_init() { + last_id = -1; + last_data.clear(); + buffer.close(); + buffer.setBuffer(data_); + buffer.open(QIODevice::ReadWrite); + stream_.setDevice(&buffer); +} diff --git a/qad/utils/chunkstream.h b/qad/utils/chunkstream.h new file mode 100644 index 0000000..108fd0b --- /dev/null +++ b/qad/utils/chunkstream.h @@ -0,0 +1,58 @@ +#ifndef CHUNKSTREAM_H +#define CHUNKSTREAM_H + +#include +#include +#include + + +class ChunkStream +{ +public: + ChunkStream(const QByteArray & data) {setSource(data);} + ChunkStream(QDataStream & str) {setSource(str);} + ChunkStream(QByteArray * data = 0) {setSource(data);} + ~ChunkStream(); + + template + struct Chunk { + Chunk(int i, const T & d): id(i), data(d) {} + int id; + T data; + }; + template static Chunk chunk(int id, const T & data) {return Chunk(id, data);} + + void setSource(const QByteArray & data); + void setSource(QDataStream & str); + void setSource(QByteArray * data); + QDataStream & dataStream() {return stream_;} + QByteArray data() const {return tmp_data;} + bool atEnd() const {return stream_.atEnd();} + + int read() {stream_ >> last_id >> last_data; return last_id;} + int getID() {return last_id;} + template + T getData() const {T ret; QDataStream s(last_data); s.setVersion(QDataStream::Qt_4_8); s >> ret; return ret;} + template + void get(T & v) const {v = getData();} +private: + void _init(); + + int last_id; + QByteArray * data_, last_data, tmp_data; + QBuffer buffer; + QDataStream stream_; + +}; + +template +ChunkStream & operator <<(ChunkStream & s, const ChunkStream::Chunk & c) { + QByteArray ba; + QDataStream bas(&ba, QIODevice::WriteOnly); + bas.setVersion(QDataStream::Qt_4_8); + bas << c.data; + s.dataStream() << c.id << ba; + return s; +} + +#endif // CHUNKSTREAM_H diff --git a/qad/utils/plugin/CMakeLists.txt b/qad/utils/plugin/CMakeLists.txt new file mode 100644 index 0000000..058341f --- /dev/null +++ b/qad/utils/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(utils "") diff --git a/qad/utils/plugin/qad_utils.cpp b/qad/utils/plugin/qad_utils.cpp new file mode 100644 index 0000000..1f0505a --- /dev/null +++ b/qad/utils/plugin/qad_utils.cpp @@ -0,0 +1,13 @@ +//#include "qpiconfigplugin.h" +#include "qad_utils.h" + +QADUtils::QADUtils(QObject * parent): QObject(parent) { + //m_widgets.append(new QPIConfigPlugin(this)); +} + + +QList QADUtils::customWidgets() const { + return m_widgets; +} + +Q_EXPORT_PLUGIN2(qad_utils_plugin, QADUtils) diff --git a/qad/utils/plugin/qad_utils.h b/qad/utils/plugin/qad_utils.h new file mode 100644 index 0000000..046be18 --- /dev/null +++ b/qad/utils/plugin/qad_utils.h @@ -0,0 +1,21 @@ +#ifndef QAD_UTILS_H +#define QAD_UTILS_H + +#include +#include + +class QADUtils: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit QADUtils(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; + +}; + +#endif // QAD_UTILS_H diff --git a/qad/utils/propertystorage.cpp b/qad/utils/propertystorage.cpp new file mode 100644 index 0000000..effc2c1 --- /dev/null +++ b/qad/utils/propertystorage.cpp @@ -0,0 +1,148 @@ +#include "propertystorage.h" +#include + + +bool PropertyStorage::isPropertyExists(const QString & _name) const { + for (int i = 0; i < props.size(); ++i) + if (props[i].name == _name) + return true; + return false; +} + + +void PropertyStorage::addProperty(const PropertyStorage::Property & p) { + for (int i = 0; i < props.size(); ++i) + if (props[i].name == p.name) { + props[i] = p; + return; + } + props << p; +} + + +void PropertyStorage::removeProperty(const QString & _name) { + for (int i = 0; i < props.size(); ++i) + if (props[i].name == _name) { + props.removeAt(i); + return; + } +} + + +void PropertyStorage::removePropertiesByFlag(int flag) { + for (int i = 0; i < props.size(); ++i) + if ((props[i].flags & flag) == flag) { + props.removeAt(i); + --i; + } +} + + +void PropertyStorage::updateProperties(const QList & properties_, int flag_ignore) { + QVariantMap values; + foreach (const PropertyStorage::Property & p, props) + if (((p.flags & flag_ignore) != flag_ignore) || (flag_ignore == 0)) + values[p.name] = p.value; + props = properties_; + for (int i = 0; i < props.size(); ++i) { + PropertyStorage::Property & p(props[i]); + if (values.contains(p.name)) { + QVariant pv = values[p.name]; + if (pv.userType() == p.value.userType()) + p.value = pv; + } + } +} + + +PropertyStorage::Property PropertyStorage::propertyByName(const QString & name) const { + foreach (const Property & p, props) + if (p.name == name) + return p; + return Property(); +} + + +QVariant PropertyStorage::propertyValueByName(const QString & name) const { + foreach (const Property & p, props) + if (p.name == name) + return p.value; + return QVariant(); +} + + +void PropertyStorage::setPropertyValue(const QString & name, const QVariant & value) { + for (int i = 0; i < props.size(); ++i) + if (props[i].name == name) { + props[i].value = value; + return; + } +} + + +void PropertyStorage::setPropertyComment(const QString & name, const QString & comment) { + for (int i = 0; i < props.size(); ++i) + if (props[i].name == name) { + props[i].comment = comment; + return; + } +} + + +void PropertyStorage::setPropertyFlags(const QString & name, int flags) { + for (int i = 0; i < props.size(); ++i) + if (props[i].name == name) { + props[i].flags = flags; + return; + } +} + + +PropertyStorage::Property PropertyStorage::parsePropertyLine(QString l) { + PropertyStorage::Property ret; + QString pn, pc, pt("s"), pv; + if (l.contains('#')) { + int i = l.indexOf('#'); + pn = l.left(i).trimmed(); + pc = l.right(l.length() - i - 1).trimmed(); + } else { + if (l.contains('(')) { + int bs = l.indexOf('('), be = l.indexOf(')'); + if (be > 0) { + pc = l.mid(bs + 1, be - bs - 1).trimmed(); + l.remove(bs, be - bs + 1); + } else { + pc = l.right(l.length() - bs - 1).trimmed(); + l = l.left(bs); + } + } + pn = l.trimmed(); + } + if (!pc.isEmpty()) { + pt = pc.left(1); + pc = pc.remove(0, 1).trimmed(); + } + if (pn.contains('=')) { + int i = pn.indexOf('='); + pv = pn.right(pn.length() - i - 1).trimmed(); + pn.truncate(i); + pn = pn.trimmed(); + } + ret.name = pn; + ret.comment = pc; + ret.value = QVariant(typeFromLetter(pt)); + if (!pv.isEmpty()) { + //qDebug() << "set value !" << pv; + switch (ret.value.type()) { + case QVariant::Bool: pv = pv.toLower(); ret.value = (pv == "on" || pv == "true" || pv == "enable" || pv == "enabled" || pv.toInt() > 0 ? true : false); break; + case QVariant::Int: ret.value = pv.toInt(); break; + case QVariant::UInt: ret.value = pv.toUInt(); break; + case QVariant::LongLong: ret.value = pv.toLongLong(); break; + case QVariant::ULongLong: ret.value = pv.toULongLong(); break; + case QVariant::Double: ret.value = pv.toDouble(); break; + case QVariant::Color: ret.value = QColor(pv); break; + default: ret.value = pv; break; + }; + } + return ret; +} diff --git a/qad/utils/propertystorage.h b/qad/utils/propertystorage.h new file mode 100644 index 0000000..3fa515f --- /dev/null +++ b/qad/utils/propertystorage.h @@ -0,0 +1,107 @@ +#ifndef PROPERTYSTORAGE_H +#define PROPERTYSTORAGE_H + +#include "qad_types.h" + + +class PropertyStorage { +public: + PropertyStorage() {} + + struct Property { + Property(const QString & n = QString(), const QString & c = QString(), const QVariant & v = QVariant(), int f = 0): + name(n), comment(c), value(v), flags(f) {} + QString name; + QString comment; + QVariant value; + int flags; + }; + + PropertyStorage(const QList & pl) {props = pl;} + + typedef QList::const_iterator const_iterator; + typedef QList::iterator iterator; + + iterator begin() {return props.begin();} + const_iterator begin() const {return props.begin();} + const_iterator constBegin() const {return props.constBegin();} + iterator end() {return props.end();} + const_iterator end() const {return props.end();} + const_iterator constEnd() const {return props.constEnd();} + + int count() const {return props.count();} + int length() const {return props.length();} + int size() const {return props.size();} + bool isEmpty() const {return props.isEmpty();} + Property & first() {return props.first();} + const Property & first() const {return props.first();} + Property & front() {return props.front();} + const Property & front() const {return props.front();} + Property & last() {return props.last();} + const Property & last() const {return props.last();} + Property & back() {return props.back();} + const Property & back() const {return props.back();} + void removeFirst() {props.removeFirst();} + void removeLast() {props.removeLast();} + void removeAt(int i) {props.removeAt(i);} + Property value(int i) const {return props.value(i);} + Property value(int i, const Property & defaultValue) const {return props.value(i, defaultValue);} + void clear() {props.clear();} + + PropertyStorage copy() const {return PropertyStorage(*this);} + int propertiesCount() const {return props.size();} + QList & properties() {return props;} + const QList & properties() const {return props;} + const PropertyStorage & propertyStorage() const {return *this;} + bool isPropertyExists(const QString & _name) const; + void clearProperties() {props.clear();} + void addProperty(const Property & p); + void addProperty(const QString & _name, const QVariant & _def_value, const QString & _comment = QString(), int _flags = 0) {addProperty(Property(_name, _comment, _def_value, _flags));} + void removeProperty(const QString & _name); + void removePropertiesByFlag(int flag); + void updateProperties(const QList & properties_, int flag_ignore = 0); + Property propertyByName(const QString & name) const; + QVariant propertyValueByName(const QString & name) const; + void setPropertyValue(const QString & name, const QVariant & value); + void setPropertyComment(const QString & name, const QString & comment); + void setPropertyFlags(const QString & name, int flags); + + PropertyStorage & operator <<(const PropertyStorage::Property & p) {props << p; return *this;} + PropertyStorage & operator <<(const QList & p) {props << p; return *this;} + PropertyStorage & operator <<(const PropertyStorage & p) {props << p.props; return *this;} + Property & operator[](int i) {return props[i];} + const Property & operator[](int i) const {return props[i];} + + static Property parsePropertyLine(QString l); + +protected: + QList props; + +}; + +inline QDebug operator <<(QDebug s, const PropertyStorage::Property & p) {s.nospace() << p.name << " (0x" << QString::number(p.flags, 16) << ") = " << p.value; return s.space();} + +inline QDataStream & operator <<(QDataStream & s, const PropertyStorage & p) {s << p.properties(); return s;} +inline QDataStream & operator >>(QDataStream & s, PropertyStorage & p) {s >> p.properties(); return s;} + +inline QDataStream & operator <<(QDataStream & s, const PropertyStorage::Property & p) { + ChunkStream cs; + cs << cs.chunk(1, p.name) << cs.chunk(2, p.comment) << cs.chunk(3, p.value) << cs.chunk(4, p.flags); + s << cs.data(); + return s; +} +inline QDataStream & operator >>(QDataStream & s, PropertyStorage::Property & p) { + ChunkStream cs(s); + while (!cs.atEnd()) { + switch (cs.read()) { + case 1: cs.get(p.name); break; + case 2: cs.get(p.comment); break; + case 3: cs.get(p.value); break; + case 4: cs.get(p.flags); break; + } + } + return s; +} + + +#endif // PROPERTYSTORAGE_H diff --git a/qad/utils/qad_types.cpp b/qad/utils/qad_types.cpp new file mode 100644 index 0000000..76a5394 --- /dev/null +++ b/qad/utils/qad_types.cpp @@ -0,0 +1,123 @@ +#include "qad_types.h" + + +__QADTypesRegistrator__ __registrator__; + + +int QAD::Enum::selectedValue() const { + foreach (const Enumerator & e, enum_list) + if (e.name == selected) + return e.value; + return 0; +} + + +bool QAD::Enum::selectValue(int v) { + foreach (const Enumerator & e, enum_list) + if (e.value == v) { + selected = e.name; + return true; + } + return false; +} + + +bool QAD::Enum::selectName(const QString & n) { + foreach (const Enumerator & e, enum_list) + if (e.name == n) { + selected = e.name; + return true; + } + return false; +} + + +int QAD::Enum::value(const QString & n) const { + foreach (const Enumerator & e, enum_list) + if (e.name == n) + return e.value; + return 0; +} + + +QString QAD::Enum::name(int v) const { + foreach (const Enumerator & e, enum_list) + if (e.value == v) + return e.name; + return QString(); +} + + +QList QAD::Enum::values() const { + QList ret; + foreach (const Enumerator & e, enum_list) + ret << e.value; + return ret; +} + + +QStringList QAD::Enum::names() const { + QStringList ret; + foreach (const Enumerator & e, enum_list) + ret << e.name; + return ret; +} + + +QAD::Enum & QAD::Enum::operator <<(const QAD::Enumerator & v) { + enum_list << v; + return *this; +} + + +QAD::Enum & QAD::Enum::operator <<(const QString & v) { + enum_list << Enumerator(enum_list.size(), v); + return *this; +} + + +QAD::Enum & QAD::Enum::operator <<(const QStringList & v) { + foreach (const QString & s, v) + (*this) << s; + return *this; +} + + + + +QVariant::Type typeFromLetter(const QString & l) { + if (l.isEmpty()) return QVariant::String; + QString ft = l.left(1); + if (ft == "l") return QVariant::StringList; + if (ft == "b") return QVariant::Bool; + if (ft == "n") return QVariant::Int; + if (ft == "f") return QVariant::Double; + if (ft == "c") return QVariant::Color; + if (ft == "r") return QVariant::Rect; + if (ft == "a") return QVariant::RectF; + if (ft == "p") return QVariant::Point; + if (ft == "v") return QVariant::PointF; + if (ft == "e") return (QVariant::Type)qMetaTypeId(); + if (ft == "F") return (QVariant::Type)qMetaTypeId(); + if (ft == "D") return (QVariant::Type)qMetaTypeId(); + return QVariant::String; +} + + +QString uniqueName(QString n, const QStringList & names) { + if (!names.contains(n)) + return n; + QString num; + while (!n.isEmpty()) { + if (n.right(1)[0].isDigit()) { + num.push_front(n.right(1)); + n.chop(1); + } else break; + } + if (!n.endsWith('_')) n += '_'; + int in = num.toInt() + 1; + QString nn = n + QString::number(in).rightJustified(3, '0'); + while (names.contains(nn)) + nn = n + QString::number(++in).rightJustified(3, '0'); + return nn; +} diff --git a/qad/utils/qad_types.h b/qad/utils/qad_types.h new file mode 100644 index 0000000..e3815e4 --- /dev/null +++ b/qad/utils/qad_types.h @@ -0,0 +1,115 @@ +#ifndef QAD_TYPES_H +#define QAD_TYPES_H + +#include +#include +#include +#include +#include +#include +#include "chunkstream.h" + + +namespace QAD { + + struct Enumerator { + Enumerator(int v = 0, const QString & n = QString()): value(v), name(n) {} + int value; + QString name; + }; + + struct Enum { + Enum(const QString & n = QString()): enum_name(n) {} + QString toString() const {return selected;} // obsolete + int selectedValue() const; + QString selectedName() const {return selected;} + bool selectValue(int v); + bool selectName(const QString & n); + int value(const QString & n) const; + QString name(int v) const; + QList values() const; + QStringList names() const; + QString enum_name; + QString selected; + QList enum_list; + Enum & operator <<(const Enumerator & v); + Enum & operator <<(const QString & v); + Enum & operator <<(const QStringList & v); + }; + + struct File { + File(const QString & p = QString(), const QString & f = QString(), bool abs = false): file(p), filter(f), is_abs(abs) {} + QString toString() const {return file;} + QString file; + QString filter; + bool is_abs; + }; + + struct Dir { + Dir(const QString & d = QString(), bool abs = false): dir(d), is_abs(abs) {} + QString toString() const {return dir;} + QString dir; + bool is_abs; + }; + +} + +Q_DECLARE_METATYPE(QAD::Enumerator) +inline QDataStream & operator <<(QDataStream & s, const QAD::Enumerator & v) {s << v.value << v.name; return s;} +inline QDataStream & operator >>(QDataStream & s, QAD::Enumerator & v) {s >> v.value >> v.name; return s;} +inline QDebug operator <<(QDebug s, const QAD::Enumerator & v) {s.nospace() << v.name << "(" << v.value << ")"; return s.space();} + +Q_DECLARE_METATYPE(QAD::Enum) +inline QDataStream & operator <<(QDataStream & s, const QAD::Enum & v) {s << v.enum_name << v.selected << v.enum_list; return s;} +inline QDataStream & operator >>(QDataStream & s, QAD::Enum & v) {s >> v.enum_name >> v.selected >> v.enum_list; return s;} +inline QDebug operator <<(QDebug s, const QAD::Enum & v) {s.nospace() << v.selected; return s.space();} + +Q_DECLARE_METATYPE(QAD::File) +inline QDataStream & operator <<(QDataStream & s, const QAD::File & v) {s << v.file << v.filter << v.is_abs; return s;} +inline QDataStream & operator >>(QDataStream & s, QAD::File & v) {s >> v.file >> v.filter >> v.is_abs; return s;} +inline QDebug operator <<(QDebug s, const QAD::File & v) {s.nospace() << v.file; return s.space();} + +Q_DECLARE_METATYPE(QAD::Dir) +inline QDataStream & operator <<(QDataStream & s, const QAD::Dir & v) {s << v.dir << v.is_abs; return s;} +inline QDataStream & operator >>(QDataStream & s, QAD::Dir & v) {s >> v.dir >> v.is_abs; return s;} +inline QDebug operator <<(QDebug s, const QAD::Dir & v) {s.nospace() << v.dir; return s.space();} + +class __QADTypesRegistrator__ { +public: + __QADTypesRegistrator__() { + qRegisterMetaType("QAD::Enumerator"); + qRegisterMetaTypeStreamOperators("QAD::Enumerator"); + + qRegisterMetaType("QAD::Enum"); + qRegisterMetaTypeStreamOperators("QAD::Enum"); + + qRegisterMetaType("QAD::File"); + qRegisterMetaTypeStreamOperators("QAD::File"); + + qRegisterMetaType("QAD::Dir"); + qRegisterMetaTypeStreamOperators("QAD::Dir"); + } +}; + + +inline qreal quantize(qreal x, qreal q = 10.f) {return qRound(x / q) * q;} +inline QPointF quantize(QPointF x, qreal q = 10.f) {return QPointF(quantize(x.x(), q), quantize(x.y(), q));} + +inline qreal distPointToLine(const QPointF & lp0, const QPointF & lp1, const QPointF & p) { + QLineF a(lp0, lp1), b(lp0, p), c(lp1, p); + qreal f = qAbs(a.dx()*b.dy() - a.dy()*b.dx()) / a.length(), s = b.length() + c.length() - a.length(); + return qMax(f, s); +} +inline QPointF nearestPointOnLine(const QPointF & lp0, const QPointF & lp1, const QPointF & p) { + QLineF a(lp0, lp1), b(lp0, p); + return a.pointAt(b.length() / a.length()); +} +inline QRectF enlargedRect(const QRectF & r, qreal dx, qreal dy, qreal v) { + return QRectF(r.left() - v + dx, r.top() - v + dy, r.width() + v+v, r.height() + v+v); +} + +QVariant::Type typeFromLetter(const QString & l); +QString uniqueName(QString n, const QStringList & names); + + +#endif // QAD_TYPES_H diff --git a/qad/utils/qad_utils.qrc b/qad/utils/qad_utils.qrc new file mode 100644 index 0000000..12a8c2d --- /dev/null +++ b/qad/utils/qad_utils.qrc @@ -0,0 +1,17 @@ + + + ../icons/edit-clear.png + ../icons/document-save.png + ../icons/edit-clear-locationbar-rtl.png + ../icons/edit-find.png + ../icons/list-add.png + ../icons/edit-delete.png + ../icons/item-add.png + ../icons/item.png + ../icons/node-add.png + ../icons/node.png + ../icons/edit-copy.png + ../icons/edit-paste.png + ../icons/document-open_16.png + + diff --git a/qad/utils/qpiconfig.cpp b/qad/utils/qpiconfig.cpp new file mode 100644 index 0000000..bbd1cd2 --- /dev/null +++ b/qad/utils/qpiconfig.cpp @@ -0,0 +1,825 @@ +#include "qpiconfig.h" +#include +#include + + +int QString2int(const QString & string) { + QString s = string.trimmed(); + if (s.left(2) == "0x") return s.mid(2).toLongLong(0, 16); + if (s.left(1) == "0") return s.mid(1).toLongLong(0, 8); + return s.toLongLong(); +} + + +QRect QString2QRect(const QString & string) { + int sl, st, sw, sh; + int s = 0, e; + e = string.indexOf(";"); + sl = string.mid(s, e - s).toInt(); + s = e + 1; + e = string.indexOf(";", s); + st = string.mid(s, e - s).toInt(); + s = e + 1; + e = string.indexOf(";", s); + sw = string.mid(s, e - s).toInt(); + s = e + 1; + e = string.length(); + sh = string.mid(s, e - s).toInt(); + return QRect(sl, st, sw, sh); +} + + +QRectF QString2QRectF(const QString & string) { + double sl, st, sw, sh; + int s = 0, e; + e = string.indexOf(";"); + sl = string.mid(s, e - s).toDouble(); + s = e + 1; + e = string.indexOf(";", s); + st = string.mid(s, e - s).toDouble(); + s = e + 1; + e = string.indexOf(";", s); + sw = string.mid(s, e - s).toDouble(); + s = e + 1; + e = string.length(); + sh = string.mid(s, e - s).toDouble(); + return QRectF(sl, st, sw, sh); +} + + +QPoint QString2QPoint(const QString & string) { + int sx, sy; + int s = 0, e; + e = string.indexOf(";"); + sx = string.mid(s, e - s).toInt(); + s = e + 1; + e = string.length(); + sy = string.mid(s, e - s).toInt(); + return QPoint(sx, sy); +} + + +QPointF QString2QPointF(const QString & string) { + double sx, sy; + int s = 0, e; + e = string.indexOf(";"); + sx = string.mid(s, e - s).toDouble(); + s = e + 1; + e = string.length(); + sy = string.mid(s, e - s).toDouble(); + return QPointF(sx, sy); +} + + +QString QRect2QString(const QRect & rect) { + return QString::number(rect.left()) + ";" + + QString::number(rect.top()) + ";" + + QString::number(rect.width()) + ";" + + QString::number(rect.height()); +} + + +QString QRectF2QString(const QRectF & rect) { + return QString::number(rect.left()) + ";" + + QString::number(rect.top()) + ";" + + QString::number(rect.width()) + ";" + + QString::number(rect.height()); +} + + +QPIConfig::Entry QPIConfig::Branch::_empty; +QPIConfig::Entry QPIConfig::Entry::_empty; + + +QPIConfig::Branch QPIConfig::Branch::allLeaves() { + Branch b; + b.delim = delim; + foreach (Entry * i, *this) { + if (i->isLeaf()) b << i; + else allLeaves(b, i); + } + return b; +} + + +QPIConfig::Entry & QPIConfig::Branch::getValue(const QString & vname, const QString & def, bool * exist) { + if (vname.isEmpty()) { + _empty.clear(); + _empty.delim = delim; + if (exist != 0) *exist = false; + return _empty; + } + QStringList tree = vname.split(delim); + QString name = tree.front(); + tree.pop_front(); + Entry * ce = 0; + foreach (Entry * i, *this) + if (i->_name == name) { + ce = i; + break; + } + if (ce == 0) { + _empty._name = vname; + _empty._value = def; + _empty.delim = delim; + if (exist != 0) *exist = false; + return _empty; + } + foreach (QString i, tree) { + ce = ce->findChild(i); + if (ce == 0) { + _empty._name = vname; + _empty._value = def; + _empty.delim = delim; + if (exist != 0) *exist = false; + return _empty; + } + } + if (exist != 0) *exist = true; + return *ce; +} + + +QPIConfig::Branch QPIConfig::Branch::getValues(const QString & name) { + Branch b; + b.delim = delim; + foreach (Entry * i, *this) { + if (i->isLeaf()) { + if (i->_name.indexOf(name) >= 0) + b << i; + } else { + foreach (Entry * j, i->_children) + if (j->_name.indexOf(name) >= 0) + b << j; + } + } + return b; +} + + +QPIConfig::Branch QPIConfig::Branch::getLeaves() { + Branch b; + b.delim = delim; + foreach (Entry * i, *this) + if (i->isLeaf()) + b << i; + return b; +} + + +QPIConfig::Branch QPIConfig::Branch::getBranches() { + Branch b; + b.delim = delim; + foreach (Entry * i, *this) + if (!i->isLeaf()) + b << i; + return b; +} + + +QPIConfig::Branch & QPIConfig::Branch::filter(const QString & f) { + for (int i = 0; i < size(); ++i) { + if (at(i)->_name.indexOf(f) < 0) { + remove(i); + --i; + } + } + return *this; +} + + +bool QPIConfig::Branch::entryExists(const Entry * e, const QString & name) const { + if (e->_children.isEmpty()) { + if (e->_name == name) return true; + else return false; + } + foreach (Entry * i, e->_children) + if (entryExists(i, name)) return true; + return false; +} + + +QPIConfig::Entry & QPIConfig::Entry::getValue(const QString & vname, const QString & def, bool * exist) { + QStringList tree = vname.split(delim); + Entry * ce = this; + foreach (QString i, tree) { + ce = ce->findChild(i); + if (ce == 0) { + _empty._name = vname; + _empty._value = def; + _empty.delim = delim; + if (exist != 0) *exist = false; + return _empty; + } + } + if (exist != 0) *exist = true; + return *ce; +} + + +QPIConfig::Branch QPIConfig::Entry::getValues(const QString & vname) { + Branch b; + b.delim = delim; + foreach (Entry * i, _children) + if (i->_name.indexOf(vname) >= 0) + b << i; + return b; +}; + + +bool QPIConfig::Entry::entryExists(const Entry * e, const QString & name) const { + if (e->_children.isEmpty()) { + if (e->_name == name) return true; + else return false; + } + foreach (Entry * i, e->_children) + if (entryExists(i, name)) return true; + return false; +} + + +QPIConfig::QPIConfig(const QString & path, QIODevice::OpenMode mode, QPIConfig::FileType type_): QFile(path) { + init(); + type = type_; + open(mode); + //stream.setDevice(this); + parse(); +} + + +QPIConfig::QPIConfig(const QString & path, QIODevice::OpenMode mode): QFile(path) { + init(); + type = Config; + open(mode); + //stream.setDevice(this); + parse(); +} + + +QPIConfig::QPIConfig(const QString & path, QPIConfig::FileType type_): QFile(path) { + init(); + type = type_; + open(QIODevice::ReadWrite); + //stream.setDevice(this); + parse(); +} + + +QPIConfig::QPIConfig(QString * str, QPIConfig::FileType type_) { + init(); + type = type_; + buffer = str; + //stream.setDevice(this); + parse(); +} + + +QPIConfig::QPIConfig(const QString & path, QStringList dirs) { + init(); + type = Config; + internal = true; + dev = new QFile(path); + dev->open(QIODevice::ReadOnly); + incdirs = dirs; + incdirs << QFileInfo(path).absoluteDir().path(); + QString cp = path; + while (!dev->isOpen()) { + if (dirs.isEmpty()) break; + cp = dirs.back(); + if (cp.endsWith("/") || cp.endsWith("\\")) cp.chop(1); + cp += "/" + path; + dev->setFileName(cp); + dev->open(QIODevice::ReadOnly); + dirs.pop_back(); + } + if (!dev->isOpen()) { + delete dev; + dev = 0; + return; + } + dev->close(); + setFileName(cp); + open(QIODevice::ReadOnly); + parse(); +} + + +QPIConfig::~QPIConfig() { + stream.setDevice(0); + root.deleteBranch(); + foreach (QPIConfig * c, inc_devs) + delete c; + inc_devs.clear(); + includes.clear(); +} + + +void QPIConfig::init() { + internal = false; + buffer = 0; + dev = 0; + delim = "."; + root._name = "root"; + root.delim = delim; + empty.delim = delim; + empty._parent = 0; +} + + +void QPIConfig::setFile(const QString & path, QIODevice::OpenMode mode) { + buffer = 0; + setFileName(path); + if (open(mode)) + parse(); +} + + +void QPIConfig::setString(QString * str) { + buffer = str; + parse(); +} + + +QPIConfig::Entry & QPIConfig::getValue(const QString & vname, const QString & def, bool * exist) { + QStringList tree = vname.split(delim); + Entry * ce = &root; + foreach (QString i, tree) { + ce = ce->findChild(i); + if (ce == 0) { + if (exist != 0) *exist = false; + empty._name = vname; + empty._value = def; + empty.delim = delim; + return empty; + } + } + if (exist != 0) *exist = true; + return *ce; +} + + +QPIConfig::Branch QPIConfig::getValues(const QString & vname) { + Branch b; + b.delim = delim; + foreach (Entry * i, root._children) + if (i->_name.indexOf(vname) >= 0) + b << i; + return b; +} + + +QPIConfig::Entry & QPIConfig::addEntry(const QString & name, const QString & value, const QString & type, bool write, bool node) { + if (getValue(name)._parent != 0) + return empty; + QString sn = name, tn; + bool toRoot = false; + while (sn.indexOf(delim) == 0) sn.remove(0, delim.length()); + QStringList tree = sn.split(delim); + QString ename = tree.back(); + tn = tree.front(); + tree.pop_back(); + Entry * te, * ce, * entry = &root; + if (tree.isEmpty()) toRoot = true; + foreach (QString i, tree) { + te = entry->findChild(i); + if (te == 0) { + ce = new Entry(); + ce->delim = delim; + ce->_tab = entry->_tab; + ce->_line = entry->_line; + ce->_name = i; + ce->_parent = entry; + //qDebug() << " [QPIC] add " + tn; + ce->_full_name = tn; + entry->_children << ce; + entry = ce; + } else entry = te; + tn += delim + i; + } + QPIConfig::Branch ch = entry->_children; + qSort(ch.begin(), ch.end(), QPIConfig::Entry::compare); + te = (entry->isLeaf() ? 0 : ch.back()); + ce = new Entry(); + ce->delim = delim; + ce->_name = ename; + if (!node) ce->_value = value; + ce->_type = type; + if (te == 0) { + //qDebug() << "[QPIC] te == 0"; + ce->_tab = entry->_tab; + if (toRoot) ce->_line = other.size(); + else { + ch = entry->_parent->_children; + qSort(ch.begin(), ch.end(), QPIConfig::Entry::compare); + ce->_line = ch.back()->_line + 1; + } + } else { + ce->_tab = te->_tab; + if (toRoot) ce->_line = other.size(); + else ce->_line = te->_line + 1; + } + //qDebug() << "[QPIC] add " + sn + " at line " << ce->_line << ", parent " << entry->_name; + ce->_full_name = sn; + ce->_parent = entry; + entry->_children << ce; + //qDebug() << "[QPIC] children " << entry->childCount(); + if (!node) { + other.insert(ce->_line, ""); + Branch b = allLeaves(); + //qDebug() << "[QPIC] allLeaves " << b.size(); + bool found = false; + for (int i = 0; i < b.size(); ++i) { + if (found) { + b[i]->_line++; + continue; + } + if (b[i] == ce) { + found = true; + if (i > 0) + if (b[i - 1]->_line == b[i]->_line) + b[i - 1]->_line++; + } + //qDebug() << b[i]->_line; + } + } + //qDebug() << "[QPIC] add " + sn + " at line " << ce->_line << ", parent " + entry->_name; + if (write) writeAll(); + return *ce; +} + + +void QPIConfig::setValue(const QString & name, const QString & value, const QString & type, bool write) { + Entry & e(getValue(name)); + if (&e == &empty) { + addEntry(name, value, type, write); + return; + } + e._value = value; + e._type = type; + if (write) writeAll(); +} + + +int QPIConfig::entryIndex(const QString & name) { + QStringList tree = name.split(delim); + Entry * ce = &root; + foreach (QString i, tree) { + ce = ce->findChild(i); + if (ce == 0) + return -1; + } + Branch b = allLeaves(); + return allLeaves().indexOf(ce); +} + + +void QPIConfig::setValue(uint number, const QString & value, bool write) { + Entry & e(entryByIndex(number)); + if (&e == &empty) return; + e._value = value; + if (write) writeAll(); +} + + +void QPIConfig::setName(uint number, const QString & name, bool write) { + Entry & e(entryByIndex(number)); + if (&e == &empty) return; + e._name = name; + if (write) writeAll(); +} + + +void QPIConfig::setType(uint number, const QString & type, bool write) { + Entry & e(entryByIndex(number)); + if (&e == &empty) return; + e._type = type; + if (write) writeAll(); +} + + +void QPIConfig::setComment(uint number, const QString & comment, bool write) { + Entry & e(entryByIndex(number)); + if (&e == &empty) return; + e._comment = comment; + if (write) writeAll(); +} + + +void QPIConfig::removeEntry(const QString & name, bool write) { + Entry & e(getValue(name)); + if (&e == &empty) return; + Branch b = allLeaves(); + removeEntry(b, &e); + if (write) writeAll(); +} + + +void QPIConfig::removeEntry(uint number, bool write) { + Entry & e(entryByIndex(number)); + if (&e == &empty) return; + Branch b = allLeaves(); + removeEntry(b, &e); + if (write) writeAll(); +} + + +void QPIConfig::removeEntry(Branch & b, QPIConfig::Entry * e) { + bool leaf = true; + //qDebug() << " before " << b.size(); + if (e->isLeaf()) other.removeAt(e->_line); + if (!e->isLeaf() && !e->_value.isEmpty()) { + e->_value.clear(); + //leaf = false; + } else { + int cc = e->_children.size(); + for (int i = 0; i < cc; ++i) + removeEntry(b, e->_children.back()); + } + bool found = false; + for (int i = 0; i < b.size(); ++i) { + if (found) { + b[i]->_line--; + continue; + } + if (b[i] == e) found = true; + } + if (!leaf) return; + int ti = e->_parent->_children.indexOf(e); + if (ti >= 0) e->_parent->_children.remove(ti); + ti = b.indexOf(e); + if (ti >= 0) b.remove(ti); + //qDebug() << " after " << b.size(); + delete e; +} + + +void QPIConfig::writeAll() { + if (buffer == 0) { + stream.setDevice(this); + resize(0); + } else { + stream.setString(buffer); + buffer->clear(); + } + stream.seek(0); + //writeEntry(&root); + buildFullNames(&root); + Branch b = allLeaves(); + QString prefix, tprefix; + bool isPrefix; + int j = 0; + for (int i = 0; i < other.size(); ++i) { + //cout << j << endl; + if (j >= 0 && j < b.size()) { + if (b[j]->_line == i) { + b[j]->buildLine(); + stream << b[j]->_all << '\n'; + ++j; + } else { + stream << other[i]; + tprefix = getPrefixFromLine(other[i], &isPrefix); + if (isPrefix) { + prefix = tprefix; + if (!prefix.isEmpty()) + prefix += delim; + } + if (i < other.size() - 1) stream << '\n'; + } + } else { + stream << other[i]; + tprefix = getPrefixFromLine(other[i], &isPrefix); + if (isPrefix) { + prefix = tprefix; + if (!prefix.isEmpty()) + prefix += delim; + } + if (i < other.size() - 1) stream << '\n'; + } + } + if (buffer == 0) + flush(); + readAll(); +} + + +QString QPIConfig::getPrefixFromLine(QString line, bool * exists) { + line = line.trimmed(); + if (line.left(1) == "#") {if (exists) *exists = false; return QString();} + int ci = line.indexOf("#"); + if (ci >= 0) line = line.left(ci).trimmed(); + if (line.indexOf("=") >= 0) {if (exists) *exists = false; return QString();} + if (line.indexOf("[") >= 0 && line.indexOf("]") >= 0) { + if (exists) *exists = true; + line.remove(0, 1); + return line.left(line.lastIndexOf("]")).trimmed(); + } + if (exists) *exists = false; + return QString(); +} + + +QString QPIConfig::writeAllToString() { + QString str; + QTextStream s(&str); + //writeEntry(&root); + buildFullNames(&root); + Branch b = allLeaves(); + int j = 0; + for (int i = 0; i < other.size(); ++i) { + //cout << j << endl; + if (j >= 0 && j < b.size()) { + if (b[j]->_line == i) { + b[j]->buildLine(); + s << b[j]->_all << '\n'; + ++j; + } else { + s << other[i]; + if (i < other.size() - 1) s << '\n'; + } + } else { + s << other[i]; + if (i < other.size() - 1) s << '\n'; + } + } + return str; +} + + +void QPIConfig::readAllFromString(const QString & str) { + parse(str); +} + + +void QPIConfig::clear() { + root.deleteBranch(); + root.clear(); + other.clear(); + if (buffer == 0) + resize(0); + else + buffer->clear(); + stream.seek(0); +} + + +void QPIConfig::readAll() { + if (buffer == 0) + flush(); + parse(); +} + + +bool QPIConfig::entryExists(const Entry * e, const QString & name) const { + if (e->_children.isEmpty()) { + if (e->_name == name) return true; + else return false; + } + foreach (Entry * i, e->_children) + if (entryExists(i, name)) return true; + return false; +} + + +void QPIConfig::updateIncludes() { + if (internal) return; + all_includes.clear(); + foreach (QPIConfig * c, includes) + all_includes << c->allLeaves(); +} + + +QString QPIConfig::parseLine(QString v) { + int i = -1, l = 0; + while (1) { + i = v.indexOf("${"); + if (i < 0) break; + l = v.indexOf("}", i + 1); + QString w = v.mid(i + 2, l - i - 2), r; + l = w.length() + 3; + w = parseLine(w); + w = w.trimmed(); + bool ex = false; + QPIConfig::Entry & me = getValue(w, "", &ex); + if (ex) { + r = me._value; + } else { + foreach (QPIConfig::Entry * e, all_includes) { + if (e->_full_name == w) { + r = e->_value; + break; + } + } + } + v.replace(i, l, r); + } + return v; +} + + +void QPIConfig::parse(QString content) { + root.deleteBranch(); + root.clear(); + QString src, str, tab, comm, all, name, type, prefix, tprefix; + QStringList tree; + Entry * entry, * te, * ce; + int ind, sind; + bool isNew, isPrefix; + foreach (QPIConfig * c, inc_devs) + delete c; + inc_devs.clear(); + includes.clear(); + if (content.isEmpty()) { + if (buffer == 0) { + if (!isOpen()) return; + stream.setDevice(this); + } else + stream.setString(buffer); + } else { + stream.setString(&content); + } + stream.seek(0); + other.clear(); + lines = centry = 0; + while (!stream.atEnd()) { + other.push_back(QString()); + src = str = parseLine(stream.readLine()); + tprefix = getPrefixFromLine(src, &isPrefix); + if (isPrefix) { + prefix = tprefix; + if (!prefix.isEmpty()) + prefix += delim; + } + //cout << str << endl; + tab = str.left(str.indexOf(str.trimmed().left(1))); + str = str.trimmed(); + all = str; + ind = str.indexOf('='); + if ((ind > 0) && !(str[0] == '#')) { + sind = str.indexOf('#'); + if (sind > 0) { + comm = str.right(str.length() - sind - 1).trimmed(); + if (comm.length() > 0) type = comm[0]; + else type = "s"; + comm = comm.right(comm.length() - 1).trimmed(); + str = str.left(sind); + } else { + type = "s"; + comm = ""; + } + //name = str.left(ind).trimmed(); + tree = (prefix + str.left(ind).trimmed()).split(delim); + if (tree.front() == "include") { + name = str.right(str.length() - ind - 1).trimmed(); + QPIConfig * iconf = new QPIConfig(name, incdirs); + if (!iconf->dev) { + delete iconf; + } else { + inc_devs << iconf; + includes << iconf << iconf->includes; + updateIncludes(); + } + //piCout << "includes" << includes; + other.back() = src; + } else { + name = tree.back(); + tree.pop_back(); + entry = &root; + foreach (QString i, tree) { + te = entry->findChild(i); + if (te == 0) { + ce = new Entry(); + ce->delim = delim; + ce->_tab = tab; + ce->_line = lines; + ce->_name = i; + ce->_parent = entry; + entry->_children << ce; + entry = ce; + } else entry = te; + } + isNew = false; + ce = entry->findChild(name); + if (ce == 0) { + ce = new Entry(); + isNew = true; + } + ce->delim = delim; + ce->_tab = tab; + ce->_name = name; + ce->_value = str.right(str.length() - ind - 1).trimmed(); + ce->_type = type; + ce->_comment = comm; + ce->_line = lines; + ce->_all = all; + if (isNew) { + ce->_parent = entry; + entry->_children << ce; + } + } + } else other.back() = src; + lines++; + } + setEntryDelim(&root, delim); + buildFullNames(&root); + //if (content.isEmpty()) stream.setDevice(this); +} diff --git a/qad/utils/qpiconfig.h b/qad/utils/qpiconfig.h new file mode 100644 index 0000000..d7dd7fd --- /dev/null +++ b/qad/utils/qpiconfig.h @@ -0,0 +1,280 @@ +#ifndef QPICONFIG_H +#define QPICONFIG_H + +#include "QFile" +#include "QVector" +#include "QStringList" +#include "QTextStream" + +#include +#include +#include +#include +#include + + +inline QByteArray QString2QByteArray(const QString & string) {return qUncompress(QByteArray::fromBase64(string.toLatin1()));} +int QString2int(const QString & string); +inline QColor QString2QColor(const QString & string) {return (string.left(1) == "#" ? QColor(string.right(string.length() - 1).toInt(0, 16)) : QColor(QString2int(string)));} +QRect QString2QRect(const QString & string); +QRectF QString2QRectF(const QString & string); +QPoint QString2QPoint(const QString & string); +QPointF QString2QPointF(const QString & string); + +inline QString QColor2QString(const QColor & color) {QString s = color.name(); return "0x" + QString::number(color.alpha(), 16).rightJustified(2, '0') + s.right(s.length() - 1);} +inline QString QPoint2QString(const QPoint & point) {return QString::number(point.x()) + ";" + QString::number(point.y());} +inline QString QPointF2QString(const QPointF & point) {return QString::number(point.x()) + ";" + QString::number(point.y());} +inline QString QByteArray2QString(const QByteArray & array) {return QString(qCompress(array, 9).toBase64());} +QString QRect2QString(const QRect & rect); +QString QRectF2QString(const QRectF & rect); + +#define QPICONFIG_GET_VALUE \ + Entry & getValue(const QString & vname, const char * def, bool * exist = 0) {return getValue(vname, QString(def), exist);} \ + Entry & getValue(const QString & vname, const QStringList & def, bool * exist = 0) {return getValue(vname, def.join("%|%"), exist);} \ + Entry & getValue(const QString & vname, const bool def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const short def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const int def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const long def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const uchar def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const ushort def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const uint def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const ulong def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const float def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const double def, bool * exist = 0) {return getValue(vname, QString::number(def), exist);} \ + Entry & getValue(const QString & vname, const QColor & def, bool * exist = 0) {return getValue(vname, QColor2QString(def), exist);} \ + Entry & getValue(const QString & vname, const Qt::GlobalColor def, bool * exist = 0) {return getValue(vname, QColor(def), exist);} \ + Entry & getValue(const QString & vname, const QRect & def, bool * exist = 0) {return getValue(vname, QRect2QString(def), exist);} \ + Entry & getValue(const QString & vname, const QRectF & def, bool * exist = 0) {return getValue(vname, QRectF2QString(def), exist);} \ + Entry & getValue(const QString & vname, const QPoint & def, bool * exist = 0) {return getValue(vname, QPoint2QString(def), exist);} \ + Entry & getValue(const QString & vname, const QPointF & def, bool * exist = 0) {return getValue(vname, QPointF2QString(def), exist);} \ + Entry & getValue(const QString & vname, const QByteArray & def, bool * exist = 0) {return getValue(vname, QByteArray2QString(def), exist);} + +class QPIConfig: public QFile +{ + friend class Entry; + friend class Branch; + friend class QPIConfigWidget; +public: + enum FileType {Config, XML}; + + QPIConfig(const QString & path, QIODevice::OpenMode mode, QPIConfig::FileType type); + QPIConfig(const QString & path, QIODevice::OpenMode mode = QIODevice::ReadWrite); + QPIConfig(const QString & path, QPIConfig::FileType type); + QPIConfig(QString * str, QPIConfig::FileType type = QPIConfig::Config); + ~QPIConfig(); + + void setFile(const QString & path, QIODevice::OpenMode mode = QIODevice::ReadWrite); + void setString(QString * str); + + class Entry; + + class Branch: public QVector { + friend class QPIConfig; + friend class Entry; + public: + Branch() {;} + + Entry & getValue(const QString & vname, const QString & def = QString(), bool * exist = 0); + QPICONFIG_GET_VALUE + + Branch allLeaves(); + Branch getValues(const QString & name); + Branch getLeaves(); + Branch getBranches(); + Branch & filter(const QString & f); + bool isEntryExists(const QString & name) const {foreach (const Entry * i, *this) if (entryExists(i, name)) return true; return false;} + int indexOf(const Entry * e) {for (int i = 0; i < size(); ++i) if (at(i) == e) return i; return -1;} + + //void clear() {foreach (Entry * i, *this) delete i; QVector::clear();} + + private: + bool entryExists(const Entry * e, const QString & name) const; + void allLeaves(Branch & b, Entry * e) {foreach (Entry * i, e->_children) {if (i->isLeaf()) b << i; else allLeaves(b, i);}} + + static Entry _empty; + QString delim; + + }; + + class Entry { + friend class QPIConfig; + friend class Branch; + friend class QPIConfigWidget; + friend class ConfigValueWidget; + public: + Entry() {_parent = 0; _line = -1;} + + Entry * parent() const {return _parent;} + int childCount() {return _children.size();} + Branch & children() {_children.delim = delim; return _children;} + Entry * child(const int index) const {return _children[index];} + const Entry * findChild(const QString & name) const {foreach (const Entry * i, _children) if (i->_name == name) return i; return 0;} + Entry * findChild(const QString & name) {foreach (Entry * i, _children) if (i->_name == name) return i; return 0;} + bool isLeaf() const {return _children.empty();} + + const QString & name() const {return _name;} + const QString & value() const {return _value;} + const QString & type() const {return _type;} + const QString & comment() const {return _comment;} + + Entry & setName(const QString & value) {_name = value; return *this;} + Entry & setType(const QString & value) {_type = value; return *this;} + Entry & setComment(const QString & value) {_comment = value; return *this;} + Entry & setValue(const QString & value) {_value = value; return *this;} + Entry & setValue(const QStringList & value) {setValue(value.join("%|%")); setType("l"); return *this;} + Entry & setValue(const char * value) {setValue(QString(value)); setType("s"); return *this;} + Entry & setValue(const bool value) {setValue(QString::number(value)); setType("b"); return *this;} + Entry & setValue(const short value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const int value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const long value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const uchar value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const ushort value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const uint value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const ulong value) {setValue(QString::number(value)); setType("n"); return *this;} + Entry & setValue(const float value) {setValue(QString::number(value)); setType("f"); return *this;} + Entry & setValue(const double value) {setValue(QString::number(value)); setType("f"); return *this;} + Entry & setValue(const QColor & value) {setValue(QColor2QString(value)); setType("c"); return *this;} + Entry & setValue(const Qt::GlobalColor & value) {setValue(QColor(value)); return *this;} + Entry & setValue(const QRect & value) {setValue(QRect2QString(value)); setType("r"); return *this;} + Entry & setValue(const QRectF & value) {setValue(QRectF2QString(value)); setType("a"); return *this;} + Entry & setValue(const QPoint & value) {setValue(QPoint2QString(value)); setType("p"); return *this;} + Entry & setValue(const QPointF & value) {setValue(QPointF2QString(value)); setType("v"); return *this;} + Entry & setValue(const QByteArray & value) {setValue(QByteArray2QString(value)); setType("s"); return *this;} + + Entry & getValue(const QString & vname, const QString & def = QString(), bool * exist = 0); + QPICONFIG_GET_VALUE + + Branch getValues(const QString & vname); + + bool isEntryExists(const QString & name) const {return entryExists(this, name);} + const QString & stringValue() const {return _value;} + + operator bool() {return (_value.toLower().trimmed() == "true" || _value.toLower().trimmed() == "yes" || _value.toLower().trimmed() == "on" || _value.toInt() > 0);} + operator char() {return (_value.isEmpty() ? 0 : _value[0].toLatin1());} + operator short() {return _value.toShort();} + operator int() {return QString2int(_value);} + operator long() {return QString2int(_value);} + operator uchar() {return QString2int(_value);} + operator ushort() {return QString2int(_value);} + operator uint() {return QString2int(_value);} + operator ulong() {return QString2int(_value);} + operator float() {return _value.toFloat();} + operator double() {return _value.toDouble();} + operator QString() {return _value;} + operator QStringList() {return _value.split("%|%");} + operator QColor() {return QString2QColor(_value);} + operator QRect() {return QString2QRect(_value);} + operator QRectF() {return QString2QRectF(_value);} + operator QPoint() {return QString2QPoint(_value);} + operator QPointF() {return QString2QPointF(_value);} + operator QByteArray() {return QString2QByteArray(_value);} + + private: + static bool compare(const QPIConfig::Entry * f, const QPIConfig::Entry * s) {return f->_line < s->_line;} + bool entryExists(const Entry * e, const QString & name) const; + void buildLine() {_all = _tab + _full_name + " = " + _value + " #" + _type + " " + _comment;} + void clear() {_children.clear(); _name = _value = _type = _comment = _all = QString(); _line = 0; _parent = 0;} + void deleteBranch() {foreach (Entry * i, _children) {i->deleteBranch(); delete i;}} + + static Entry _empty; + Entry * _parent; + Branch _children; + QString _tab; + QString _name; + QString _value; + QString _type; + QString _comment; + QString _all; + QString _full_name; + QString delim; + int _line; + }; + + Entry & getValue(const QString & vname, const QString & def = QString(), bool * exist = 0); + QPICONFIG_GET_VALUE + + Branch getValues(const QString & vname); + + void setValue(const QString & name, const QString & value, const QString & type = "s", bool write = true); + void setValue(const QString & name, const QStringList & value, bool write = true) {setValue(name, value.join("%|%"), "l", write);} + void setValue(const QString & name, const char * value, bool write = true) {setValue(name, QString(value), "s", write);} + void setValue(const QString & name, const bool value, bool write = true) {setValue(name, QString::number(value), "b", write);} + void setValue(const QString & name, const short value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const int value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const long value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const uchar value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const ushort value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const uint value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const ulong value, bool write = true) {setValue(name, QString::number(value), "n", write);} + void setValue(const QString & name, const float value, bool write = true) {setValue(name, QString::number(value), "f", write);} + void setValue(const QString & name, const double value, bool write = true) {setValue(name, QString::number(value), "f", write);} + void setValue(const QString & name, const QColor & value, bool write = true) {setValue(name, QColor2QString(value), "c", write);} + void setValue(const QString & name, const Qt::GlobalColor & value, bool write = true) {setValue(name, QColor(value), write);} + void setValue(const QString & name, const QRect & value, bool write = true) {setValue(name, QRect2QString(value), "r", write);} + void setValue(const QString & name, const QRectF & value, bool write = true) {setValue(name, QRectF2QString(value), "a", write);} + void setValue(const QString & name, const QPoint & value, bool write = true) {setValue(name, QPoint2QString(value), "p", write);} + void setValue(const QString & name, const QPointF & value, bool write = true) {setValue(name, QPointF2QString(value), "v", write);} + void setValue(const QString & name, const QByteArray & value, bool write = true) {setValue(name, QByteArray2QString(value), "s", write);} + + Entry & rootEntry() {return root;} + int entriesCount() const {return childCount(&root);} + bool isEntryExists(const QString & name) const {return entryExists(&root, name);} + + Branch allTree() {Branch b; foreach (Entry * i, root._children) b << i; return b;} + Branch allLeaves() {Branch b; allLeaves(b, &root); qSort(b.begin(), b.end(), Entry::compare); return b;} + int entryIndex(const QString & name); + + QString getName(uint number) {return entryByIndex(number)._name;} + QString getValue(uint number) {return entryByIndex(number)._value;} + QChar getType(uint number) {return entryByIndex(number)._type[0];} + QString getComment(uint number) {return entryByIndex(number)._comment;} + + QPIConfig::Entry & addEntry(const QString & name, const QString & value, const QString & type = "s", bool write = true, bool node = false); + void setName(uint number, const QString & name, bool write = true); + void setValue(uint number, const QString & value, bool write = true); + void setType(uint number, const QString & type, bool write = true); + void setComment(uint number, const QString & comment, bool write = true); + + void removeEntry(const QString & name, bool write = true); + void removeEntry(uint number, bool write = true); + + void clear(); + void readAll(); + void writeAll(); + QString writeAllToString(); + void readAllFromString(const QString & str); + + const QString & delimiter() const {return delim;} + void setDelimiter(const QString & d) {delim = d; setEntryDelim(&root, d); readAll();} + +private: + QPIConfig(const QString & path, QStringList dirs); + void init(); + int childCount(const Entry * e) const {int c = 0; foreach (const Entry * i, e->_children) c += childCount(i); c += e->_children.size(); return c;} + bool entryExists(const Entry * e, const QString & name) const; + void buildFullNames(Entry * e) {foreach (Entry * i, e->_children) {if (e != &root) i->_full_name = e->_full_name + delim + i->_name; else i->_full_name = i->_name; buildFullNames(i);}} + void allLeaves(Branch & b, Entry * e) {foreach (Entry * i, e->_children) {if ((!i->_value.isEmpty() && !i->isLeaf()) || i->isLeaf()) b << i; allLeaves(b, i);}} + void setEntryDelim(Entry * e, const QString & d) {foreach (Entry * i, e->_children) setEntryDelim(i, d); e->delim = d;} + inline Entry & entryByIndex(const int index) {Branch b = allLeaves(); if (index < 0 || index >= b.size()) return empty; return *(b[index]);} + void removeEntry(Branch & b, Entry * e); + void deleteEntry(Entry * e) {foreach (Entry * i, e->_children) deleteEntry(i); delete e;} + QString getPrefixFromLine(QString line, bool * exists); + void updateIncludes(); + QString parseLine(QString v); + void parse(QString content = QString()); + + int centry; + bool internal; + QVector includes, inc_devs; + Branch all_includes; + QFile * dev; + QStringList incdirs; + QString delim, * buffer; + Entry root, empty; + uint lines; + QStringList other; + QTextStream stream; + FileType type; +}; + +#endif // QPICONFIG_H diff --git a/qad/utils/qpievaluator.cpp b/qad/utils/qpievaluator.cpp new file mode 100644 index 0000000..0d20aef --- /dev/null +++ b/qad/utils/qpievaluator.cpp @@ -0,0 +1,1065 @@ +/* + Peri4 Paint + Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "qpievaluator.h" + + +QPIEvaluatorContent::QPIEvaluatorContent() { + addFunction("arcsin", 1); + addFunction("arccos", 1); + addFunction("arctg", 1); + addFunction("arcctg", 1); + addFunction("random", 2); + addFunction("sin", 1); + addFunction("cos", 1); + addFunction("ctg", 1); + addFunction("tg", 1); + addFunction("exp", 1); + addFunction("cth", 1); + addFunction("sh", 1); + addFunction("ch", 1); + addFunction("th", 1); + addFunction("sqrt", 1); + addFunction("sqr", 1); + addFunction("pow", 2); + addFunction("abs", 1); + addFunction("ln", 1); + addFunction("lg", 1); + addFunction("log", 2); + addFunction("im", 1); + addFunction("re", 1); + addFunction("arg", 1); + addFunction("len", 1); + addFunction("conj", 1); + addFunction("sign", 1); + addFunction("rad", 1); + addFunction("deg", 1); + clearCustomVariables(); + //addVariable("n", 0.); + //addVariable("x1", 123); +} + + +bool QPIEvaluatorContent::setVariableValue(int index, complexd new_value) { + if (index < 0 || index >= variables.size()) return false; + variables[index].value = new_value; + return true; +} + + +bool QPIEvaluatorContent::setVariableName(int index, const QString & new_name) { + if (index < 0 || index >= variables.size()) return false; + variables[index].name = new_name; + return true; +} + + +void QPIEvaluatorContent::clearCustomVariables() { + var_index.clear(); + func_index.clear(); + variables.clear(); + addVariable("i", complexd_i); + addVariable("pi", atan(1.) * 4.); + addVariable("e", exp(1.)); + cv_count = variables.size(); +} + + +void QPIEvaluatorContent::sortVariables() { + var_index.clear(); + qSort(variables.begin(), variables.end()); + for (int i = 0; i < variables.size(); i++) + var_index[variables[i].name] = i; + /* + qDebug() << "---"; + for (int i = 0; i < variables.size(); i++) { + qDebug() << variables[i].name; + } + */ +} + + +QPIEvaluatorTypes::BaseFunctions QPIEvaluatorContent::getBaseFunction(const QString & name) { + if (name == "sin") return QPIEvaluatorTypes::bfSin; + if (name == "cos") return QPIEvaluatorTypes::bfCos; + if (name == "tg") return QPIEvaluatorTypes::bfTg; + if (name == "ctg") return QPIEvaluatorTypes::bfCtg; + if (name == "arcsin") return QPIEvaluatorTypes::bfArcsin; + if (name == "arccos") return QPIEvaluatorTypes::bfArccos; + if (name == "arctg") return QPIEvaluatorTypes::bfArctg; + if (name == "arcctg") return QPIEvaluatorTypes::bfArcctg; + if (name == "exp") return QPIEvaluatorTypes::bfExp; + if (name == "random") return QPIEvaluatorTypes::bfRandom; + if (name == "sh") return QPIEvaluatorTypes::bfSh; + if (name == "ch") return QPIEvaluatorTypes::bfCh; + if (name == "th") return QPIEvaluatorTypes::bfTh; + if (name == "cth") return QPIEvaluatorTypes::bfCth; + if (name == "sqrt") return QPIEvaluatorTypes::bfSqrt; + if (name == "sqr") return QPIEvaluatorTypes::bfSqr; + if (name == "pow") return QPIEvaluatorTypes::bfPow; + if (name == "abs") return QPIEvaluatorTypes::bfAbs; + if (name == "ln") return QPIEvaluatorTypes::bfLn; + if (name == "lg") return QPIEvaluatorTypes::bfLg; + if (name == "log") return QPIEvaluatorTypes::bfLog; + if (name == "im") return QPIEvaluatorTypes::bfIm; + if (name == "re") return QPIEvaluatorTypes::bfRe; + if (name == "arg") return QPIEvaluatorTypes::bfArg; + if (name == "len") return QPIEvaluatorTypes::bfLen; + if (name == "conj") return QPIEvaluatorTypes::bfConj; + if (name == "sign") return QPIEvaluatorTypes::bfSign; + if (name == "rad") return QPIEvaluatorTypes::bfRad; + if (name == "deg") return QPIEvaluatorTypes::bfDeg; + return QPIEvaluatorTypes::bfUnknown; +} + +const QString & QPIEvaluator::prepare(const QString & string) { + currentString = string.trimmed(); + if (currentString.isEmpty()) currentString = "0"; + replaceOperators(); + removeSpaces(); + checkBrackets(); + while (fillElements()) checkBrackets(); + while (setSignes()) fillElements(); + removeJunk(); + findUnknownVariables(); + return currentString; +} + + +void QPIEvaluator::removeSpaces() { + QString tmps = currentString; + for (int i = 0; i < tmps.length(); i++) { + if (tmps[i] == ' ' || tmps[i] == '\t') { + tmps.remove(i, 1); + i--; + } + } + currentString = tmps; +} + + +void QPIEvaluator::removeJunk() { + QChar cc; + bool junk = true; + int bcnt; + while (junk) { + if (currentString.left(1) != "(" || currentString.right(1) != ")") return; + bcnt = 1; + junk = false; + for (int i = 1; i < currentString.length(); i++) { + cc = currentString[i]; + if (cc == '(') bcnt++; + if (cc == ')') bcnt--; + if (bcnt == 0) { + if (i == currentString.length() - 1) { + currentString = currentString.mid(1, currentString.length() - 2); + elements.pop_front(); + elements.pop_back(); + junk = true; + break; + } else break; + } + } + } +} + + +void QPIEvaluator::replaceOperators() { + currentString.replace("==", "="); + currentString.replace("!=", ":"); + currentString.replace(">=", "}"); + currentString.replace("<=", "{"); + currentString.replace("&&", "&"); + currentString.replace("||", "|"); +} + + +void QPIEvaluator::makeOutput(QString & string) { + string.replace(":", "≠"); + string.replace("}", "≥"); + string.replace("{", "≤"); + string.replace("&", "⋀"); + string.replace("|", "⋁"); +} + + +void QPIEvaluator::findUnknownVariables() { + QString cvar; + unknownVars.clear(); + for (int i = 0; i < currentString.length(); i++) { + if (elements[i].var_num == -666) cvar += currentString[i]; + else { + if (cvar.length() == 0) continue; + unknownVars << cvar; + cvar = ""; + } + } + if (cvar.length() > 0) unknownVars << cvar; + unknownVars.removeDuplicates(); +} + + +bool QPIEvaluator::isSign(const QChar & ch) { + return ch == '+' || ch == '-' || + ch == '*' || ch == '/' || + ch == '%' || ch == '^' || + ch == '=' || ch == ':' || + ch == '>' || ch == '<' || + ch == '}' || ch == '{' || + ch == '&' || ch == '|'; +} + + +void QPIEvaluator::checkBrackets() { + QString tmps = currentString; + QChar fc, sc; + int bcnt = 0, bpos = 0, inserted = 0; + currentString = tmps; + for (int i = 0; i < tmps.length(); i++) { + if (tmps[i] == '(') { + if (bcnt == 0) bpos = i; + bcnt++; + } + if (tmps[i] == ')') { + if (bcnt == 0) { + currentString.insert(bpos + inserted, "("); + inserted++; + } else bcnt--; + } + } + if (bcnt > 0) currentString += QString(bcnt, ')'); + tmps = currentString; + for (int i = 0; i < tmps.length() - 1; i++) { + fc = tmps[i].toLower(); + sc = tmps[i + 1].toLower(); + if ((fc == ')' && sc == '(') || + (fc == ')' && sc >= '0' && sc <= '9') || + (fc == ')' && sc >= 'a' && sc <= 'z') ) tmps.insert(++i, '*'); + } + currentString = tmps; +} + + +bool QPIEvaluator::fillElements() { + int fstart, flen, cnum = 0, cpart = 0, cfunc; + QChar cc, nc, pc, fc = '!'; + bool numFound = false; + QString curfind, tmps = currentString; + elements.resize(tmps.length()); + for (int i = 0; i < elements.size(); i++) { + elements[i].type = QPIEvaluatorTypes::etVariable; + elements[i].var_num = -666; + } + currentVariables.clear(); + //qDebug().nospace() << "search for functions ..."; + for (int i = 0; i < content.functionsCount(); i++) { + curfind = content.function(i).identifier; + cfunc = i; //(int)content.function(i).type; + flen = curfind.length(); + fstart = 0; + while (fstart >= 0) { + fstart = tmps.indexOf(curfind, fstart); + if (fstart < 0) break; + if (tmps[fstart + flen] != '(') { + //currentString.insert(fstart + flen, "("); + fstart++; + continue; + } + for (int j = fstart; j < fstart + flen; j++) { + elements[j].set(QPIEvaluatorTypes::etFunction, cnum, cfunc); + tmps.replace(j, 1, fc); + } + cnum++; + } + } + cnum = 0; + //qDebug().nospace() << "search for variables ..."; + for (int i = 0; i < content.variablesCount(); i++) { + curfind = content.variable(i).name; + flen = curfind.length(); + fstart = 0; + while (fstart >= 0) { + fstart = tmps.indexOf(curfind, fstart); + if (fstart < 0) break; + for (int j = fstart; j < fstart + flen; j++) { + elements[j].set(QPIEvaluatorTypes::etVariable, cnum, i); + tmps.replace(j, 1, fc); + } + cnum++; + } + } + curfind = ""; + cnum = 1; + //qDebug().nospace() << "search for numbers ..."; + for (int i = 0; i < tmps.length(); i++) { + cc = tmps[i]; + /*if (cc == " " || cc == "(" || cc == ")") { + curfind = ""; + cpart = 0; + numFound = false; + continue; + }*/ + switch (cpart) { + case 0: + if ((cc >= '0' && cc <= '9')) {// || cc == '-' || cc == '+') { + curfind += cc; + cpart = 1; + continue; + } + if (cc == '.') { + curfind += cc; + cpart = 2; + continue; + } + if (cc == 'E') { + curfind += cc; + cpart = 3; + continue; + } + break; + case 1: + if (cc >= '0' && cc <= '9') { + curfind += cc; + continue; + } + if (cc == '.') { + curfind += cc; + cpart = 2; + continue; + } + if (cc == 'E') { + curfind += cc; + cpart = 3; + continue; + } + numFound = true; + break; + case 2: + if (cc >= '0' && cc <= '9') { + curfind += cc; + continue; + } + if (cc == 'E') { + curfind += cc; + cpart = 3; + continue; + } + numFound = true; + break; + case 3: + if ((cc >= '0' && cc <= '9') || cc == '-' || cc == '+') { + curfind += cc; + cpart = 4; + continue; + } + numFound = true; + break; + case 4: + if (cc >= '0' && cc <= '9') { + curfind += cc; + continue; + } + numFound = true; + break; + } + if (numFound) { + //qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble(); + currentVariables.push_back(QPIEvaluatorTypes::Variable("tmp" + QString::number(cnum), curfind.toDouble())); + for (int j = i - curfind.length(); j < i; j++) { + elements[j].set(QPIEvaluatorTypes::etNumber, cnum, -cnum); + tmps.replace(j, 1, fc); + } + curfind = ""; + cnum++; + cpart = 0; + numFound = false; + } + } + if (cpart > 0) { + //qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble(); + currentVariables.push_back(QPIEvaluatorTypes::Variable("tmp" + QString::number(cnum), curfind.toDouble())); + for (int j = tmps.length() - curfind.length(); j < tmps.length(); j++) { + elements[j].set(QPIEvaluatorTypes::etNumber, cnum, -cnum); + tmps.replace(j, 1, fc); + } + } + cc = nc = fc; + //qDebug().nospace() << "search for signes ..."; + for (int i = 0; i < tmps.length(); i++) { + cc = tmps[i]; + if (i > 0) pc = tmps[i - 1]; + else pc = fc; + if (i < tmps.length() - 1) nc = tmps[i + 1]; + else nc = fc; + if (cc == '(' || cc == ')' || cc == ',') { + elements[i].set(QPIEvaluatorTypes::etOperator, -1); + continue; + } + if (cc == '-' || cc == '+') { + elements[i].set(QPIEvaluatorTypes::etOperator, -1); + if (i < tmps.length() - 1) if (elements[i + 1].type == QPIEvaluatorTypes::etVariable || + elements[i + 1].type == QPIEvaluatorTypes::etFunction) continue; + if ((pc == '(' || isSign(pc) || i == 0) && i < tmps.length() - 1) { + if (elements[i + 1].type != QPIEvaluatorTypes::etOperator) { + cnum = elements[i + 1].num; + elements[i].set(QPIEvaluatorTypes::etNumber, cnum); + tmps.replace(i, 1, fc); + ///cout << "found sign " << cc << " :" << cnum - 1 << endl; + if (cc == '-' && currentVariables.size() >= cnum) + currentVariables[cnum - 1].value = -currentVariables[cnum - 1].value; + //i++; + continue; + } + } + } + if (isSign(cc)) { + elements[i].set(QPIEvaluatorTypes::etOperator, -1); + continue; + } + } + /* + qDebug().nospace() << tmps; + cout << " "; + for (int i = 0; i < elements.size(); i++) { + switch (elements[i].type) { + case etFunction: cout << "f"; break; + case etNumber: cout << "n"; break; + case etOperator: cout << "o"; break; + case etVariable: cout << "v"; break; + } + } + cout << endl; + */ + return false; + //for (int i = 0; i < currentVariables.size(); i++) qDebug() << "var " << i << ": " << currentVariables[i].value.real(); +} + + +bool QPIEvaluator::setSignes() { + int inserted = 0, ni, pi = 0, needInsert = 0; + QChar fc, sc, pc; + QString tmps = currentString; + for (int i = 0; i < tmps.length() - 1; i++) { + needInsert = 0; + ni = i + 1; + if (i > 0) pi = i - 1; + fc = tmps[i].toLower(); + sc = tmps[ni].toLower(); + pc = tmps[pi].toLower(); + //if (elements[i].type == etOperator || elements[ni].type == etVariable) continue; + if (fc == ',' || sc == ',') continue; + if (elements[i].type == QPIEvaluatorTypes::etOperator && elements[ni].type == QPIEvaluatorTypes::etOperator) continue; + if (fc == ')' && (elements[ni].type == QPIEvaluatorTypes::etNumber || elements[ni].type == QPIEvaluatorTypes::etVariable || elements[ni].type == QPIEvaluatorTypes::etFunction)) needInsert = 1; + if (sc == '(' && (elements[i].type == QPIEvaluatorTypes::etNumber || elements[i].type == QPIEvaluatorTypes::etVariable)) needInsert = 1; + if (elements[i].type == QPIEvaluatorTypes::etNumber && elements[ni].type == QPIEvaluatorTypes::etNumber && elements[i].num != elements[ni].num) needInsert = 1; + if (elements[i].type == QPIEvaluatorTypes::etVariable && elements[ni].type == QPIEvaluatorTypes::etVariable && elements[i].num != elements[ni].num) needInsert = 1; + if ((elements[i].type == QPIEvaluatorTypes::etNumber && elements[ni].type == QPIEvaluatorTypes::etVariable) || (elements[i].type == QPIEvaluatorTypes::etVariable && elements[ni].type == QPIEvaluatorTypes::etNumber)) needInsert = 1; + if ((elements[i].type == QPIEvaluatorTypes::etNumber || elements[i].type == QPIEvaluatorTypes::etVariable) && elements[ni].type == QPIEvaluatorTypes::etFunction) needInsert = 1; + if (elements[i].type == QPIEvaluatorTypes::etFunction && elements[ni].type == QPIEvaluatorTypes::etFunction && elements[i].num != elements[ni].num) needInsert = 2; + if (elements[i].type == QPIEvaluatorTypes::etFunction && elements[ni].type != QPIEvaluatorTypes::etFunction && sc != '(') needInsert = 2; + if (elements[pi].type == QPIEvaluatorTypes::etOperator && (elements[ni].type == QPIEvaluatorTypes::etFunction || elements[ni].type == QPIEvaluatorTypes::etVariable) && fc == '-') needInsert = 3; + switch (needInsert) { + case 1: + currentString.insert(ni + inserted, "*"); + elements.insert(ni + inserted, QPIEvaluatorTypes::Element(QPIEvaluatorTypes::etOperator, -1)); + //inserted++; + //i++; + return true; + /*case 2: + currentString.insert(ni + inserted, ")"); + currentString.insert(ni + inserted, "("); + elements.insert(ni + inserted, Element(etOperator, -1)); + elements.insert(ni + inserted, Element(etOperator, -1)); + inserted++; + i++; + return true;*/ + case 3: + currentString.insert(ni + inserted, "1*"); + elements.insert(ni + inserted, QPIEvaluatorTypes::Element(QPIEvaluatorTypes::etOperator, -1)); + //inserted; + //i++; + return true; + } + } + /*if (elements[tmps.length() - 1].type == etFunction) { + currentString.insert(tmps.length() + inserted, ")"); + currentString.insert(tmps.length() + inserted, "("); + elements.insert(tmps.length() + inserted, Element(etOperator, -1)); + elements.insert(tmps.length() + inserted, Element(etOperator, -1)); + return true; + }*/ + return false; +} + + +void QPIEvaluator::convert() { + int j; + QPIEvaluatorTypes::Element ce, pe; + for (int i = 0; i < currentString.length(); i++) { + pe = elements[i]; + if (pe.type != QPIEvaluatorTypes::etFunction) continue; + j = i + 1; + while (j < currentString.length()) { + ce = elements[j]; + if (ce != pe) break; + j++; + } + currentString.replace(i, j - i, " "); + for (int k = i + 1; k < j; k++) elements.remove(i); + //i++; + } + for (int i = 0; i < currentString.length(); i++) { + pe = elements[i]; + if (pe.type != QPIEvaluatorTypes::etNumber) continue; + j = i + 1; + while (j < currentString.length()) { + ce = elements[j]; + if (ce != pe) break; + j++; + } + currentString.replace(i, j - i, " "); + for (int k = i + 1; k < j; k++) elements.remove(i); + //i++; + } + for (int i = 0; i < currentString.length(); i++) { + pe = elements[i]; + if (pe.type != QPIEvaluatorTypes::etVariable) continue; + j = i + 1; + while (j < currentString.length()) { + ce = elements[j]; + if (ce != pe) break; + j++; + } + currentString.replace(i, j - i, " "); + for (int k = i + 1; k < j; k++) elements.remove(i); + //i++; + } + /*qDebug().nospace() << currentString; + cout << " "; + for (int i = 0; i < elements.size(); i++) { + switch (elements[i].type) { + case etFunction: cout << "f"; break; + case etNumber: cout << "n"; break; + case etOperator: cout << "o"; break; + case etVariable: cout << "v"; break; + } + } + cout << endl;*/ +} + + + +const QString & QPIEvaluator::preprocess(const QString & string) { + static QString ret; + int lind; + ret = prepare(string); + convert(); + instructions.clear(); + //qDebug() << preproc->currentString; + variables = currentVariables; + lind = parse(currentString); + if (instructions.size() == 0) { + variables.push_back(QPIEvaluatorTypes::Variable()); + instructions.push_back(QPIEvaluatorTypes::Instruction(QPIEvaluatorTypes::oNone, QVector(1, lind), -variables.size())); + } + kvars = &(content.variables); + /* + cout << endl << "variables:" << endl; + for (int i = 0; i < variables.size(); i++) + cout << i << " value = " << variables[i].value << endl; + + cout << endl << "instructions:" << endl; + for (int i = 0; i < instructions.size(); i++) { + cout << i << endl; + cout << " operation " << instructions[i].operation << endl; + cout << " operators: "; + for (int j = 0; j < instructions[i].operators.size(); j++) + cout << instructions[i].operators[j] << "; "; + cout << endl << " function " << instructions[i].function << endl; + cout << " out " << instructions[i].out << endl; + } + */ + makeOutput(ret); + return ret; +} + + +QPIEvaluatorTypes::Operation QPIEvaluator::operationInOrder(const int & index) { + switch (index) { + case 0: return QPIEvaluatorTypes::oPower; + case 1: return QPIEvaluatorTypes::oMultiply; + case 2: return QPIEvaluatorTypes::oDivide; + case 3: return QPIEvaluatorTypes::oResidue; + case 4: return QPIEvaluatorTypes::oAdd; + case 5: return QPIEvaluatorTypes::oSubtract; + case 6: return QPIEvaluatorTypes::oEqual; + case 7: return QPIEvaluatorTypes::oNotEqual; + case 8: return QPIEvaluatorTypes::oGreaterEqual; + case 9: return QPIEvaluatorTypes::oSmallerEqual; + case 10: return QPIEvaluatorTypes::oGreater; + case 11: return QPIEvaluatorTypes::oSmaller; + case 12: return QPIEvaluatorTypes::oAnd; + case 13: return QPIEvaluatorTypes::oOr; + default: return QPIEvaluatorTypes::oNone; + } +} + + +int QPIEvaluator::parse(const QString & string, int offset) { + int slen = string.length(), /*facnt,*/ farg, bcnt, k; + QChar cc; + QPIEvaluatorTypes::Element ce; + QPIEvaluatorTypes::Function cfunc; + QPIEvaluatorTypes::Operation coper; + QString sbrackets, carg; + QVector args, atmp; + QVector opers; + + ///qDebug() << "to parse :" + string; + ///cout << " "; for (int i = 0; i < slen; i++) cout << preproc->elements[i + offset].type; cout << endl; + + for (int i = 0; i < slen; i++) { + ce = elements[i + offset]; + cc = string[i]; + switch (ce.type) { + case QPIEvaluatorTypes::etNumber: + args.push_back(ce.var_num); + continue; + case QPIEvaluatorTypes::etVariable: + args.push_back(ce.var_num); + continue; + case QPIEvaluatorTypes::etFunction: + i++; + cfunc = content.function(ce.var_num); + //facnt = cfunc.arguments; + atmp.clear(); + bcnt = farg = 1; + ///qDebug() << "function: " + cfunc.identifier; + //for (int k = 0; k < facnt; k++) { + carg = ""; + k = i + 1; + //if (string.size() <= k || k < 0) return -666; + while (bcnt > 0) { + //if (k < facnt - 1) fcomma = string.indexOf(',', j); + cc = string[k]; + switch (cc.toLatin1()) { + case '(': bcnt++; break; + case ')': + bcnt--; + if (bcnt == 0) { + ///qDebug() << "arument: " << carg; + atmp.push_back(parse(carg, k + offset - carg.length())); + k++; + carg = ""; + if (atmp.size() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back(); + continue; + } + break; + case ',': + if (bcnt == 1) { + ///qDebug() << "arument: " << carg; + atmp.push_back(parse(carg, k + offset - carg.length())); + k++; + carg = ""; + if (atmp.size() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back(); + continue; + } + break; + } + carg += cc; + k++; + } + i = k - 1; + if (farg > 0) { + variables.push_back(QPIEvaluatorTypes::Variable()); + farg = -variables.size(); + } + instructions.push_back(QPIEvaluatorTypes::Instruction(QPIEvaluatorTypes::oFunction, atmp, farg, ce.var_num)); + args.push_back(farg); + //for (int i = 0; i < args.size(); i++) cout << preproc->currentVariables[-args[i]].value << endl; + //i = j + 1; + continue; + case QPIEvaluatorTypes::etOperator: + //qDebug() << "operator: " << cc; + if (cc == '(') { + sbrackets = inBrackets(string.right(slen - i)); + args.push_back(parse(sbrackets, i + offset + 1)); + i += sbrackets.length() + 1; + continue; + } + if (cc == '+') {opers.push_back(QPIEvaluatorTypes::oAdd); continue;} + if (cc == '-') {opers.push_back(QPIEvaluatorTypes::oSubtract); continue;} + if (cc == '*') {opers.push_back(QPIEvaluatorTypes::oMultiply); continue;} + if (cc == '/') {opers.push_back(QPIEvaluatorTypes::oDivide); continue;} + if (cc == '%') {opers.push_back(QPIEvaluatorTypes::oResidue); continue;} + if (cc == '^') {opers.push_back(QPIEvaluatorTypes::oPower); continue;} + if (cc == '=') {opers.push_back(QPIEvaluatorTypes::oEqual); continue;} + if (cc == ':') {opers.push_back(QPIEvaluatorTypes::oNotEqual); continue;} + if (cc == '}') {opers.push_back(QPIEvaluatorTypes::oGreaterEqual); continue;} + if (cc == '{') {opers.push_back(QPIEvaluatorTypes::oSmallerEqual); continue;} + if (cc == '>') {opers.push_back(QPIEvaluatorTypes::oGreater); continue;} + if (cc == '<') {opers.push_back(QPIEvaluatorTypes::oSmaller); continue;} + if (cc == '&') {opers.push_back(QPIEvaluatorTypes::oAnd); continue;} + if (cc == '|') {opers.push_back(QPIEvaluatorTypes::oOr); continue;} + } + } + /* + cout << "stack: " << endl << "args: "; + for (int i = 0; i < args.size(); i++) cout << args[i] << ", "; + cout << endl << "opers: "; + for (int i = 0; i < opers.size(); i++) cout << opers[i] << ", "; + */ + if (opers.size() == 0) { + if (args.size() > 0) return args.back(); + else return -666; + } + for (int i = 0; i < QPIEvaluatorTypes::operationCount; i++) { + coper = operationInOrder(i); + for (int j = 0; j < opers.size(); j++) { + if (coper == QPIEvaluatorTypes::oDivide || coper == QPIEvaluatorTypes::oMultiply) { + if (opers[j] != QPIEvaluatorTypes::oDivide && opers[j] != QPIEvaluatorTypes::oMultiply) continue; + } else { + if (opers[j] != coper) continue; + } + atmp.clear(); + if (j < args.size() && j >= 0) atmp.push_back(args[j]); + else atmp.push_back(-666); + if (j + 1 < args.size() && j >= -1) atmp.push_back(args[j + 1]); + else atmp.push_back(-666); + farg = 1; + if (atmp[0] < 0) farg = atmp[0]; + else { + if (atmp[1] < 0) farg = atmp[1]; + else { + variables.push_back(QPIEvaluatorTypes::Variable()); + farg = -variables.size(); + } + } + instructions.push_back(QPIEvaluatorTypes::Instruction(opers[j], atmp, farg)); + if (j >= 0 && j < args.size()) { + args.remove(j); + if (j < args.size()) args[j] = farg; + } + opers.remove(j); + j--; + } + } + return instructions.back().out; + ///cout << endl; +} + + +bool QPIEvaluator::check() { + QPIEvaluatorTypes::Instruction ci; + bool error; + if (unknownVars.size() > 0) { + lastError = "Unknown variables: \"" + unknownVars.join("\", \"") + "\""; + return false; + } + for (int i = 0; i < instructions.size(); i++) { + error = false; + ci = instructions[i]; + switch (ci.operation) { + case QPIEvaluatorTypes::oNone: break; + case QPIEvaluatorTypes::oFunction: + for (int j = 0; j < ci.operators.size(); j++) { + if (ci.operators[j] == -666) { //(ci.operators[j] < -variables.size() || ci.operators[j] >= kvars->size()) { + error = true; + break; + } + } + if (ci.operators.size() != content.function(ci.function).arguments || error) { + lastError = "Invalid arguments count for function \"" + content.function(ci.function).identifier + "\""; + return false; + } + break; + default: + if (ci.operators[0] == -666 || ci.operators[1] == -666) error = true; + if (ci.operators.size() != 2 || error) { + lastError = "Invalid arguments count for operation \" " + operationChar(ci.operation) + " \""; + return false; + } + break; + } + if (ci.out < -variables.size()) { + lastError = "Invalid variable index \"" + QString::number(ci.out) + "\""; + return false; + } + for (int j = 0; j < ci.operators.size(); j++) { + if (ci.operators[j] < -variables.size() || ci.operators[j] >= kvars->size()) { + lastError = "Invalid variable index \"" + QString::number(ci.operators[j]) + "\""; + return false; + } + } + } + return true; +} + + +QString QPIEvaluator::inBrackets(const QString & string) { + int slen = string.length(), bcnt = 0; + QChar cc; + for (int i = 0; i < slen; i++) { + cc = string[i]; + if (cc == '(') bcnt++; + if (cc == ')') { + bcnt--; + if (bcnt == 0) return string.mid(1, i - 1); + } + } + return QString(); +} + + +QString QPIEvaluator::operationChar(const QPIEvaluatorTypes::Operation & operation) { + switch (operation) { + case QPIEvaluatorTypes::oAdd: return "+"; + case QPIEvaluatorTypes::oSubtract: return "-"; + case QPIEvaluatorTypes::oMultiply: return "*"; + case QPIEvaluatorTypes::oDivide: return "/"; + case QPIEvaluatorTypes::oPower: return "^"; + case QPIEvaluatorTypes::oResidue: return "%"; + case QPIEvaluatorTypes::oEqual: return "="; + case QPIEvaluatorTypes::oNotEqual: return ("≠"); + case QPIEvaluatorTypes::oGreaterEqual: return ("≥"); + case QPIEvaluatorTypes::oSmallerEqual: return ("≤"); + case QPIEvaluatorTypes::oGreater: return ">"; + case QPIEvaluatorTypes::oSmaller: return "<"; + case QPIEvaluatorTypes::oAnd: return ("⋀"); + case QPIEvaluatorTypes::oOr: return ("⋁"); + default: return "???"; + } +} + + +inline complexd QPIEvaluator::residue(const complexd & f, const complexd & s) { + complexd ret; + if (s.real() != 0.) ret = complexd(f.real() - ((int)(f.real() / s.real())) * s.real(), 0.); + if (s.imag() != 0.) ret = complexd(ret.real(), f.imag() - ((int)(f.imag() / s.imag())) * s.imag()); + return ret; +} + + +inline void QPIEvaluator::execFunction(const QPIEvaluatorTypes::Instruction & ci) { + QPIEvaluatorTypes::Function cfunc = content.function(ci.function); + int oi = -ci.out - 1; + complexd tmp, stmp; + double ldtmp; + //qDebug() << "function " << (int)cfunc.type; + switch (cfunc.type) { + case QPIEvaluatorTypes::bfSin: + tmpvars[oi].value = sin(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfCos: + tmpvars[oi].value = cos(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfTg: + tmpvars[oi].value = tan(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfCtg: + tmp = tan(value(ci.operators[0])); + if (tmp == complexd_0) tmpvars[oi].value = 0.; + else tmpvars[oi].value = complexd_1 / tmp; + break; + case QPIEvaluatorTypes::bfArcsin: + tmpvars[oi].value = asinc_qpie(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfArccos: + tmpvars[oi].value = acosc_qpie(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfArctg: + tmpvars[oi].value = atanc_qpie(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfArcctg: + tmp = atanc_qpie(value(ci.operators[0])); + if (tmp == complexd_0) tmpvars[oi].value = 0.; + else tmpvars[oi].value = complexd_1 / tmp; + break; + case QPIEvaluatorTypes::bfSh: + tmpvars[oi].value = sinh(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfCh: + tmpvars[oi].value = cosh(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfTh: + tmpvars[oi].value = tanh(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfCth: + tmp = tanh(value(ci.operators[0])); + if (tmp == complexd_0) tmpvars[oi].value = 0.; + else tmpvars[oi].value = complexd_1 / tmp; + break; + case QPIEvaluatorTypes::bfAbs: + tmpvars[oi].value = abs(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfSqrt: + tmpvars[oi].value = sqrt(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfSqr: + tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[0]); + break; + case QPIEvaluatorTypes::bfExp: + tmpvars[oi].value = exp(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfPow: + tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1])); + break; + case QPIEvaluatorTypes::bfLn: + tmpvars[oi].value = log(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfLg: + tmpvars[oi].value = log10(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfLog: + tmp = log(value(ci.operators[1])); + if (tmp == complexd_0) tmpvars[oi].value = 0.; + else tmpvars[oi].value = log(value(ci.operators[0])) / tmp; + break; + case QPIEvaluatorTypes::bfRe: + tmpvars[oi].value = value(ci.operators[0]).real(); + break; + case QPIEvaluatorTypes::bfIm: + tmpvars[oi].value = value(ci.operators[0]).imag(); + break; + case QPIEvaluatorTypes::bfArg: + tmpvars[oi].value = arg(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfLen: + tmpvars[oi].value = abs(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfConj: + tmpvars[oi].value = conj(value(ci.operators[0])); + break; + case QPIEvaluatorTypes::bfSign: + ldtmp = value(ci.operators[0]).real(); + tmpvars[oi].value = ldtmp >= 0. ? complexd_1 : -complexd_1; + break; + case QPIEvaluatorTypes::bfRad: + tmpvars[oi].value = value(ci.operators[0]) * complexd(deg2rad_qpie, 0.); + break; + case QPIEvaluatorTypes::bfDeg: + tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg_qpie, 0.); + break; + case QPIEvaluatorTypes::bfRandom: + tmp = static_cast(qrand()) / RAND_MAX; + stmp = value(ci.operators[1]) - value(ci.operators[0]); + tmpvars[oi].value = value(ci.operators[0]) + tmp * stmp; + break; + default: break; + } +} + + +inline bool QPIEvaluator::execInstructions() { + QPIEvaluatorTypes::Instruction ci; + int oi; + complexd tmp; + tmpvars = variables; + //cout << "var count " << tmpvars.size() << endl; + for (int i = 0; i < instructions.size(); i++) { + ci = instructions[i]; + oi = -ci.out - 1; + //cout << value(ci.operators[0]) << operationChar(ci.operation) << value(ci.operators[1]) << ", " << oi << endl; + switch (ci.operation) { + case QPIEvaluatorTypes::oAdd: + tmpvars[oi].value = value(ci.operators[0]) + value(ci.operators[1]); + break; + case QPIEvaluatorTypes::oSubtract: + tmpvars[oi].value = value(ci.operators[0]) - value(ci.operators[1]); + break; + case QPIEvaluatorTypes::oMultiply: + tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[1]); + break; + case QPIEvaluatorTypes::oDivide: + tmp = value(ci.operators[1]); + if (tmp == complexd(0., 0.)) tmpvars[oi].value = 0.; + else tmpvars[oi].value = value(ci.operators[0]) / tmp; + break; + case QPIEvaluatorTypes::oResidue: + tmpvars[oi].value = residue(value(ci.operators[0]), value(ci.operators[1])); + break; + case QPIEvaluatorTypes::oPower: + tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1])); + break; + case QPIEvaluatorTypes::oEqual: + tmpvars[oi].value = value(ci.operators[0]) == value(ci.operators[1]); + break; + case QPIEvaluatorTypes::oNotEqual: + tmpvars[oi].value = value(ci.operators[0]) != value(ci.operators[1]); + break; + case QPIEvaluatorTypes::oGreaterEqual: + tmpvars[oi].value = value(ci.operators[0]).real() >= value(ci.operators[1]).real(); + break; + case QPIEvaluatorTypes::oSmallerEqual: + tmpvars[oi].value = value(ci.operators[0]).real() <= value(ci.operators[1]).real(); + break; + case QPIEvaluatorTypes::oGreater: + tmpvars[oi].value = value(ci.operators[0]).real() > value(ci.operators[1]).real(); + break; + case QPIEvaluatorTypes::oSmaller: + tmpvars[oi].value = value(ci.operators[0]).real() < value(ci.operators[1]).real(); + break; + case QPIEvaluatorTypes::oAnd: + tmpvars[oi].value = value(ci.operators[0]).real() > 0. && value(ci.operators[1]).real() > 0.; + break; + case QPIEvaluatorTypes::oOr: + tmpvars[oi].value = value(ci.operators[0]).real() > 0. || value(ci.operators[1]).real() > 0.; + break; + case QPIEvaluatorTypes::oFunction: + execFunction(ci); + break; + case QPIEvaluatorTypes::oNone: + tmpvars[oi].value = value(ci.operators[0]); + break; + } + } + if (!instructions.isEmpty()) + out = value(instructions.back().out); + return true; +} + + +bool QPIEvaluator::check(const QString & string) { + currentString = preprocess(string); + correct = check(); + if (!correct) + return false; + lastError = "Correct"; + return true; +} + + +int QPIEvaluator::setVariable(const QString & name, complexd value) { + int i = content.findVariable(name); + if (i < 0) { + content.addVariable(name, value); + return content.findVariable(name); + } else { + content.setVariableValue(i, value); + return i; + } + return -1; +} + + +complexd QPIEvaluator::evaluate() { + if (!execInstructions()) out = 0.; + if (fabs(out.real()) < 1E-300) out = complexd(0., out.imag()); + if (fabs(out.imag()) < 1E-300) out = complexd(out.real(), 0.); + return out; +} diff --git a/qad/utils/qpievaluator.h b/qad/utils/qpievaluator.h new file mode 100644 index 0000000..4815b45 --- /dev/null +++ b/qad/utils/qpievaluator.h @@ -0,0 +1,196 @@ +/* + Peri4 Paint + Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef QPIEVALUATOR_H +#define QPIEVALUATOR_H + +#include +#include +#include +#include +#include +#include + +#ifndef PIP_MATH_COMPLEX +#define QPIEVALUATOR_COMPLEX +typedef std::complex complexd; +const complexd complexd_i(0., 1.); +const complexd complexd_0(0.); +const complexd complexd_1(1.); +#endif +const double deg2rad_qpie = atan(1.) / 45.; +const double rad2deg_qpie = 45. / atan(1.); + +inline complexd round_qpie(const complexd & c) {return complexd(round(c.real()), round(c.imag()));} +inline complexd floor_qpie(const complexd & c) {return complexd(floor(c.real()), floor(c.imag()));} +inline complexd ceil_qpie(const complexd & c) {return complexd(ceil(c.real()), ceil(c.imag()));} +inline complexd atanc_qpie(const complexd & c) {return -complexd(-0.5, 1.) * log((complexd_1 + complexd_i * c) / (complexd_1 - complexd_i * c));} +inline complexd asinc_qpie(const complexd & c) {return -complexd_i * log(complexd_i * c + sqrt(complexd_1 - c * c));} +inline complexd acosc_qpie(const complexd & c) {return -complexd_i * log(c + complexd_i * sqrt(complexd_1 - c * c));} + +namespace QPIEvaluatorTypes { + static const int operationCount = 14; + + enum eType {etNumber, etOperator, etVariable, etFunction}; + enum Operation {oNone, oAdd, oSubtract, oMultiply, oDivide, oResidue, oPower, + oEqual, oNotEqual, oGreater, oSmaller, oGreaterEqual, oSmallerEqual, + oAnd, oOr, oFunction}; + enum BaseFunctions {bfUnknown, bfSin, bfCos, bfTg, bfCtg, + bfArcsin, bfArccos, bfArctg, bfArcctg, + bfExp, bfRandom, bfSh, bfCh, bfTh, bfCth, + bfSqrt, bfSqr, bfPow, bfAbs, + bfLn, bfLg, bfLog, bfSign, + bfIm, bfRe, bfArg, bfLen, bfConj, + bfRad, bfDeg}; + + struct Instruction { + Instruction() {;} + Instruction(Operation oper, QVector opers, int out_ind, int func = -1) { + operation = oper; operators = opers; out = out_ind; function = func;} + Operation operation; + QVector operators; + int out; + int function;}; + struct Element { + Element() {;} + Element(eType new_type, int new_num, int new_var_num = -1) {set(new_type, new_num, new_var_num);} + void set(eType new_type, int new_num, int new_var_num = -1) {type = new_type; num = new_num; var_num = new_var_num;} + eType type; + int num; + int var_num;}; + struct Function { + Function() {arguments = 0; type = bfUnknown;} + Function(const QString & name, int args, BaseFunctions ftype) {identifier = name; arguments = args; type = ftype;} + QString identifier; + BaseFunctions type; + int arguments;}; + struct Variable { + Variable() {value = 0.;} + Variable(const QString & var_name, complexd val) {name = var_name; value = val;} + QString name; + complexd value;}; + inline bool operator <(const Variable & s1, const Variable & s2) { + if (s1.name.size() != s2.name.size()) + return s1.name.size() > s2.name.size(); + return s1.name > s2.name; + } +}; +/* + ≠ : + ≥ } + ≤ { + ⋀ & + ⋁ | +*/ +class QPIEvaluatorContent +{ + friend class QPIEvaluator; +public: + QPIEvaluatorContent(); + ~QPIEvaluatorContent() {;} + + void addFunction(const QString & name, int args = 1) {functions.push_back(QPIEvaluatorTypes::Function(name, args, getBaseFunction(name)));} + void addVariable(const QString & name, const complexd & val = 0., bool sort = true) {variables.push_back(QPIEvaluatorTypes::Variable(name, val)); if (sort) sortVariables();} + int functionsCount() const {return functions.size();} + int variablesCount() const {return variables.size();} + int customVariablesCount() const {return variables.size() - cv_count;} + int findFunction(const QString & name) const {return func_index.value(name, -1);} + int findVariable(const QString & name) const {return var_index.value(name, -1);} + QPIEvaluatorTypes::Function function(int index) {if (index < 0 || index >= functions.size()) return QPIEvaluatorTypes::Function(); return functions[index];} + QPIEvaluatorTypes::Variable variable(int index) {if (index < 0 || index >= variables.size()) return QPIEvaluatorTypes::Variable(); return variables[index];} + QPIEvaluatorTypes::Function function(const QString & name) {return function(findFunction(name));} + QPIEvaluatorTypes::Variable variable(const QString & name) {return variable(findVariable(name));} + QPIEvaluatorTypes::Variable customVariable(int index) {if (index < cv_count || index >= variables.size() + cv_count) return QPIEvaluatorTypes::Variable(); return variables[index + cv_count];} + bool setVariableValue(int index, complexd new_value); + bool setVariableName(int index, const QString & new_name); + bool setVariableValue(const QString & var_name, const complexd & new_value) {return setVariableValue(findVariable(var_name), new_value);} + bool setVariableName(const QString & var_name, const QString & new_name) {return setVariableName(findVariable(var_name), new_name);} + void removeVariable(int index) {variables.remove(index);} + void removeVariable(const QString & var_name) {removeVariable(findVariable(var_name));} + void clearCustomVariables(); + void sortVariables(); + QPIEvaluatorTypes::BaseFunctions getBaseFunction(const QString & name); + +private: + QVector functions; + QVector variables; + QMap var_index, func_index; + int cv_count; + +}; + +class QPIEvaluator +{ +public: + QPIEvaluator() {correct = false ;} + ~QPIEvaluator() {;} + + bool check(const QString & string); + bool isCorrect() const {return correct;} + int setVariable(const QString & name, complexd value = 0.); + void setVariable(int index, complexd value = 0.) {if (index >= 0 && index < content.variablesCount()) content.setVariableValue(index, value);} + void setCustomVariableValue(int index, complexd value = 0.) {content.variables[index + content.cv_count].value = value;} + complexd evaluate(); + void removeVariable(const QString & name) {content.removeVariable(name);} + void clearCustomVariables() {content.clearCustomVariables();} + int variableIndex(const QString & name) const {return content.findVariable(name);} + const QStringList & unknownVariables() const {return unknownVars;} + const QString & expression() const {return currentString;} + const QString & error() const {return lastError;} + const complexd & lastResult() const {return out;} + static QString inBrackets(const QString & string); + + QPIEvaluatorContent content; + +private: + const QString & prepare(const QString & string); + const QString & preprocess(const QString & string); + int parse(const QString & string, int offset = 0); + void convert(); + void checkBrackets(); + void removeSpaces(); + void findUnknownVariables(); + void removeJunk(); + void replaceOperators(); + void makeOutput(QString & string); + bool fillElements(); + bool setSignes(); + bool isSign(const QChar & ch); + QString inverse(const QString & string) {int len = string.length(); QString s; for (int i = 0; i < len; i++) s += string[len - i - 1]; return s;} + bool check(); + bool execInstructions(); + QString operationChar(const QPIEvaluatorTypes::Operation & operation); + QPIEvaluatorTypes::Operation operationInOrder(const int & index); + complexd value(const int & index) {if (index < 0) return tmpvars[-index - 1].value; else return kvars->at(index).value;} + inline complexd residue(const complexd & f, const complexd & s); + inline void execFunction(const QPIEvaluatorTypes::Instruction & ci); + + QVector elements; + QVector currentVariables, variables, tmpvars, * kvars; + QVector instructions; + QStringList unknownVars; + QString currentString, lastError; + complexd out; + bool correct; + +}; + +inline bool operator ==(QPIEvaluatorTypes::Element e1, QPIEvaluatorTypes::Element e2) {return (e1.type == e2.type && e1.num == e2.num);} +inline bool operator !=(QPIEvaluatorTypes::Element e1, QPIEvaluatorTypes::Element e2) {return (e1.type != e2.type || e1.num != e2.num);} + +#endif // QPIEVALUATOR_H diff --git a/qad/widgets/CMakeLists.txt b/qad/widgets/CMakeLists.txt new file mode 100644 index 0000000..2f09131 --- /dev/null +++ b/qad/widgets/CMakeLists.txt @@ -0,0 +1,2 @@ +set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} qad_utils) +qad_project(widgets "${LIBS}") diff --git a/qad/widgets/chardialog.cpp b/qad/widgets/chardialog.cpp new file mode 100644 index 0000000..992564f --- /dev/null +++ b/qad/widgets/chardialog.cpp @@ -0,0 +1,151 @@ +#include "chardialog.h" +#include "ui_chardialog.h" + + +CharDialog::CharDialog(QWidget * parent): QDialog(parent) { + ui = new Ui::CharDialog(); + ui->setupUi(this); + QChar c; + int k; + for (int i = 0; i < 256; ++i) { + for (int j = 0; j < 256; ++j) { + c = QChar(j, i); + k = c.category(); + if (chars.size() <= k) + chars.resize(k + 1); + if (!c.isPrint()) continue; + + chars[k].push_back(c); + } + } + size = 30; + QStringList cat; + cat << tr("No Category") << tr("Mark NonSpacing") << tr("Mark SpacingCombining") << tr("Mark Enclosing") + << tr("Number DecimalDigit") << tr("Number Letter") << tr("Number Other") << tr("Separator Space") + << tr("Separator Line") << tr("Separator Paragraph") << tr("Other Control") << tr("Other Format") + << tr("Other Surrogate") << tr("Other PrivateUse") << tr("Other NotAssigned") << tr("Letter Uppercase") + << tr("Letter Lowercase") << tr("Letter Titlecase") << tr("Letter Modifier") << tr("Letter Other") + << tr("Punctuation Connector") << tr("Punctuation Dash") << tr("Punctuation Open") << tr("Punctuation Close") + << tr("Punctuation InitialQuote") << tr("Punctuation FinalQuote") << tr("Punctuation Other") << tr("Symbol Math") + << tr("Symbol Currency") << tr("Symbol Modifier") << tr("Symbol Other"); + ui->comboCategory->addItems(cat); + ui->spinSize->setValue(size); + ui->comboCategory->setCurrentIndex(27); + ui->tableChars->viewport()->installEventFilter(this); +} + + +CharDialog::~CharDialog() { + delete ui; +} + + +void CharDialog::setCharFont(const QFont & f) { + QFont fnt = ui->tableChars->font(); + fnt.setFamily(f.family()); + ui->tableChars->setFont(fnt); +} + + +void CharDialog::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + QStringList cat; + cat << tr("No Category") << tr("Mark NonSpacing") << tr("Mark SpacingCombining") << tr("Mark Enclosing") + << tr("Number DecimalDigit") << tr("Number Letter") << tr("Number Other") << tr("Separator Space") + << tr("Separator Line") << tr("Separator Paragraph") << tr("Other Control") << tr("Other Format") + << tr("Other Surrogate") << tr("Other PrivateUse") << tr("Other NotAssigned") << tr("Letter Uppercase") + << tr("Letter Lowercase") << tr("Letter Titlecase") << tr("Letter Modifier") << tr("Letter Other") + << tr("Punctuation Connector") << tr("Punctuation Dash") << tr("Punctuation Open") << tr("Punctuation Close") + << tr("Punctuation InitialQuote") << tr("Punctuation FinalQuote") << tr("Punctuation Other") << tr("Symbol Math") + << tr("Symbol Currency") << tr("Symbol Modifier") << tr("Symbol Other"); + int pi = ui->comboCategory->currentIndex(); + ui->comboCategory->clear(); + ui->comboCategory->addItems(cat); + ui->comboCategory->setCurrentIndex(pi); + return; + } + QDialog::changeEvent(e); +} + + +bool CharDialog::eventFilter(QObject * o, QEvent * e) { + if (o == ui->tableChars->viewport()) { + if (e->type() != QEvent::Wheel) + return QDialog::eventFilter(o, e); + qApp->sendEvent(ui->verticalScroll, e); + } + return QDialog::eventFilter(o, e); +} + + +void CharDialog::resizeEvent(QResizeEvent * ) { + int r = ui->tableChars->contentsRect().height() / csize, c = ui->tableChars->contentsRect().width() / csize; + ui->tableChars->setRowCount(r); + ui->tableChars->setColumnCount(c); + for (int i = 0; i < r; ++i) { + for (int j = 0; j < c; ++j) { + if (ui->tableChars->item(i, j) == 0) { + ui->tableChars->setItem(i, j, new QTableWidgetItem()); + ui->tableChars->item(i, j)->setTextAlignment(Qt::AlignCenter); + } + } + } + on_comboCategory_currentIndexChanged(ui->comboCategory->currentIndex()); +} + + +void CharDialog::clear() { + for (int i = 0; i < ui->tableChars->rowCount(); ++i) + for (int j = 0; j < ui->tableChars->columnCount(); ++j) + ui->tableChars->item(i, j)->setText(QString()); +} + + +void CharDialog::on_comboCategory_currentIndexChanged(int index) { + if (index < 0) return; + int r = ui->tableChars->rowCount(), c = ui->tableChars->columnCount(), m; + cur = &chars[index]; + if (r == 0) return; + m = (cur->size() - 2) / c - r + 1; + if (m < 0) m = 0; + ui->verticalScroll->setMinimum(0); + ui->verticalScroll->setMaximum(m); + on_verticalScroll_valueChanged(ui->verticalScroll->value()); +} + + +void CharDialog::on_verticalScroll_valueChanged(int index) { + int ci = ui->tableChars->columnCount() * index; + for (int i = 0; i < ui->tableChars->rowCount(); ++i) { + for (int j = 0; j < ui->tableChars->columnCount(); ++j) { + ++ci; + if (cur->size() > ci) ui->tableChars->item(i, j)->setText(cur->at(ci)); + else ui->tableChars->item(i, j)->setText(QString()); + } + } +} + + +void CharDialog::on_spinSize_valueChanged(int index) { + size = index; + csize = size * 2; + ui->tableChars->horizontalHeader()->setDefaultSectionSize(csize); + ui->tableChars->verticalHeader()->setDefaultSectionSize(csize); + on_comboCategory_currentIndexChanged(ui->comboCategory->currentIndex()); + QFont font = ui->tableChars->font(); + font.setPointSize(size); + ui->tableChars->setFont(font); + resizeEvent(0); +} + + +void CharDialog::on_tableChars_cellPressed(int row, int column) { + sel_char = ui->tableChars->item(row, column)->text()[0]; +} + + +void CharDialog::on_buttonBox_accepted() { + emit charSelected(sel_char); + accept(); +} diff --git a/qad/widgets/chardialog.h b/qad/widgets/chardialog.h new file mode 100644 index 0000000..675b611 --- /dev/null +++ b/qad/widgets/chardialog.h @@ -0,0 +1,50 @@ +#ifndef CHARDIALOG_H +#define CHARDIALOG_H + +#include +#include +#include + +namespace Ui { + class CharDialog; +}; + +class CharDialog: public QDialog +{ + Q_OBJECT +public: + explicit CharDialog(QWidget * parent = 0); + ~CharDialog(); + + QChar selectedChar() {return sel_char;} + void setCharFont(const QFont & f); + +public slots: + +private: + void changeEvent(QEvent * e); + virtual bool eventFilter(QObject * o, QEvent * e); + virtual void resizeEvent(QResizeEvent * ); + void clear(); + + Ui::CharDialog * ui; + QVector > chars; + QVector * cur; + QChar sel_char; + int size, csize; + +private slots: + void on_comboCategory_currentIndexChanged(int index); + void on_verticalScroll_valueChanged(int index); + void on_spinSize_valueChanged(int index); + void on_tableChars_cellPressed(int row, int column); + void on_tableChars_cellDoubleClicked(int , int ) {on_buttonBox_accepted();} + void on_buttonBox_accepted(); + void on_buttonBox_rejected() {reject();} + +signals: + void charSelected(QChar ch); + +}; + +#endif // CHARDIALOG_H diff --git a/qad/widgets/chardialog.ui b/qad/widgets/chardialog.ui new file mode 100644 index 0000000..7548b62 --- /dev/null +++ b/qad/widgets/chardialog.ui @@ -0,0 +1,92 @@ + + + CharDialog + + + + 0 + 0 + 467 + 448 + + + + Choose symbol + + + + :/icons/icons/mbricks_128.png:/icons/icons/mbricks_128.png + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + false + + + 24 + + + false + + + 24 + + + + + + + 0 + + + Qt::Vertical + + + + + + + 1 + + + 200 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + diff --git a/qad/widgets/clineedit.cpp b/qad/widgets/clineedit.cpp new file mode 100644 index 0000000..861dd50 --- /dev/null +++ b/qad/widgets/clineedit.cpp @@ -0,0 +1,51 @@ +#include "clineedit.h" + + +CLineEdit::CLineEdit(QWidget * parent): QLineEdit(parent) { + cw = new QWidget(this); + cw->setStyleSheet("background-image: url(:/icons/edit-clear-locationbar-rtl.png);"); + cw->setCursor(Qt::ArrowCursor); + cw->setToolTip(tr("Clear")); + cw->hide(); + cw->installEventFilter(this); + int m0, m1, m2, m3; + getTextMargins(&m0, &m1, &m2, &m3); + setTextMargins(m0, m1, m2 + 21, m3); + connect(this, SIGNAL(textChanged(QString)), this, SLOT(textChanged_(QString))); + //connect(cw, SIGNAL(mouseReleaseEvent(QMouseEvent * )), this, SLOT(clearMouseRelease(QMouseEvent * ))); +} + + +bool CLineEdit::eventFilter(QObject * o, QEvent * e) { + if (e->type() == QEvent::MouseButtonRelease) { + clearMouseRelease((QMouseEvent * )e); + } + return QLineEdit::eventFilter(o, e); +} + + +void CLineEdit::resizeEvent(QResizeEvent * e) { + QLineEdit::resizeEvent(e); + cw->setGeometry(width() - 21, (height() - 17) / 2, 16, 16); +} + + +void CLineEdit::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + cw->setToolTip(tr("Clear")); + return; + } + QLineEdit::changeEvent(e); +} + + +void CLineEdit::setDefaultText(const QString & t, bool set_text) { + dt = t; + if (set_text) { + setText(t); + emit textEdited(t); + cw->hide(); + return; + } + textChanged_(text()); +} diff --git a/qad/widgets/clineedit.h b/qad/widgets/clineedit.h new file mode 100644 index 0000000..121942b --- /dev/null +++ b/qad/widgets/clineedit.h @@ -0,0 +1,43 @@ +#ifndef CLINEEDIT_H +#define CLINEEDIT_H + +#include +#include +#include +#include + + +class CLineEdit: public QLineEdit +{ + Q_OBJECT + Q_PROPERTY(QString defaultText READ defaultText WRITE setDefaultText) + +public: + explicit CLineEdit(QWidget * parent = 0); + ~CLineEdit() {delete cw;} + + inline QString defaultText() const {return dt;} + +protected: + QWidget * cw; + QString dt; + +private: + bool eventFilter(QObject * o, QEvent * e); + void resizeEvent(QResizeEvent * ); + void changeEvent(QEvent * e); + +private slots: + void clearMouseRelease(QMouseEvent * e) {if (cw->rect().contains(e->pos())) clearClick();} + void textChanged_(QString text) {cw->setVisible(text != dt);} + +public slots: + void clearClick() {if (!isEnabled()) return; setText(dt); emit cleared(); emit textEdited(dt);} + void setDefaultText(const QString & t, bool set_text = false); + +signals: + void cleared(); + +}; + +#endif // CLINEEDIT_H diff --git a/qad/widgets/colorbutton.cpp b/qad/widgets/colorbutton.cpp new file mode 100644 index 0000000..215a05f --- /dev/null +++ b/qad/widgets/colorbutton.cpp @@ -0,0 +1,112 @@ +#include "colorbutton.h" +#include +#include +#include + +ColorButton::ColorButton(QWidget * parent): QPushButton(parent) { + frame = false; + options = QColorDialog::ShowAlphaChannel; + back = new QWidget(this); + back->setAutoFillBackground(true); + back->show(); + pal = back->palette(); + pal.setBrush(back->backgroundRole(), QBrush(QImage(":/icons/alpha.png"))); + back->setPalette(pal); + label = new QFrame(this); + label->setAutoFillBackground(true); + label->setFrameStyle(QFrame::Panel | QFrame::Sunken); + label->show(); + pal = label->palette(); + menu.addAction(QIcon(":/icons/edit-copy.png"), tr("Copy"), this, SLOT(copy())); + menu.addAction(QIcon(":/icons/edit-paste.png"), tr("Paste"), this, SLOT(paste())); + menu.addSeparator(); + menu.addAction(tr("Mix with clipboard"), this, SLOT(mix())); + setAcceptDrops(true); + connect(this, SIGNAL(clicked(bool)), this, SLOT(clicked())); +} + + +ColorButton::~ColorButton() { + delete label; +} + + +void ColorButton::resizeEvent(QResizeEvent * ) { + if (frame) back->setGeometry(rect()); + else back->setGeometry(8, 5, width() - 16, height() - 12); + label->setGeometry(back->geometry()); +} + + +void ColorButton::mousePressEvent(QMouseEvent * e) { + pp = e->pos(); + if (e->buttons().testFlag(Qt::RightButton)) { + menu.popup(e->globalPos()); + return; + } + QPushButton::mousePressEvent(e); +} + + +void ColorButton::mouseMoveEvent(QMouseEvent * e) { + if (e->buttons().testFlag(Qt::LeftButton)) { + if ((e->pos() - pp).manhattanLength() > QApplication::startDragDistance()) { + setDown(false); + QDrag * drag = new QDrag(this); + QMimeData * data = new QMimeData(); + data->setColorData(color()); + drag->setMimeData(data); + drag->exec(Qt::CopyAction); + return; + } + } + QPushButton::mouseMoveEvent(e); +} + + +void ColorButton::dragEnterEvent(QDragEnterEvent * e) { + e->accept(); + QPushButton::dragEnterEvent(e); +} + + +void ColorButton::dropEvent(QDropEvent * e) { + const QMimeData * data = e->mimeData(); + QColor c = qvariant_cast(data->colorData()); + if (c.isValid()) { + setColor(c); + return; + } + c = QColor(data->text()); + if (c.isValid()) { + setColor(c); + return; + } + QPushButton::dropEvent(e); +} + + +void ColorButton::clicked() { + QColor ret = QColorDialog::getColor(color(), this, tr("Choose color"), options); + if (!ret.isValid()) return; + setColor(ret); +} + + +void ColorButton::mix() { + QColor c(QApplication::clipboard()->text()); + if (!c.isValid()) return; + QColor sc = color(); + setColor(QColor((c.red() + sc.red()) / 2, (c.green() + sc.green()) / 2, (c.blue() + sc.blue()) / 2, (c.alpha() + sc.alpha()) / 2)); +} + + +void ColorButton::setColor(const QColor & col) { + if (pal.color(label->backgroundRole()) == col) return; + if (options.testFlag(QColorDialog::ShowAlphaChannel)) + pal.setColor(label->backgroundRole(), col); + else + pal.setColor(label->backgroundRole(), QColor(col.red(), col.green(), col.blue())); + label->setPalette(pal); + emit colorChanged(color()); +} diff --git a/qad/widgets/colorbutton.h b/qad/widgets/colorbutton.h new file mode 100644 index 0000000..37eb4e9 --- /dev/null +++ b/qad/widgets/colorbutton.h @@ -0,0 +1,63 @@ +#ifndef COLORBUTTON_H +#define COLORBUTTON_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +class ColorButton: public QPushButton +{ + Q_OBJECT + Q_PROPERTY(QColor color READ color WRITE setColor) + Q_PROPERTY(bool useNativeDialog READ useNativeDialog WRITE setUseNativeDialog) + Q_PROPERTY(bool useAlphaChannel READ useAlphaChannel WRITE setUseAlphaChannel) + Q_PROPERTY(bool frameOnly READ frameOnly WRITE setFrameOnly) + +public: + explicit ColorButton(QWidget * parent = 0); + ~ColorButton(); + + QColor color() const {return pal.color(label->backgroundRole());} + bool useNativeDialog() const {return !options.testFlag(QColorDialog::DontUseNativeDialog);} + bool useAlphaChannel() const {return options.testFlag(QColorDialog::ShowAlphaChannel);} + bool frameOnly() const {return frame;} + +public slots: + void setColor(const QColor & col); + void setUseNativeDialog(bool yes) {if (yes) options &= ~QColorDialog::DontUseNativeDialog; else options |= QColorDialog::DontUseNativeDialog;} + void setUseAlphaChannel(bool yes) {if (yes) options |= QColorDialog::ShowAlphaChannel; else options &= ~QColorDialog::ShowAlphaChannel;} + void setFrameOnly(bool yes) {frame = yes; setFlat(frame); resizeEvent(0);} + +private: + void mousePressEvent(QMouseEvent * e); + void mouseMoveEvent(QMouseEvent * e); + void resizeEvent(QResizeEvent * ); + void dragEnterEvent(QDragEnterEvent * e); + void dropEvent(QDropEvent * e); + + QFrame * label; + QWidget * back; + QPalette pal; + QPoint pp; + QMenu menu; + QColorDialog::ColorDialogOptions options; + bool frame; + +private slots: + void clicked(); + void copy() {QApplication::clipboard()->setText(color().name());} + void paste() {QColor c(QApplication::clipboard()->text()); if (c.isValid()) setColor(c);} + void mix(); + +signals: + void colorChanged(QColor); + +}; + +#endif // COLORBUTTON_H diff --git a/qad/widgets/ecombobox.cpp b/qad/widgets/ecombobox.cpp new file mode 100644 index 0000000..00935c7 --- /dev/null +++ b/qad/widgets/ecombobox.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include "ecombobox.h" + + +class EModel: public QStandardItemModel { +public: + EModel(QObject * parent = 0): QStandardItemModel(parent) { +#if QT_VERSION < 0x050000 + setSupportedDragActions(Qt::MoveAction); +#endif + } +protected: + virtual Qt::ItemFlags flags(const QModelIndex & index) const { + Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; + if (!index.isValid()) f |= Qt::ItemIsDropEnabled; + return f; + } +#if QT_VERSION >= 0x050000 + Qt::DropActions supportedDragActions() const {return Qt::MoveAction;} +#endif +}; + + +EComboBox::EComboBox(QWidget * parent): QComboBox(parent) { + setView(&iv); + setModel(new EModel()); + iv.setTextElideMode(Qt::ElideMiddle); + iv.setRootIsDecorated(false); + iv.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + iv.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + iv.setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + iv.setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + iv.setDragDropMode(QAbstractItemView::InternalMove); + iv.setMinimumHeight(100); + icon.setPixmap(QPixmap(":/icons/edit-find.png")); + ifont = nfont = font(); + ifont.setItalic(true); +#if QT_VERSION >= 0x040700 + filter.setPlaceholderText(tr("Filter")); + filter.setFont(ifont); +#endif + header.setAutoFillBackground(true); + header.setLayout(new QBoxLayout(QBoxLayout::LeftToRight)); + header.layout()->setSpacing(2); + header.layout()->setContentsMargins(2, 0, 0, 0); + header.layout()->addWidget(&icon); + header.layout()->addWidget(&filter); + header.setParent(iv.header()); + connect(&filter, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); +} + + +QSize EComboBox::sizeHint() const { + QSize s = QComboBox::sizeHint(); + s.setWidth(s.width() + 16); + return s; +} + + +void EComboBox::showPopup() { + filterChanged(filter.text(), true); + QComboBox::showPopup(); + QRect r = iv.header()->rect(); + header.setGeometry(r.x(), r.y(), r.width(), r.height() - 1); + filter.setFocus(); +} + + +void EComboBox::filterChanged(const QString & text, bool first) { + if (filter.text().isEmpty()) filter.setFont(ifont); + else filter.setFont(nfont); + iv.hide(); + QModelIndex pi = iv.rootIndex(); + if (text.isEmpty()) { + for (int i = 0; i < iv.model()->rowCount(); ++i) { + iv.setRowHidden(i, pi, false); + iv.model()->setData(iv.model()->index(i, 0), iv.model()->index(i, 0, pi).data().toString(), Qt::ToolTipRole); + } + iv.show(); + if (first) return; + hidePopup(); + showPopup(); + qApp->processEvents(); + QRect r = iv.header()->rect(); + header.setGeometry(r.x(), r.y(), r.width(), r.height() - 1); + return; + } + for (int i = 0; i < iv.model()->rowCount(); ++i) { + iv.setRowHidden(i, pi, !iv.model()->index(i, 0, pi).data().toString().contains(QRegExp(text, Qt::CaseInsensitive))); + iv.model()->setData(iv.model()->index(i, 0), iv.model()->index(i, 0, pi).data().toString(), Qt::ToolTipRole); + } + iv.show(); + qApp->processEvents(); + QRect r = iv.header()->rect(); + header.setGeometry(r.x(), r.y(), r.width(), r.height() - 1); +} diff --git a/qad/widgets/ecombobox.h b/qad/widgets/ecombobox.h new file mode 100644 index 0000000..4ad832a --- /dev/null +++ b/qad/widgets/ecombobox.h @@ -0,0 +1,36 @@ +#ifndef ECOMBOBOX_H +#define ECOMBOBOX_H + +#include +#include +#include +#include +#include "clineedit.h" + + +class EComboBox: public QComboBox +{ + Q_OBJECT +public: + explicit EComboBox(QWidget * parent = 0); + + QSize sizeHint() const; + +public slots: + virtual void showPopup(); + +private: + QTreeView iv; + QWidget header; + QLabel icon; + CLineEdit filter; + QFont nfont, ifont; + +private slots: + void filterChanged(const QString & text, bool first = false); + +signals: + +}; + +#endif // ECOMBOBOX_H diff --git a/qad/widgets/iconedlabel.h b/qad/widgets/iconedlabel.h new file mode 100644 index 0000000..0df69b1 --- /dev/null +++ b/qad/widgets/iconedlabel.h @@ -0,0 +1,68 @@ + #ifndef ICONEDLABEL_H +#define ICONEDLABEL_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class IconedLabel: public QFrame +{ + Q_OBJECT + Q_ENUMS(Direction) + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QIcon icon READ icon WRITE setIcon) + Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize) + Q_PROPERTY(Direction direction READ direction WRITE setDirection) +public: + enum Direction {LeftToRight = 0, RightToLeft = 1, TopToBottom = 2, BottomToTop = 3}; + + explicit IconedLabel(QWidget * parent = 0): QFrame(parent) { + label_.setAlignment(Qt::AlignCenter); + icon_.setAlignment(Qt::AlignCenter); + size_ = QSize(16, 16); + setDirection(LeftToRight); + } + + QString text() const {return label_.text();} + QIcon icon() const {return icon_.pixmap() == 0 ? QIcon() : QIcon(*icon_.pixmap());} + QSize iconSize() const {return size_;} + Direction direction() const {return dir_;} + +protected: + QLabel label_; + QLabel icon_; + QIcon sicon_; + QSize size_; + Direction dir_; + +public slots: + void setText(const QString & t) {label_.setText(t);} + void setIcon(const QIcon & i) {sicon_ = i; icon_.setPixmap(i.pixmap(size_));} + void setIconSize(const QSize & s) {size_ = s; icon_.setPixmap(sicon_.pixmap(size_));} + void setDirection(Direction d) { + dir_ = d; + if (layout() != 0) + delete layout(); + QLayout * lay = new QBoxLayout((QBoxLayout::Direction)dir_); + lay->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding)); + lay->addWidget(&label_); + lay->addWidget(&icon_); + lay->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding)); + lay->setContentsMargins(0, 0, 0, 0); + setLayout(lay); + update(); + } + +signals: + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ICONEDLABEL_H diff --git a/qad/widgets/lang/qad_widgets_ru.qm b/qad/widgets/lang/qad_widgets_ru.qm new file mode 100644 index 0000000..e5a2155 Binary files /dev/null and b/qad/widgets/lang/qad_widgets_ru.qm differ diff --git a/qad/widgets/lang/qad_widgets_ru.ts b/qad/widgets/lang/qad_widgets_ru.ts new file mode 100644 index 0000000..29f8aa0 --- /dev/null +++ b/qad/widgets/lang/qad_widgets_ru.ts @@ -0,0 +1,853 @@ + + + + + CLineEdit + + + + Clear + Сбросить + + + + CharDialog + + + Choose symbol + + + + + + No Category + + + + + + Mark NonSpacing + + + + + + Mark SpacingCombining + + + + + + Mark Enclosing + + + + + + Number DecimalDigit + + + + + + Number Letter + + + + + + Number Other + + + + + + Separator Space + + + + + + Separator Line + + + + + + Separator Paragraph + + + + + + Other Control + + + + + + Other Format + + + + + + Other Surrogate + + + + + + Other PrivateUse + + + + + + Other NotAssigned + + + + + + Letter Uppercase + + + + + + Letter Lowercase + + + + + + Letter Titlecase + + + + + + Letter Modifier + + + + + + Letter Other + + + + + + Punctuation Connector + + + + + + Punctuation Dash + + + + + + Punctuation Open + + + + + + Punctuation Close + + + + + + Punctuation InitialQuote + + + + + + Punctuation FinalQuote + + + + + + Punctuation Other + + + + + + Symbol Math + + + + + + Symbol Currency + + + + + + Symbol Modifier + + + + + + Symbol Other + + + + + ColorButton + + + Copy + Копировать + + + + Paste + Вставить + + + + Mix with clipboard + Смешать с буфером обмена + + + + Choose color + Выберите цвет + + + + EComboBox + + + Filter + Фильтр + + + + Graphic + + + Autofit + Вписать + + + + Grid + Сетка + + + + Cursor axis + Координаты курсора + + + + Only expand Y + Только расширять по Y + + + + Only expand X + Только расширять по X + + + + Border inputs + Граничные поля ввода + + + + Legend + Легенда + + + + Configure ... + Настроить ... + + + + Save image ... + Сохранить изображение ... + + + + Clear + Очистить + + + + Close + Закрыть + + + + Cursor: ( ; ) + Курсор: ( ; ) + + + + + Cursor: + Курсор: + + + + Selection + Выбрано + + + + Size + Размер + + + + + Range + Диапазон + + + + + Length + Длина + + + + + Cursor + Курсор + + + + Save Image + Соханение изображения + + + + y(x) + + + + + Check all + + + + + GraphicConf + + + Graphic parameters + Параметры графика + + + + Appearance + Внешний вид + + + + Border inputs + Граничные поля ввода + + + + Antialiasing + Антиалиасинг + + + + Status bar + Строка состояния + + + + OpenGL + + + + + Legend + Легенда + + + + Background color: + Цвет фона: + + + + Text color: + Цвет текста: + + + + Grid + Сетка + + + + Margins + Отступы + + + + + + + + px + пикс + + + + All: + Все: + + + + Right: + Правый: + + + + Left: + Левый: + + + + Bottom: + Нижний: + + + + Top: + Верхний: + + + + + Color: + Цвет: + + + + + Style: + Стиль: + + + + Width: + Толщина: + + + + Step X: + Шаг X: + + + + Step Y: + Шаг Y: + + + + Auto step + Автоматическая + + + + Graphics + Графики + + + + Lines width: + Толщина линий: + + + + Points width: + Толщина точек: + + + + Fill: + Заливка: + + + + NoPen + Без линий + + + + Solid + Сплошная + + + + Dash + Штриховая + + + + Dot + Пунктирная + + + + Dash-Dot + Штрих-пунктирная + + + + Dash-Dot-Dot + Штрих-пунктир-пунктирная + + + + QPIConfigNewDialog + + + Dialog + + + + + Type + + + + + string + + + + + s + + + + + integer + + + + + n + + + + + float + + + + + f + + + + + string list + + + + + l + + + + + boolean + + + + + b + + + + + color + + + + + c + + + + + rectangle + + + + + r + + + + + area + + + + + a + + + + + point + + + + + p + + + + + vector + + + + + v + + + + + ip + + + + + i + + + + + Name: + + + + + Comment: + + + + + Value: + + + + + QPIConfigWidget + + + Name + + + + + Value + + + + + Type + + + + + Comment + + + + + string + + + + + string list + + + + + integer + + + + + float + + + + + boolean + + + + + color + + + + + rectangle + + + + + area + + + + + point + + + + + vector + + + + + ip + + + + + Add item ... + + + + + Add node ... + + + + + Convert to item + + + + + Convert to node + + + + + Remove + + + + + Expand all + + + + + Collapse all + + + + + QPointEdit + + + + X + + + + + + Y + + + + + QRectEdit + + + + X + + + + + + Y + + + + + + Height + + + + + + Width + + + + + Shortcuts + + + + Command + + + + + + Shortcut + + + + + StringListEdit + + + + Add + + + + + + Remove + + + + + + Clear + + + + diff --git a/qad/widgets/lang/ru.qm b/qad/widgets/lang/ru.qm new file mode 100644 index 0000000..e5a2155 Binary files /dev/null and b/qad/widgets/lang/ru.qm differ diff --git a/qad/widgets/lang/ru.ts b/qad/widgets/lang/ru.ts new file mode 100644 index 0000000..29f8aa0 --- /dev/null +++ b/qad/widgets/lang/ru.ts @@ -0,0 +1,853 @@ + + + + + CLineEdit + + + + Clear + Сбросить + + + + CharDialog + + + Choose symbol + + + + + + No Category + + + + + + Mark NonSpacing + + + + + + Mark SpacingCombining + + + + + + Mark Enclosing + + + + + + Number DecimalDigit + + + + + + Number Letter + + + + + + Number Other + + + + + + Separator Space + + + + + + Separator Line + + + + + + Separator Paragraph + + + + + + Other Control + + + + + + Other Format + + + + + + Other Surrogate + + + + + + Other PrivateUse + + + + + + Other NotAssigned + + + + + + Letter Uppercase + + + + + + Letter Lowercase + + + + + + Letter Titlecase + + + + + + Letter Modifier + + + + + + Letter Other + + + + + + Punctuation Connector + + + + + + Punctuation Dash + + + + + + Punctuation Open + + + + + + Punctuation Close + + + + + + Punctuation InitialQuote + + + + + + Punctuation FinalQuote + + + + + + Punctuation Other + + + + + + Symbol Math + + + + + + Symbol Currency + + + + + + Symbol Modifier + + + + + + Symbol Other + + + + + ColorButton + + + Copy + Копировать + + + + Paste + Вставить + + + + Mix with clipboard + Смешать с буфером обмена + + + + Choose color + Выберите цвет + + + + EComboBox + + + Filter + Фильтр + + + + Graphic + + + Autofit + Вписать + + + + Grid + Сетка + + + + Cursor axis + Координаты курсора + + + + Only expand Y + Только расширять по Y + + + + Only expand X + Только расширять по X + + + + Border inputs + Граничные поля ввода + + + + Legend + Легенда + + + + Configure ... + Настроить ... + + + + Save image ... + Сохранить изображение ... + + + + Clear + Очистить + + + + Close + Закрыть + + + + Cursor: ( ; ) + Курсор: ( ; ) + + + + + Cursor: + Курсор: + + + + Selection + Выбрано + + + + Size + Размер + + + + + Range + Диапазон + + + + + Length + Длина + + + + + Cursor + Курсор + + + + Save Image + Соханение изображения + + + + y(x) + + + + + Check all + + + + + GraphicConf + + + Graphic parameters + Параметры графика + + + + Appearance + Внешний вид + + + + Border inputs + Граничные поля ввода + + + + Antialiasing + Антиалиасинг + + + + Status bar + Строка состояния + + + + OpenGL + + + + + Legend + Легенда + + + + Background color: + Цвет фона: + + + + Text color: + Цвет текста: + + + + Grid + Сетка + + + + Margins + Отступы + + + + + + + + px + пикс + + + + All: + Все: + + + + Right: + Правый: + + + + Left: + Левый: + + + + Bottom: + Нижний: + + + + Top: + Верхний: + + + + + Color: + Цвет: + + + + + Style: + Стиль: + + + + Width: + Толщина: + + + + Step X: + Шаг X: + + + + Step Y: + Шаг Y: + + + + Auto step + Автоматическая + + + + Graphics + Графики + + + + Lines width: + Толщина линий: + + + + Points width: + Толщина точек: + + + + Fill: + Заливка: + + + + NoPen + Без линий + + + + Solid + Сплошная + + + + Dash + Штриховая + + + + Dot + Пунктирная + + + + Dash-Dot + Штрих-пунктирная + + + + Dash-Dot-Dot + Штрих-пунктир-пунктирная + + + + QPIConfigNewDialog + + + Dialog + + + + + Type + + + + + string + + + + + s + + + + + integer + + + + + n + + + + + float + + + + + f + + + + + string list + + + + + l + + + + + boolean + + + + + b + + + + + color + + + + + c + + + + + rectangle + + + + + r + + + + + area + + + + + a + + + + + point + + + + + p + + + + + vector + + + + + v + + + + + ip + + + + + i + + + + + Name: + + + + + Comment: + + + + + Value: + + + + + QPIConfigWidget + + + Name + + + + + Value + + + + + Type + + + + + Comment + + + + + string + + + + + string list + + + + + integer + + + + + float + + + + + boolean + + + + + color + + + + + rectangle + + + + + area + + + + + point + + + + + vector + + + + + ip + + + + + Add item ... + + + + + Add node ... + + + + + Convert to item + + + + + Convert to node + + + + + Remove + + + + + Expand all + + + + + Collapse all + + + + + QPointEdit + + + + X + + + + + + Y + + + + + QRectEdit + + + + X + + + + + + Y + + + + + + Height + + + + + + Width + + + + + Shortcuts + + + + Command + + + + + + Shortcut + + + + + StringListEdit + + + + Add + + + + + + Remove + + + + + + Clear + + + + diff --git a/qad/widgets/plugin/CMakeLists.txt b/qad/widgets/plugin/CMakeLists.txt new file mode 100644 index 0000000..b4d9aec --- /dev/null +++ b/qad/widgets/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(widgets "") diff --git a/qad/widgets/plugin/chardialogplugin.cpp b/qad/widgets/plugin/chardialogplugin.cpp new file mode 100644 index 0000000..4ad02db --- /dev/null +++ b/qad/widgets/plugin/chardialogplugin.cpp @@ -0,0 +1,69 @@ +#include "chardialog.h" +#include "chardialogplugin.h" +#include + + +CharDialogPlugin::CharDialogPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void CharDialogPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool CharDialogPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * CharDialogPlugin::createWidget(QWidget * parent) { + return new CharDialog(parent); +} + + +QString CharDialogPlugin::name() const { + return QLatin1String("CharDialog"); +} + + +QString CharDialogPlugin::group() const { + return QLatin1String("Dialogs"); +} + + +QIcon CharDialogPlugin::icon() const { + return QIcon(":/icons/chardialog.png"); +} + + +QString CharDialogPlugin::toolTip() const { + return QLatin1String("Character Select Dialog"); +} + + +QString CharDialogPlugin::whatsThis() const { + return QLatin1String("Character Select Dialog"); +} + + +bool CharDialogPlugin::isContainer() const { + return false; +} + + +QString CharDialogPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString CharDialogPlugin::includeFile() const { + return QLatin1String("chardialog.h"); +} + diff --git a/qad/widgets/plugin/chardialogplugin.h b/qad/widgets/plugin/chardialogplugin.h new file mode 100644 index 0000000..8f447ea --- /dev/null +++ b/qad/widgets/plugin/chardialogplugin.h @@ -0,0 +1,31 @@ +#ifndef CHARDIALOGPLUGIN_H +#define CHARDIALOGPLUGIN_H + +#include + +class CharDialogPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + CharDialogPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // CHARDIALOGPLUGIN_H diff --git a/qad/widgets/plugin/clineeditplugin.cpp b/qad/widgets/plugin/clineeditplugin.cpp new file mode 100644 index 0000000..7315985 --- /dev/null +++ b/qad/widgets/plugin/clineeditplugin.cpp @@ -0,0 +1,69 @@ +#include "clineedit.h" +#include "clineeditplugin.h" +#include + + +CLineEditPlugin::CLineEditPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void CLineEditPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool CLineEditPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * CLineEditPlugin::createWidget(QWidget * parent) { + return new CLineEdit(parent); +} + + +QString CLineEditPlugin::name() const { + return QLatin1String("CLineEdit"); +} + + +QString CLineEditPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon CLineEditPlugin::icon() const { + return QIcon(":/icons/clineedit.png"); +} + + +QString CLineEditPlugin::toolTip() const { + return QLatin1String("Clearable Line Edit"); +} + + +QString CLineEditPlugin::whatsThis() const { + return QLatin1String("Clearable Line Edit"); +} + + +bool CLineEditPlugin::isContainer() const { + return false; +} + + +QString CLineEditPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString CLineEditPlugin::includeFile() const { + return QLatin1String("clineedit.h"); +} + diff --git a/qad/widgets/plugin/clineeditplugin.h b/qad/widgets/plugin/clineeditplugin.h new file mode 100644 index 0000000..2c1ff17 --- /dev/null +++ b/qad/widgets/plugin/clineeditplugin.h @@ -0,0 +1,31 @@ +#ifndef CLINEEDITPLUGIN_H +#define CLINEEDITPLUGIN_H + +#include + +class CLineEditPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + CLineEditPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // CLINEEDITPLUGIN_H diff --git a/qad/widgets/plugin/colorbuttonplugin.cpp b/qad/widgets/plugin/colorbuttonplugin.cpp new file mode 100644 index 0000000..84e8574 --- /dev/null +++ b/qad/widgets/plugin/colorbuttonplugin.cpp @@ -0,0 +1,69 @@ +#include "colorbutton.h" +#include "colorbuttonplugin.h" +#include + + +ColorButtonPlugin::ColorButtonPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void ColorButtonPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool ColorButtonPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * ColorButtonPlugin::createWidget(QWidget * parent) { + return new ColorButton(parent); +} + + +QString ColorButtonPlugin::name() const { + return QLatin1String("ColorButton"); +} + + +QString ColorButtonPlugin::group() const { + return QLatin1String("Buttons"); +} + + +QIcon ColorButtonPlugin::icon() const { + return QIcon(":/icons/colorbutton.png"); +} + + +QString ColorButtonPlugin::toolTip() const { + return QLatin1String("Color Button"); +} + + +QString ColorButtonPlugin::whatsThis() const { + return QLatin1String("Color Button"); +} + + +bool ColorButtonPlugin::isContainer() const { + return false; +} + + +QString ColorButtonPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString ColorButtonPlugin::includeFile() const { + return QLatin1String("colorbutton.h"); +} + diff --git a/qad/widgets/plugin/colorbuttonplugin.h b/qad/widgets/plugin/colorbuttonplugin.h new file mode 100644 index 0000000..a19619d --- /dev/null +++ b/qad/widgets/plugin/colorbuttonplugin.h @@ -0,0 +1,31 @@ +#ifndef COLORBUTTONPLUGIN_H +#define COLORBUTTONPLUGIN_H + +#include + +class ColorButtonPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + ColorButtonPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // COLORBUTTONPLUGIN_H diff --git a/qad/widgets/plugin/ecomboboxplugin.cpp b/qad/widgets/plugin/ecomboboxplugin.cpp new file mode 100644 index 0000000..c0079d4 --- /dev/null +++ b/qad/widgets/plugin/ecomboboxplugin.cpp @@ -0,0 +1,69 @@ +#include "ecombobox.h" +#include "ecomboboxplugin.h" +#include + + +EComboBoxPlugin::EComboBoxPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void EComboBoxPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool EComboBoxPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * EComboBoxPlugin::createWidget(QWidget * parent) { + return new EComboBox(parent); +} + + +QString EComboBoxPlugin::name() const { + return QLatin1String("EComboBox"); +} + + +QString EComboBoxPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon EComboBoxPlugin::icon() const { + return QIcon(":/icons/ecombobox.png"); +} + + +QString EComboBoxPlugin::toolTip() const { + return QLatin1String("Combo Box with Search"); +} + + +QString EComboBoxPlugin::whatsThis() const { + return QLatin1String("Combo Box with Search"); +} + + +bool EComboBoxPlugin::isContainer() const { + return false; +} + + +QString EComboBoxPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString EComboBoxPlugin::includeFile() const { + return QLatin1String("ecombobox.h"); +} + diff --git a/qad/widgets/plugin/ecomboboxplugin.h b/qad/widgets/plugin/ecomboboxplugin.h new file mode 100644 index 0000000..9038c97 --- /dev/null +++ b/qad/widgets/plugin/ecomboboxplugin.h @@ -0,0 +1,31 @@ +#ifndef ECOMBOBOXPLUGIN_H +#define ECOMBOBOXPLUGIN_H + +#include + +class EComboBoxPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + EComboBoxPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // ECOMBOBOXPLUGIN_H diff --git a/qad/widgets/plugin/iconedlabelplugin.h b/qad/widgets/plugin/iconedlabelplugin.h new file mode 100644 index 0000000..d2be41e --- /dev/null +++ b/qad/widgets/plugin/iconedlabelplugin.h @@ -0,0 +1,31 @@ +#ifndef ICONEDLABEPLUGIN_H +#define ICONEDLABEPLUGIN_H + +#include + +class IconedLabelPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + IconedLabelPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // ICONEDLABEPLUGIN_H diff --git a/qad/widgets/plugin/lconedlabelplugin.cpp b/qad/widgets/plugin/lconedlabelplugin.cpp new file mode 100644 index 0000000..a24f3e2 --- /dev/null +++ b/qad/widgets/plugin/lconedlabelplugin.cpp @@ -0,0 +1,69 @@ +#include "iconedlabel.h" +#include "iconedlabelplugin.h" +#include + + +IconedLabelPlugin::IconedLabelPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void IconedLabelPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool IconedLabelPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * IconedLabelPlugin::createWidget(QWidget * parent) { + return new IconedLabel(parent); +} + + +QString IconedLabelPlugin::name() const { + return QLatin1String("IconedLabel"); +} + + +QString IconedLabelPlugin::group() const { + return QLatin1String("Display Widgets"); +} + + +QIcon IconedLabelPlugin::icon() const { + return QIcon(); +} + + +QString IconedLabelPlugin::toolTip() const { + return QLatin1String("Label with Icon"); +} + + +QString IconedLabelPlugin::whatsThis() const { + return QLatin1String("Label with Icon"); +} + + +bool IconedLabelPlugin::isContainer() const { + return false; +} + + +QString IconedLabelPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString IconedLabelPlugin::includeFile() const { + return QLatin1String("iconedlabel.h"); +} + diff --git a/qad/widgets/plugin/qad_widgets.cpp b/qad/widgets/plugin/qad_widgets.cpp new file mode 100644 index 0000000..57fe666 --- /dev/null +++ b/qad/widgets/plugin/qad_widgets.cpp @@ -0,0 +1,40 @@ +#include "spinsliderplugin.h" +#include "colorbuttonplugin.h" +#include "chardialogplugin.h" +#include "shortcutsplugin.h" +#include "clineeditplugin.h" +#include "qipeditplugin.h" +#include "qpointeditplugin.h" +#include "qrecteditplugin.h" +#include "ecomboboxplugin.h" +#include "qpiconsoleplugin.h" +#include "iconedlabelplugin.h" +#include "qcodeeditplugin.h" +#include "qvarianteditplugin.h" +#include "qpiconfigplugin.h" +#include "qad_widgets.h" + +QADWidgets::QADWidgets(QObject * parent): QObject(parent) +{ + m_widgets.append(new SpinSliderPlugin(this)); + m_widgets.append(new ColorButtonPlugin(this)); + m_widgets.append(new CharDialogPlugin(this)); + m_widgets.append(new ShortcutsPlugin(this)); + m_widgets.append(new CLineEditPlugin(this)); + m_widgets.append(new QIPEditPlugin(this)); + m_widgets.append(new QPointEditPlugin(this)); + m_widgets.append(new QRectEditPlugin(this)); + m_widgets.append(new EComboBoxPlugin(this)); + m_widgets.append(new QPIConsolePlugin(this)); + m_widgets.append(new IconedLabelPlugin(this)); + m_widgets.append(new QCodeEditPlugin(this)); + m_widgets.append(new QVariantEditPlugin(this)); + m_widgets.append(new QPIConfigPlugin(this)); +} + + +QList QADWidgets::customWidgets() const { + return m_widgets; +} + +Q_EXPORT_PLUGIN2(qad_widgets_plugin, QADWidgets) diff --git a/qad/widgets/plugin/qad_widgets.h b/qad/widgets/plugin/qad_widgets.h new file mode 100644 index 0000000..bac6dca --- /dev/null +++ b/qad/widgets/plugin/qad_widgets.h @@ -0,0 +1,21 @@ +#ifndef QAD_WIDGETS_H +#define QAD_WIDGETS_H + +#include +#include + +class QADWidgets: public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit QADWidgets(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; + +}; + +#endif // QAD_WIDGETS_H diff --git a/qad/widgets/plugin/qcodeeditplugin.cpp b/qad/widgets/plugin/qcodeeditplugin.cpp new file mode 100644 index 0000000..1bd7aaa --- /dev/null +++ b/qad/widgets/plugin/qcodeeditplugin.cpp @@ -0,0 +1,69 @@ +#include "qcodeedit.h" +#include "qcodeeditplugin.h" +#include + + +QCodeEditPlugin::QCodeEditPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QCodeEditPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QCodeEditPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QCodeEditPlugin::createWidget(QWidget * parent) { + return new QCodeEdit(parent); +} + + +QString QCodeEditPlugin::name() const { + return QLatin1String("QCodeEdit"); +} + + +QString QCodeEditPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon QCodeEditPlugin::icon() const { + return QIcon(":/icons/qcodeedit.png"); +} + + +QString QCodeEditPlugin::toolTip() const { + return QLatin1String("QCodeEdit"); +} + + +QString QCodeEditPlugin::whatsThis() const { + return QLatin1String("QCodeEdit"); +} + + +bool QCodeEditPlugin::isContainer() const { + return false; +} + + +QString QCodeEditPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QCodeEditPlugin::includeFile() const { + return QLatin1String("qcodeedit.h"); +} + diff --git a/qad/widgets/plugin/qcodeeditplugin.h b/qad/widgets/plugin/qcodeeditplugin.h new file mode 100644 index 0000000..f14d448 --- /dev/null +++ b/qad/widgets/plugin/qcodeeditplugin.h @@ -0,0 +1,31 @@ +#ifndef QCODEEDITPLUGIN_H +#define QCODEEDITPLUGIN_H + +#include + +class QCodeEditPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QCodeEditPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QCODEEDITPLUGIN_H diff --git a/qad/widgets/plugin/qipeditplugin.cpp b/qad/widgets/plugin/qipeditplugin.cpp new file mode 100644 index 0000000..7cc94dd --- /dev/null +++ b/qad/widgets/plugin/qipeditplugin.cpp @@ -0,0 +1,69 @@ +#include "qipedit.h" +#include "qipeditplugin.h" +#include + + +QIPEditPlugin::QIPEditPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QIPEditPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QIPEditPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QIPEditPlugin::createWidget(QWidget * parent) { + return new QIPEdit(parent); +} + + +QString QIPEditPlugin::name() const { + return QLatin1String("QIPEdit"); +} + + +QString QIPEditPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon QIPEditPlugin::icon() const { + return QIcon(); +} + + +QString QIPEditPlugin::toolTip() const { + return QLatin1String("IP Edit"); +} + + +QString QIPEditPlugin::whatsThis() const { + return QLatin1String("IP Edit"); +} + + +bool QIPEditPlugin::isContainer() const { + return false; +} + + +QString QIPEditPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QIPEditPlugin::includeFile() const { + return QLatin1String("qipedit.h"); +} + diff --git a/qad/widgets/plugin/qipeditplugin.h b/qad/widgets/plugin/qipeditplugin.h new file mode 100644 index 0000000..afe910f --- /dev/null +++ b/qad/widgets/plugin/qipeditplugin.h @@ -0,0 +1,31 @@ +#ifndef QIPEDITPLUGIN_H +#define QIPEDITPLUGIN_H + +#include + +class QIPEditPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QIPEditPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QIPEDITPLUGIN_H diff --git a/qad/widgets/plugin/qpiconfigplugin.cpp b/qad/widgets/plugin/qpiconfigplugin.cpp new file mode 100644 index 0000000..8fee953 --- /dev/null +++ b/qad/widgets/plugin/qpiconfigplugin.cpp @@ -0,0 +1,69 @@ +#include "qpiconfigwidget.h" +#include "qpiconfigplugin.h" +#include + + +QPIConfigPlugin::QPIConfigPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QPIConfigPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QPIConfigPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QPIConfigPlugin::createWidget(QWidget * parent) { + return new QPIConfigWidget(parent, 0, false); +} + + +QString QPIConfigPlugin::name() const { + return QLatin1String("QPIConfigWidget"); +} + + +QString QPIConfigPlugin::group() const { + return QLatin1String("Editor Widgets"); +} + + +QIcon QPIConfigPlugin::icon() const { + return QIcon(); +} + + +QString QPIConfigPlugin::toolTip() const { + return QLatin1String(""); +} + + +QString QPIConfigPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool QPIConfigPlugin::isContainer() const { + return false; +} + + +QString QPIConfigPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QPIConfigPlugin::includeFile() const { + return QLatin1String("qpiconfigwidget.h"); +} + diff --git a/qad/widgets/plugin/qpiconfigplugin.h b/qad/widgets/plugin/qpiconfigplugin.h new file mode 100644 index 0000000..7844196 --- /dev/null +++ b/qad/widgets/plugin/qpiconfigplugin.h @@ -0,0 +1,31 @@ +#ifndef QPICONFIGPLUGIN_H +#define QPICONFIGPLUGIN_H + +#include + +class QPIConfigPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QPIConfigPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QPICONFIGPLUGIN_H diff --git a/qad/widgets/plugin/qpiconsoleplugin.cpp b/qad/widgets/plugin/qpiconsoleplugin.cpp new file mode 100644 index 0000000..ad1f615 --- /dev/null +++ b/qad/widgets/plugin/qpiconsoleplugin.cpp @@ -0,0 +1,69 @@ +#include "qpiconsole.h" +#include "qpiconsoleplugin.h" +#include + + +QPIConsolePlugin::QPIConsolePlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QPIConsolePlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QPIConsolePlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QPIConsolePlugin::createWidget(QWidget * parent) { + return new QPIConsole(parent); +} + + +QString QPIConsolePlugin::name() const { + return QLatin1String("QPIConsole"); +} + + +QString QPIConsolePlugin::group() const { + return QLatin1String("Display Widgets"); +} + + +QIcon QPIConsolePlugin::icon() const { + return QIcon(":/icons/qpiconsole.png"); +} + + +QString QPIConsolePlugin::toolTip() const { + return QLatin1String("QPIConsole"); +} + + +QString QPIConsolePlugin::whatsThis() const { + return QLatin1String("QPIConsole"); +} + + +bool QPIConsolePlugin::isContainer() const { + return false; +} + + +QString QPIConsolePlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QPIConsolePlugin::includeFile() const { + return QLatin1String("qpiconsole.h"); +} + diff --git a/qad/widgets/plugin/qpiconsoleplugin.h b/qad/widgets/plugin/qpiconsoleplugin.h new file mode 100644 index 0000000..2f2b38f --- /dev/null +++ b/qad/widgets/plugin/qpiconsoleplugin.h @@ -0,0 +1,31 @@ +#ifndef QPICONSOLEPLUGIN_H +#define QPICONSOLEPLUGIN_H + +#include + +class QPIConsolePlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QPIConsolePlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QPICONSOLEPLUGIN_H diff --git a/qad/widgets/plugin/qpointeditplugin.cpp b/qad/widgets/plugin/qpointeditplugin.cpp new file mode 100644 index 0000000..622c78e --- /dev/null +++ b/qad/widgets/plugin/qpointeditplugin.cpp @@ -0,0 +1,69 @@ +#include "qpointedit.h" +#include "qpointeditplugin.h" +#include + + +QPointEditPlugin::QPointEditPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QPointEditPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QPointEditPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QPointEditPlugin::createWidget(QWidget * parent) { + return new QPointEdit(parent); +} + + +QString QPointEditPlugin::name() const { + return QLatin1String("QPointEdit"); +} + + +QString QPointEditPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon QPointEditPlugin::icon() const { + return QIcon(":/icons/qpointedit.png"); +} + + +QString QPointEditPlugin::toolTip() const { + return QLatin1String("Point Edit"); +} + + +QString QPointEditPlugin::whatsThis() const { + return QLatin1String("Point Edit"); +} + + +bool QPointEditPlugin::isContainer() const { + return false; +} + + +QString QPointEditPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QPointEditPlugin::includeFile() const { + return QLatin1String("qpointedit.h"); +} + diff --git a/qad/widgets/plugin/qpointeditplugin.h b/qad/widgets/plugin/qpointeditplugin.h new file mode 100644 index 0000000..9ab5177 --- /dev/null +++ b/qad/widgets/plugin/qpointeditplugin.h @@ -0,0 +1,31 @@ +#ifndef QPOINTEDITPLUGIN_H +#define QPOINTEDITPLUGIN_H + +#include + +class QPointEditPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QPointEditPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QPOINTEDITPLUGIN_H diff --git a/qad/widgets/plugin/qrecteditplugin.cpp b/qad/widgets/plugin/qrecteditplugin.cpp new file mode 100644 index 0000000..f64f30c --- /dev/null +++ b/qad/widgets/plugin/qrecteditplugin.cpp @@ -0,0 +1,69 @@ +#include "qrectedit.h" +#include "qrecteditplugin.h" +#include + + +QRectEditPlugin::QRectEditPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QRectEditPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QRectEditPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QRectEditPlugin::createWidget(QWidget * parent) { + return new QRectEdit(parent); +} + + +QString QRectEditPlugin::name() const { + return QLatin1String("QRectEdit"); +} + + +QString QRectEditPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon QRectEditPlugin::icon() const { + return QIcon(":/icons/qrectedit.png"); +} + + +QString QRectEditPlugin::toolTip() const { + return QLatin1String("Rect Edit"); +} + + +QString QRectEditPlugin::whatsThis() const { + return QLatin1String("Rect Edit"); +} + + +bool QRectEditPlugin::isContainer() const { + return false; +} + + +QString QRectEditPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QRectEditPlugin::includeFile() const { + return QLatin1String("qrectedit.h"); +} + diff --git a/qad/widgets/plugin/qrecteditplugin.h b/qad/widgets/plugin/qrecteditplugin.h new file mode 100644 index 0000000..54beeaf --- /dev/null +++ b/qad/widgets/plugin/qrecteditplugin.h @@ -0,0 +1,31 @@ +#ifndef QRECTEDITPLUGIN_H +#define QRECTEDITPLUGIN_H + +#include + +class QRectEditPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QRectEditPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QRECTEDITPLUGIN_H diff --git a/qad/widgets/plugin/qvarianteditplugin.cpp b/qad/widgets/plugin/qvarianteditplugin.cpp new file mode 100644 index 0000000..733eb88 --- /dev/null +++ b/qad/widgets/plugin/qvarianteditplugin.cpp @@ -0,0 +1,69 @@ +#include "qvariantedit.h" +#include "qvarianteditplugin.h" +#include + + +QVariantEditPlugin::QVariantEditPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void QVariantEditPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool QVariantEditPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * QVariantEditPlugin::createWidget(QWidget * parent) { + return new QVariantEdit(parent); +} + + +QString QVariantEditPlugin::name() const { + return QLatin1String("QVariantEdit"); +} + + +QString QVariantEditPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon QVariantEditPlugin::icon() const { + return QIcon(":/icons/qvariantedit.png"); +} + + +QString QVariantEditPlugin::toolTip() const { + return QLatin1String("QVariant Edit"); +} + + +QString QVariantEditPlugin::whatsThis() const { + return QLatin1String("QVariant Edit"); +} + + +bool QVariantEditPlugin::isContainer() const { + return false; +} + + +QString QVariantEditPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString QVariantEditPlugin::includeFile() const { + return QLatin1String("qvariantedit.h"); +} + diff --git a/qad/widgets/plugin/qvarianteditplugin.h b/qad/widgets/plugin/qvarianteditplugin.h new file mode 100644 index 0000000..20b0b3d --- /dev/null +++ b/qad/widgets/plugin/qvarianteditplugin.h @@ -0,0 +1,31 @@ +#ifndef QVARIANTEDITPLUGIN_H +#define QVARIANTEDITPLUGIN_H + +#include + +class QVariantEditPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + QVariantEditPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // QVARIANTEDITPLUGIN_H diff --git a/qad/widgets/plugin/shortcutsplugin.cpp b/qad/widgets/plugin/shortcutsplugin.cpp new file mode 100644 index 0000000..774f4e3 --- /dev/null +++ b/qad/widgets/plugin/shortcutsplugin.cpp @@ -0,0 +1,69 @@ +#include "shortcuts.h" +#include "shortcutsplugin.h" +#include + + +ShortcutsPlugin::ShortcutsPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void ShortcutsPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool ShortcutsPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * ShortcutsPlugin::createWidget(QWidget * parent) { + return new Shortcuts(parent, false); +} + + +QString ShortcutsPlugin::name() const { + return QLatin1String("Shortcuts"); +} + + +QString ShortcutsPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon ShortcutsPlugin::icon() const { + return QIcon(); +} + + +QString ShortcutsPlugin::toolTip() const { + return QLatin1String("Shortcuts Edit"); +} + + +QString ShortcutsPlugin::whatsThis() const { + return QLatin1String("Shortcuts Edit"); +} + + +bool ShortcutsPlugin::isContainer() const { + return false; +} + + +QString ShortcutsPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString ShortcutsPlugin::includeFile() const { + return QLatin1String("shortcuts.h"); +} + diff --git a/qad/widgets/plugin/shortcutsplugin.h b/qad/widgets/plugin/shortcutsplugin.h new file mode 100644 index 0000000..d2eca1b --- /dev/null +++ b/qad/widgets/plugin/shortcutsplugin.h @@ -0,0 +1,31 @@ +#ifndef SHORTCUTSPLUGIN_H +#define SHORTCUTSPLUGIN_H + +#include + +class ShortcutsPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + ShortcutsPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif diff --git a/qad/widgets/plugin/spinsliderplugin.cpp b/qad/widgets/plugin/spinsliderplugin.cpp new file mode 100644 index 0000000..683312d --- /dev/null +++ b/qad/widgets/plugin/spinsliderplugin.cpp @@ -0,0 +1,69 @@ +#include "spinslider.h" +#include "spinsliderplugin.h" +#include + + +SpinSliderPlugin::SpinSliderPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void SpinSliderPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool SpinSliderPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * SpinSliderPlugin::createWidget(QWidget * parent) { + return new SpinSlider(parent); +} + + +QString SpinSliderPlugin::name() const { + return QLatin1String("SpinSlider"); +} + + +QString SpinSliderPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon SpinSliderPlugin::icon() const { + return QIcon(":/icons/spinslider.png"); +} + + +QString SpinSliderPlugin::toolTip() const { + return QLatin1String("Spin with Slider"); +} + + +QString SpinSliderPlugin::whatsThis() const { + return QLatin1String("Spin with Slider"); +} + + +bool SpinSliderPlugin::isContainer() const { + return false; +} + + +QString SpinSliderPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString SpinSliderPlugin::includeFile() const { + return QLatin1String("spinslider.h"); +} + diff --git a/qad/widgets/plugin/spinsliderplugin.h b/qad/widgets/plugin/spinsliderplugin.h new file mode 100644 index 0000000..fbf4d85 --- /dev/null +++ b/qad/widgets/plugin/spinsliderplugin.h @@ -0,0 +1,31 @@ +#ifndef SPINSLIDERPLUGIN_H +#define SPINSLIDERPLUGIN_H + +#include + +class SpinSliderPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + SpinSliderPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif diff --git a/qad/widgets/qad_widgets.qrc b/qad/widgets/qad_widgets.qrc new file mode 100644 index 0000000..38360db --- /dev/null +++ b/qad/widgets/qad_widgets.qrc @@ -0,0 +1,40 @@ + + + lang/qad_widgets_ru.ts + ../icons/dialog-close.png + ../icons/edit-clear.png + ../icons/edit-guides.png + ../icons/view-grid.png + ../icons/zoom-fit-best.png + ../icons/configure.png + ../icons/alpha.png + ../icons/document-save.png + ../icons/edit-clear-locationbar-rtl.png + ../icons/edit-find.png + ../icons/list-add.png + ../icons/edit-delete.png + ../icons/item-add.png + ../icons/item.png + ../icons/node-add.png + ../icons/node.png + ../icons/edit-copy.png + ../icons/edit-paste.png + ../icons/expand_s_x.png + ../icons/expand_s_y.png + ../icons/expand_x.png + ../icons/expand_y.png + ../icons/border-line.png + ../icons/legend.png + ../icons/chardialog.png + ../icons/clineedit.png + ../icons/colorbutton.png + ../icons/ecombobox.png + ../icons/qpiconsole.png + ../icons/spinslider.png + ../icons/etabwidget.png + ../icons/qcodeedit.png + ../icons/qvariantedit.png + ../icons/code-word.png + ../icons/f1.png + + diff --git a/qad/widgets/qcodeedit.cpp b/qad/widgets/qcodeedit.cpp new file mode 100644 index 0000000..6e9ea5e --- /dev/null +++ b/qad/widgets/qcodeedit.cpp @@ -0,0 +1,1003 @@ +#include "qcodeedit.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +QCodeEdit::QCodeEdit(QWidget * parent): QWidget(parent) { + prev_lc = auto_comp_pl = -1; + textCode = textLines = 0; + + timer = 0; + _ignore_focus_out = _destructor = false; + _first = true; + es_line.format.setBackground(QColor(240, 245, 240)); + es_line.format.setProperty(QTextFormat::FullWidthSelection, true); + es_cursor.format.setBackground(QColor(220, 255, 200)); + widget_help = new QFrame(); + widget_help->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + widget_help->setFocusPolicy(Qt::NoFocus); + widget_help->setFrameShadow(QFrame::Sunken); + widget_help->setFrameShape(QFrame::StyledPanel); + widget_help->setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); + widget_help->layout()->setContentsMargins(0, 0, 0, 0); + for (int i = 0; i < 2; ++i) { + lbl_help[i] = new IconedLabel(); + lbl_help[i]->setFrameShadow(QFrame::Plain); + lbl_help[i]->setFrameShape(QFrame::NoFrame); + lbl_help[i]->setDirection(IconedLabel::RightToLeft); + widget_help->layout()->addWidget(lbl_help[i]); + } + lbl_help[1]->setIcon(QIcon(":/icons/f1.png")); + lbl_help[1]->setText(trUtf8("Press F1 for details")); + completer = new QTreeWidget(); + completer->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + completer->setFocusPolicy(Qt::NoFocus); + completer->setColumnCount(2); + completer->setRootIsDecorated(false); + completer->setHeaderHidden(true); + completer->header()->setDefaultAlignment(Qt::AlignCenter); + completer->header()-> +#if (QT_VERSION >= 0x050000) + setSectionResizeMode +#else + setResizeMode +#endif + (QHeaderView::ResizeToContents); + completer->header()->setStretchLastSection(true); + //completer->setColumnWidth(0, 180); + completer->resize(500, 200); + textCode = new QPlainTextEdit(); + textLines = new QPlainTextEdit(); + textCode->setFrameShadow(QFrame::Plain); + textCode->setFrameShape(QFrame::NoFrame); + textCode->setLineWrapMode(QPlainTextEdit::NoWrap); + textCode->setTabChangesFocus(false); + textLines->setFrameShadow(QFrame::Plain); + textLines->setFrameShape(QFrame::NoFrame); + textLines->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + textLines->setFocusPolicy(Qt::NoFocus); + textLines->setTextInteractionFlags(Qt::NoTextInteraction); + textLines->setLineWrapMode(QPlainTextEdit::NoWrap); + textLines->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + textLines->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + textLines->viewport()->setAutoFillBackground(false); + textLines->viewport()->setCursor(Qt::ArrowCursor); + textLines->setFixedWidth(textLines->fontMetrics().width(" ")); + setLayout(new QBoxLayout(QBoxLayout::BottomToTop)); + layout()->setContentsMargins(0, 0, 0, 0); + QFrame * frame = new QFrame(); + frame->setFrameShadow(QFrame::Sunken); + frame->setFrameShape(QFrame::StyledPanel); + frame->setLayout(new QBoxLayout(QBoxLayout::LeftToRight)); + frame->layout()->setContentsMargins(0, 0, 0, 0); + frame->layout()->setSpacing(0); + frame->layout()->addWidget(textLines); + frame->layout()->addWidget(textCode); + layout()->addWidget(frame); + + QAction * a = new QAction(this); + a->setShortcut(QKeySequence("Shift+Tab")); + a->setShortcutContext(Qt::WidgetShortcut); + connect(a, SIGNAL(triggered(bool)), this, SLOT(deindent())); + textCode->addAction(a); + a = new QAction(this); + a->setShortcut(QKeySequence("Ctrl+D")); + a->setShortcutContext(Qt::WidgetShortcut); + connect(a, SIGNAL(triggered(bool)), this, SLOT(deleteLine())); + textCode->addAction(a); + frame->setFocusProxy(textCode); + QTextOption to = textLines->document()->defaultTextOption(); + to.setAlignment(Qt::AlignTop | Qt::AlignRight); + textLines->document()->setDefaultTextOption(to); + setShowSpaces(true); + + connect(completer, SIGNAL(itemDoubleClicked(QTreeWidgetItem * ,int)), this, SLOT(commitCompletition())); + connect(textCode->verticalScrollBar(), SIGNAL(valueChanged(int)), textLines->verticalScrollBar(), SLOT(setValue(int))); + connect(textCode, SIGNAL(textChanged()), this, SLOT(updateLines())); + connect(textCode, SIGNAL(textChanged()), this, SIGNAL(textChanged())); + connect(textCode, SIGNAL(cursorPositionChanged()), this, SLOT(textEdit_cursorPositionChanged())); + connect(textCode, SIGNAL(selectionChanged()), this, SLOT(textEdit_selectionChanged())); + updateLines(); + + registerAutoCompletitionClass(-1, QCodeEdit::Keyword, "Words", QIcon(":/icons/code-word.png")); +} + + +QCodeEdit::~QCodeEdit() { + _destructor = true; + delete textCode; + delete textLines; + delete completer; + //for (int i = 0; i < 2; ++i) + // delete lbl_help[i]; + delete widget_help; +} + + +int QCodeEdit::skipRange(const QString & s, int pos, QChar oc, QChar cc, QChar sc) { + int cnt = 0; + bool skip = false; + for (int i = pos - 1; i >= 0; --i) { + QChar c = s[i]; + if (skip) {skip = false; continue;} + if (c == sc) {skip = true; continue;} + if (c == cc) {cnt++; continue;} + if (c == oc) {cnt--; if (cnt == 0) return i;} + } + return -1; +} + + +int QCodeEdit::skipCWord(const QString & s, int pos) { + QChar pc(0), c(0); + for (int i = pos - 1; i >= 0; --i) { + pc = c; + c = s[i]; + if (c.isLetterOrNumber() || (c.toLatin1() == '_')) continue; + if (pc.isLetter() || (pc.toLatin1() == '_')) return i + 1; + return -1; + } + return -1; +} + + +bool QCodeEdit::matchWritten(QString s, QString w) { + if (s.isEmpty() || w.isEmpty()) return true; + if (s.contains(w, Qt::CaseInsensitive)) return true; + int sp(0); + for (int i = 0; i < w.size(); ++i, ++sp) { + if (sp >= s.size()) return false; + QChar wc(w[i].toLower()); + bool ns = false, bl = true; + while (sp < s.size()) { + if (ns || s[sp].toLatin1() == '_') { + if (s[sp].toLatin1() == '_') {sp++; bl = false; continue;} + if (s[sp].isLower() && bl) {sp++; continue;} + if (s[sp].toLower() != wc) return false; + } + if (s[sp].toLower() == wc) break; + ns = true; + sp++; + } + if (sp >= s.size()) return false; + } + return true; +} + + +QChar QCodeEdit::pairChar(QChar c) { + switch (c.toLatin1()) { + case '\"': return '\"'; + case '(': return ')'; + case ')': return '('; + case '[': return ']'; + case ']': return '['; + default: break; + } + return QChar(); +} + + +bool QCodeEdit::eventFilter(QObject * o, QEvent * e) { + if (_destructor) return QWidget::eventFilter(o, e); + if (e->type() == QEvent::Destroy) { + completer->removeEventFilter(this); + textCode->removeEventFilter(this); + textCode->viewport()->removeEventFilter(this); + textLines->viewport()->removeEventFilter(this); + return QWidget::eventFilter(o, e); + } + if (textLines) { + if (o == textLines->viewport()) { + if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || + e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonDblClick) { +#if (QT_VERSION < 0x050000) + const_cast(((QMouseEvent*)e)->pos()) = QPoint(0, ((QMouseEvent*)e)->pos().y()); +#endif + QApplication::sendEvent(textCode->viewport(), e); + return true; + } + if (e->type() == QEvent::Wheel) { + QApplication::sendEvent(textCode->viewport(), e); + return true; + } + } + } + if (o == completer) { + //qDebug() << o << e; + if (e->type() == QEvent::WindowActivate) + _ignore_focus_out = true; + //qDebug() << e; + return QWidget::eventFilter(o, e); + } + if (textCode) { + if (o == textCode->viewport()) { + if (e->type() == QEvent::MouseButtonPress) { + completer->hide(); + hideHelp(); + } + if (e->type() == QEvent::ToolTip) { + QTextCursor tc = textCode->cursorForPosition(((QHelpEvent*)e)->pos()); + tc.select(QTextCursor::WordUnderCursor); + raiseHelp(tc); + } + return QWidget::eventFilter(o, e); + } + if (o == textCode) { + //qDebug() << o << e; + QMetaObject::invokeMethod(this, "syncScrolls", Qt::QueuedConnection); + QKeyEvent * ke; + QChar kc(0); + switch (e->type()) { + case QEvent::KeyPress: + ke = (QKeyEvent * )e; + switch (ke->key()) { + case Qt::Key_Space: + if (ke->modifiers().testFlag(Qt::ControlModifier)) { + invokeAutoCompletition(true); + return true; + } + break; + case Qt::Key_Escape: + completer->hide(); + hideHelp(); + break; + case Qt::Key_Up: + if (completer->isVisible()) { + previousCompletition(); + return true; + } + completer->hide(); + hideHelp(); + if (ke->modifiers().testFlag(Qt::AltModifier)) { + copyLineUp(); + return true; + } + if (ke->modifiers().testFlag(Qt::ControlModifier) && ke->modifiers().testFlag(Qt::ShiftModifier)) { + moveLineUp(); + return true; + } + break; + case Qt::Key_Down: + if (completer->isVisible()) { + nextCompletition(); + return true; + } + completer->hide(); + hideHelp(); + if (ke->modifiers().testFlag(Qt::AltModifier)) { + copyLineDown(); + return true; + } + if (ke->modifiers().testFlag(Qt::ControlModifier) && ke->modifiers().testFlag(Qt::ShiftModifier)) { + moveLineDown(); + return true; + } + break; + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_PageUp: + case Qt::Key_PageDown: + if (completer->isVisible()) { + qApp->sendEvent(completer, new QKeyEvent(e->type(), ke->key(), ke->modifiers())); + return true; + } + break; + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Backspace: + case Qt::Key_Delete: + if (completer->isVisible()) + QMetaObject::invokeMethod(this, "invokeAutoCompletition", Qt::QueuedConnection, Q_ARG(bool, false)); + break; + case Qt::Key_Return: + if (completer->isVisible()) { + commitCompletition(); + completer->hide(); + return true; + } + if (textCode->textCursor().selectedText().isEmpty()) + QMetaObject::invokeMethod(this, "autoIndent", Qt::QueuedConnection); + break; + case Qt::Key_Tab: + if (!textCode->textCursor().selectedText().isEmpty()) { + if (ke->modifiers().testFlag(Qt::ShiftModifier)) + deindent(); + else + indent(); + return true; + } + break; + case Qt::Key_D: + if (ke->modifiers().testFlag(Qt::ControlModifier)) { + completer->hide(); + return true; + } + break; + default: break; + } + if (!ke->text().isEmpty()) + kc = ke->text()[0]; + if (kc == '.') { + completer->hide(); + QMetaObject::invokeMethod(this, "invokeAutoCompletition", Qt::QueuedConnection, Q_ARG(bool, false)); + } else { + if ((kc.isLetterOrNumber() || kc.toLatin1() == '_') && completer->isVisible()) + QMetaObject::invokeMethod(this, "invokeAutoCompletition", Qt::QueuedConnection, Q_ARG(bool, false)); + } + break; + case QEvent::FocusOut: + if (_ignore_focus_out) { + _ignore_focus_out = false; + break; + } + case QEvent::Hide: + case QEvent::HideToParent: + case QEvent::MouseButtonPress: + //qDebug() << e; + completer->hide(); + hideHelp(); + default: break; + } + } + } + return QWidget::eventFilter(o, e); +} + + +void QCodeEdit::showEvent(QShowEvent * ) { + if (!_first) return; + _first = false; + completer->installEventFilter(this); + textCode->installEventFilter(this); + textCode->viewport()->installEventFilter(this); + textLines->viewport()->installEventFilter(this); +} + + +void QCodeEdit::timerEvent(QTimerEvent * ) { + parse(); + emit parseRequest(); + killTimer(timer); + timer = 0; +} + + +void QCodeEdit::applyExtraSelection() { + textCode->setExtraSelections(QList() << es_line << es_selected << es_custom << es_cursor); +} + + +void QCodeEdit::nextCompletition() { + int ci = completer->currentIndex().row(); + if (ci >= completer->topLevelItemCount() - 1) return; + if (completer->topLevelItem(ci + 1)->flags().testFlag(Qt::ItemIsSelectable)) + completer->setCurrentItem(completer->topLevelItem(ci + 1)); + else { + if (ci >= completer->topLevelItemCount() - 2) return; + completer->setCurrentItem(completer->topLevelItem(ci + 2)); + } +} + + +void QCodeEdit::previousCompletition() { + int ci = completer->currentIndex().row(); + if (ci <= 0) return; + if (completer->topLevelItem(ci - 1)->flags().testFlag(Qt::ItemIsSelectable)) + completer->setCurrentItem(completer->topLevelItem(ci - 1)); + else { + if (ci <= 1) return; + completer->setCurrentItem(completer->topLevelItem(ci - 2)); + } +} + + +void QCodeEdit::syncScrolls() { + textLines->verticalScrollBar()->setValue(textCode->verticalScrollBar()->value()); +} + + +void QCodeEdit::deleteLine() { + QTextCursor tc = textCode->textCursor(); + tc.movePosition(QTextCursor::EndOfLine); + tc.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); + bool md = true; + if (!tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor)) { + tc.movePosition(QTextCursor::StartOfLine); + tc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + md = false; + } + tc.removeSelectedText(); + tc.movePosition(QTextCursor::StartOfLine); + if (md) tc.movePosition(QTextCursor::Down); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::copyLineUp() { + QTextCursor tc = textCode->textCursor(); + int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; + QString st_ = tc.selection().toPlainText(); + if (st_.endsWith("\n")) { + st_.chop(1); + se--; se_--; + } + tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); + tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); + tc.setPosition(ss); tc.setPosition(se, QTextCursor::KeepAnchor); + bool ins_nl = false; + if (!tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor)) + ins_nl = true; + QString l = tc.selectedText(); + tc.beginEditBlock(); + tc.setPosition(ss); + if (ins_nl) + l.append("\n"); + tc.insertText(l); + tc.setPosition(ss_); + tc.setPosition(se_, QTextCursor::KeepAnchor); + tc.endEditBlock(); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::copyLineDown() { + QTextCursor tc = textCode->textCursor(); + int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; + QString st_ = tc.selection().toPlainText(); + if (st_.endsWith("\n")) { + st_.chop(1); + se--; se_--; + } + tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); + tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); + tc.setPosition(ss); tc.setPosition(se, QTextCursor::KeepAnchor); + bool ins_nl = false; + if (!tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor)) + ins_nl = true; + QString l = tc.selectedText(); + tc.beginEditBlock(); + tc.setPosition(ss); + ss_ += l.size(); se_ += l.size(); + if (ins_nl) { + l.append("\n"); + ss_++; se_++; + } + tc.insertText(l); + tc.setPosition(ss_); + tc.setPosition(se_, QTextCursor::KeepAnchor); + tc.endEditBlock(); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::moveLineUp() { + QTextCursor tc = textCode->textCursor(); + int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; + QString st_ = tc.selection().toPlainText(); + if (st_.endsWith("\n")) { + st_.chop(1); + se--; se_--; + } + tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); + tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); + tc.setPosition(ss); + if (!tc.movePosition(QTextCursor::Up)) + return; + tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); + QString l = tc.selectedText(); + ss -= l.size(); se -= l.size(); + ss_ -= l.size(); se_ -= l.size(); + tc.beginEditBlock(); + tc.removeSelectedText(); + tc.setPosition(se); + bool de = false; + if (!tc.movePosition(QTextCursor::Right)) { + l.prepend("\n"); + de = true; + } + tc.insertText(l); + if (de) { + tc.movePosition(QTextCursor::End); + tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); + tc.removeSelectedText(); + } + tc.setPosition(ss_); + tc.setPosition(se_, QTextCursor::KeepAnchor); + tc.endEditBlock(); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::moveLineDown() { + QTextCursor tc = textCode->textCursor(); + int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; + QString st_ = tc.selection().toPlainText(); + if (st_.endsWith("\n")) { + st_.chop(1); + se--; se_--; + } + tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); + tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); + tc.setPosition(se); + if (!tc.movePosition(QTextCursor::Right)) + return; + bool de = false; + if (!tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor)) { + tc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); + de = true; + } + QString l = tc.selectedText(); + tc.beginEditBlock(); + tc.removeSelectedText(); + tc.setPosition(ss); + if (de) l += "\n"; + tc.insertText(l); + if (de) { + tc.movePosition(QTextCursor::End); + tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); + tc.removeSelectedText(); + } + ss += l.size(); se += l.size(); + ss_ += l.size(); se_ += l.size(); + tc.setPosition(ss_); + tc.setPosition(se_, QTextCursor::KeepAnchor); + tc.endEditBlock(); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::indent() { + QTextCursor tc = textCode->textCursor(); + int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; + QString st_ = tc.selection().toPlainText(); + if (st_.endsWith("\n")) { + st_.chop(1); + se--; se_--; + } + tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); + tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); + tc.setPosition(ss); + while (tc.position() < se_) { + tc.insertText("\t"); + se_++; + tc.movePosition(QTextCursor::StartOfLine); + if (!tc.movePosition(QTextCursor::Down)) + break; + } + tc.setPosition(ss_ + 1); + tc.setPosition(se_, QTextCursor::KeepAnchor); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::deindent() { + QTextCursor tc = textCode->textCursor(); + int ss = tc.selectionStart(), ss_ = ss, se = tc.selectionEnd(), se_ = se; + QString st_ = tc.selection().toPlainText(); + if (st_.endsWith("\n")) { + st_.chop(1); + se--; se_--; + } + tc.setPosition(ss); tc.movePosition(QTextCursor::StartOfLine); ss = tc.position(); + tc.setPosition(se); tc.movePosition(QTextCursor::EndOfLine); se = tc.position(); + tc.setPosition(ss); + bool first = true; + while (tc.position() < se_) { + tc.movePosition(QTextCursor::StartOfLine); + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + int rs = 0; + if (tc.selectedText() == "\t") { + tc.removeSelectedText(); + rs = 1; + } else { + for (int i = 0; i < 4; ++i) { + tc.movePosition(QTextCursor::StartOfLine); + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + if (tc.selectedText() == " ") { + tc.removeSelectedText(); + rs++; + } + } + } + if (first) { + first = false; + ss_ -= rs; + } + se_ -= rs; + tc.movePosition(QTextCursor::StartOfLine); + if (!tc.movePosition(QTextCursor::Down)) + break; + } + tc.setPosition(ss_); + tc.setPosition(se_, QTextCursor::KeepAnchor); + textCode->setTextCursor(tc); +} + + +void QCodeEdit::autoIndent() { + QTextCursor tc = textCode->textCursor(), stc = tc; + tc.movePosition(QTextCursor::StartOfLine); + if (!tc.movePosition(QTextCursor::Up)) return; + tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); + QString line = tc.selectedText(), tabs; + int i = 0; + for (; i < line.size(); ++i) + if (!line[i].isSpace()) { + tabs = line.left(i); + break; + } + if (i >= line.size()) + tabs = line.left(line.size() - 1); + int nt = qMax(0, line.count(QChar('{')) - line.count(QChar('}'))); + tabs.append(QString("\t").repeated(nt)); + if (tabs.isEmpty()) return; + stc.insertText(tabs); + textCode->setTextCursor(stc); +} + + +void QCodeEdit::scrollToTop() { + prev_lc = -1; + updateLines(); + textCode->verticalScrollBar()->setValue(0); + textLines->verticalScrollBar()->setValue(0); +} + + +void QCodeEdit::updateLines() { + if (timer > 0) killTimer(timer); + timer = startTimer(500); + textCode->setTabStopWidth(textCode->fontMetrics().width(" ")); + int lc = textCode->document()->lineCount(); + if (prev_lc == lc) return; + prev_lc = lc; + textLines->setFixedWidth(textLines->fontMetrics().width(QString(" %1").arg(lc))); + textLines->clear(); + for (int i = 1; i <= lc; ++i) + textLines->appendPlainText(QString("%1").arg(i)); + textLines->verticalScrollBar()->setValue(textCode->verticalScrollBar()->value()); +} + + +QString QCodeEdit::selectArg(QString s, int arg) { + if (!s.contains('(') || arg < 0) return s; + QString ss = s.left(s.indexOf('(')); + s.remove(0, ss.size()); + if (s.startsWith('(')) s.remove(0, 1); + if (s.endsWith(')')) s.chop(1); + QStringList al = s.split(","); + QString ret = ss + "("; + for (int i = 0; i < al.size(); ++i) { + if (i > 0) ret += ", "; + if (i == arg) ret += ""; + ret += al[i].trimmed(); + if (i == arg) ret += ""; + } + ret += ")"; + return ret; +} + + +void QCodeEdit::raiseHelp(QTextCursor tc, int arg) { + bool ok; + QPair scope = getScope(tc, &ok); + //qDebug() << "help" << scope; + QString st = tc.selectedText(); + if (arg >= 0) st = scope.second; + if (!ok || st.isEmpty()) { + hideHelp(); + return; + } + ok = false; + ACList acl(autoCompletitionList(scope.first, scope.second)); + foreach (const ACPair & i, acl) { + foreach (const StringsPair & s, i.second) { + QString ts = s.second; + //qDebug() << ts << st; + if (ts != st) { + if (ts.startsWith(st)) { + ts.remove(0, st.size()); + ts = ts.trimmed(); + if (!ts.isEmpty()) { + if (ts[0] != '(') + continue; + } + } else + continue; + } + //qDebug() << s.second << st; + ACClass acc = ac_classes.value(i.first); + lbl_help[0]->setIcon(acc.icon); + lbl_help[0]->setText(QString("[%1] %2 %3").arg(acc.name, s.first, selectArg(s.second, arg))); + ok = true; + break; + } + if (ok) break; + } + if (!ok) { + hideHelp(); + return; + } + es_cursor.cursor = tc; + applyExtraSelection(); + tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, st.size()); + lbl_help[0]->setFont(font()); + widget_help->resize(widget_help->sizeHint()); + widget_help->move(textCode->mapToGlobal(textCode->cursorRect(tc).topLeft() - QPoint(0, widget_help->height() + 8))); + widget_help->show(); + cursor_scope = scope.first; + cursor_scope << scope.second; + //qDebug() << "tooltip" << st; +} + + +void QCodeEdit::hideHelp() { + widget_help->hide(); + es_cursor.cursor = QTextCursor(); + cursor_scope.clear(); + applyExtraSelection(); +} + + +QTextCursor QCodeEdit::functionStart(QTextCursor tc, int * arg) { + QString doc = textCode->toPlainText(); + int bcnt = 0, a = 0, i = -1; + for (i = tc.position() - 1; i >= 0; --i) { + if (doc[i] == ')') bcnt++; + if (doc[i] == '(') { + if (bcnt == 0) + break; + else + bcnt--; + } + //if (doc[i] == '(') bcnt--; + if (doc[i] == ',' && bcnt == 0) a++; + } + if (i < 0) return QTextCursor(); + if (arg) *arg = a; + QTextCursor ret(textCode->document()); + ret.setPosition(i); + //qDebug() << "found" << i << a; + return ret; +} + + +QCodeEdit::ACList QCodeEdit::wordsCompletitionList(const QString & written) const { + QCodeEdit::ACList ret; + if (!written.isEmpty()) { + QTextCursor tc = QTextCursor(textCode->document()->begin()), stc; + QStringList acwl; + tc = QTextCursor(textCode->document()->begin()); + while (true) { + tc = textCode->document()->find(written, tc); + if (tc.isNull()) break; + stc = tc; + stc.movePosition(QTextCursor::Left); + stc.select(QTextCursor::WordUnderCursor); + if (!stc.selectedText().isEmpty() && stc.selectedText().trimmed() != written) + acwl << stc.selectedText(); + } + acwl.removeDuplicates(); + ACPair acl; + acl.first = -1; + foreach (const QString & s, acwl) + acl.second << StringsPair("", s); + ret << acl; + } + return ret; +} + + +QPair QCodeEdit::getScope(QTextCursor tc, bool * ok) { + QPair ret; + QTextCursor stc = tc; + if (tc.isNull()) { + completer->hide(); + if (ok) *ok = false; + return ret; + } + int line = tc.block().firstLineNumber(); + if (completer->isVisible()) { + if (auto_comp_pl != line) { + completer->hide(); + auto_comp_pl = line; + if (ok) *ok = false; + return ret; + } + } + QString doc = textCode->toPlainText(); + auto_comp_pl = line; + completer->clear(); + int spos = tc.position(), cpos = spos; + tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); + QStringList scope; + QString written = tc.selectedText().trimmed(); + //qDebug() << "\n*** invokeAutoCompletition ***"; + if (written != "_" && !written.leftJustified(1)[0].isLetterOrNumber()) { + written.clear(); + } else { + cpos = skipCWord(doc, spos); + if (cpos >= 0) + written = doc.mid(cpos, spos - cpos).trimmed(); + } + while (cpos >= 0) { + cpos--; + //qDebug() << "char =" << doc.mid(cpos, 1); + if (doc.mid(cpos, 1) != ".") break; + QChar c = doc.mid(cpos - 1, 1).leftJustified(1)[0]; + int ppos = cpos; + if (c == '\"' || c == ')' || c == ']') { + cpos = skipRange(doc, cpos, pairChar(c), c, '\\'); + //qDebug() << "range" << cpos; + if (cpos < 0) break; + } + int npos = skipCWord(doc, cpos); + if (npos < 0) break; + scope.push_front(doc.mid(npos, ppos - npos)); + cpos = npos; + } + ret.first = scope; + ret.second = written; + if (ok) *ok = true; + return ret; +} + + +void QCodeEdit::invokeAutoCompletition(bool force) { + int arg = -1; + QTextCursor htc = functionStart(textCode->textCursor(), &arg); + if (!htc.isNull()) { + //qDebug() << "raise"; + raiseHelp(htc, arg); + } + bool ok; + QPair scope = getScope(textCode->textCursor(), &ok); + if (!ok) return; + ACList acl(autoCompletitionList(scope.first, scope.second)); + //qDebug() << written << scope << acl.size(); + if (scope.first.isEmpty() && scope.second.isEmpty() && !force) { + completer->hide(); + hideHelp(); + return; + } + acl << wordsCompletitionList(scope.second); + QFont bf(font()); + bf.setBold(true); + foreach (const ACPair & ac, acl) { + if (ac.second.isEmpty()) continue; + ACClass acc = ac_classes.value(ac.first); + QTreeWidgetItem * gi = new QTreeWidgetItem(); + gi->setText(0, acc.name); + gi->setTextAlignment(0, Qt::AlignCenter); + gi->setTextAlignment(1, Qt::AlignCenter); + gi->setFont(0, bf); + gi->setBackgroundColor(0, Qt::lightGray); + gi->setFlags(Qt::ItemIsEnabled); + completer->addTopLevelItem(gi); + gi->setFirstColumnSpanned(true); + foreach (const StringsPair & s, ac.second) { + QTreeWidgetItem * ni = new QTreeWidgetItem(); + ni->setIcon(0, acc.icon); + ni->setText(0, s.first); + ni->setText(1, s.second); + completer->addTopLevelItem(ni); + } + } + if (completer->topLevelItemCount() > 1) + completer->setCurrentItem(completer->topLevelItem(1)); + if (completer->isHidden()) + completer->move(textCode->mapToGlobal(textCode->cursorRect().bottomRight())); + completer->setVisible(completer->topLevelItemCount() > 0); +} + + +void QCodeEdit::commitCompletition() { + if (completer->currentItem() == 0) return; + if (!completer->currentItem()->flags().testFlag(Qt::ItemIsSelectable)) return; + QString ins = completer->currentItem()->text(1), ret = completer->currentItem()->text(0); + QTextCursor tc = textCode->textCursor(), stc = tc; + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + bool ins_br = true, shifted = false; + if (!tc.selectedText().isEmpty()) { + if (!tc.selectedText()[0].isLetterOrNumber() && !tc.selectedText()[0].isSpace()) { + stc.movePosition(QTextCursor::Left); + shifted = true; + } else { + tc.movePosition(QTextCursor::Left); + tc.movePosition(QTextCursor::EndOfWord); + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + } + if (!tc.selectedText().isEmpty()) + if (tc.selectedText()[0].toLatin1() == '(') + ins_br = false; + } + if (ins.contains("(")) + ins = ins.left(ins.indexOf("(")) + "()"; + if (!ins_br && ins.endsWith("()")) + ins.chop(2); + tc = stc; + tc.select(QTextCursor::WordUnderCursor); + if (!tc.selectedText().leftJustified(1)[0].isLetterOrNumber()) { + tc = stc; + if (shifted) + tc.movePosition(QTextCursor::Right); + } + textCode->setTextCursor(tc); + textCode->textCursor().insertText(ins); + tc = textCode->textCursor(); + if (ins_br) { + if (ret == "void") { + tc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + if (tc.selectedText() != ";") { + textCode->textCursor().insertText(";"); + tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 2); + } + } + if (ins.endsWith(")") && !completer->currentItem()->text(1).endsWith("()")) { + tc.movePosition(QTextCursor::Left); + textCode->setTextCursor(tc); + } + } else { + if (completer->currentItem()->text(1).endsWith(")")) { + tc.movePosition(QTextCursor::Right); + textCode->setTextCursor(tc); + } + if (completer->currentItem()->text(1).endsWith("()")) { + tc.movePosition(QTextCursor::Right); + textCode->setTextCursor(tc); + } + } + completer->hide(); +} + + +void QCodeEdit::textEdit_cursorPositionChanged() { + es_line.cursor = textCode->textCursor(); + es_line.cursor.select(QTextCursor::LineUnderCursor); + es_line.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + applyExtraSelection(); +} + + +void QCodeEdit::textEdit_textChanged() { + updateLines(); +} + + +void QCodeEdit::textEdit_selectionChanged() { + es_selected.clear(); + QString sf = textCode->textCursor().selectedText(); + if (sf.trimmed().isEmpty() || sf.contains("\n")) { + applyExtraSelection(); + return; + } + QTextCursor tc(textCode->document()->begin()); + QTextEdit::ExtraSelection es; + es.format.setBackground(QColor(251, 250, 150)); + while (true) { + tc = textCode->document()->find(sf, tc, QTextDocument::FindCaseSensitively | QTextDocument::FindWholeWords); + if (tc.isNull()) break; + es.cursor = tc; + es_selected << es; + } + applyExtraSelection(); +} + + +void QCodeEdit::setShowSpaces(bool yes) { + spaces_ = yes; + QTextOption to = textCode->document()->defaultTextOption(); + to.setFlags(yes ? QTextOption::ShowTabsAndSpaces : (QTextOption::Flags)0); + textCode->document()->setDefaultTextOption(to); +} diff --git a/qad/widgets/qcodeedit.h b/qad/widgets/qcodeedit.h new file mode 100644 index 0000000..f477180 --- /dev/null +++ b/qad/widgets/qcodeedit.h @@ -0,0 +1,130 @@ +#ifndef QCODEEDIT_H +#define QCODEEDIT_H + +#include +#include +#include +#include +#include "iconedlabel.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QCodeEdit: public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool showSpaces READ showSpaces WRITE setShowSpaces) + Q_PROPERTY(bool showLineNumbers READ showLineNumbers WRITE setShowLineNumbers) + +public: + QCodeEdit(QWidget * parent = 0); + ~QCodeEdit(); + + enum ACClassType { + Keyword, + Function, + Namespace + }; + + QTextCursor textCursor() const {return textCode->textCursor();} + QTextDocument * document() const {return textCode->document();} + void setTextCursor(const QTextCursor & c) {textCode->setTextCursor(c);} + void centerCursor() {textCode->centerCursor(); updateLines();} + void insertText(const QString & text) {textCode->insertPlainText(text); updateLines();} + void appendText(const QString & text) {textCode->appendPlainText(text); updateLines();} + void setCustomExtraSelection(const QList & es) {es_custom = es; applyExtraSelection();} + QRect cursorRect() const {return textCode->cursorRect();} + QRect cursorRect(const QTextCursor & cursor) const {return textCode->cursorRect(cursor);} + QString text() const {return textCode->toPlainText();} + QStringList cursorScope() const {return cursor_scope;} + bool showSpaces() const {return spaces_;} + bool showLineNumbers() const {return textLines->isVisible();} + + QPlainTextEdit * textEdit() const {return textCode;} + + void registerAutoCompletitionClass(int id, ACClassType ac_class, const QString & name, const QIcon & icon = QIcon()) {ac_classes[id] = ACClass(id, ac_class, name, icon);} + +protected: + typedef QPair StringsPair; + typedef QPair > ACPair; + typedef QList ACList; + + virtual ACList autoCompletitionList(const QStringList & scope, const QString & written) const {return ACList();} + virtual void parse() {} + QString selectArg(QString s, int arg); + void raiseHelp(QTextCursor tc, int arg = -1); + void hideHelp(); + QTextCursor functionStart(QTextCursor tc, int * arg); + ACList wordsCompletitionList(const QString & written) const; + QPair getScope(QTextCursor tc, bool * ok = 0); + static int skipRange(const QString & s, int pos, QChar oc, QChar cc, QChar sc = QChar()); + static int skipCWord(const QString & s, int pos); + static bool matchWritten(QString s, QString w); + static QChar pairChar(QChar c); + +private: + struct ACClass { + ACClass(int i = -2, ACClassType c = QCodeEdit::Keyword, const QString & n = QString(), const QIcon & ic = QIcon()): id(i), class_(c), name(n), icon(ic) {} + int id; + ACClassType class_; + QString name; + QIcon icon; + }; + + QPlainTextEdit * textCode, * textLines; + QTreeWidget * completer; + IconedLabel * lbl_help[2]; + QFrame * widget_help; + QTextEdit::ExtraSelection es_line, es_cursor; + QList es_selected, es_custom; + QMap ac_classes; + QStringList cursor_scope; + int prev_lc, auto_comp_pl, timer; + bool spaces_, _ignore_focus_out, _first, _destructor; + + bool eventFilter(QObject * o, QEvent * e); + void showEvent(QShowEvent * ); + void timerEvent(QTimerEvent * ); + void applyExtraSelection(); + void nextCompletition(); + void previousCompletition(); + +private slots: + void syncScrolls(); + void deleteLine(); + void copyLineUp(); + void copyLineDown(); + void moveLineUp(); + void moveLineDown(); + void indent(); + void deindent(); + void autoIndent(); + void invokeAutoCompletition(bool force = false); + void commitCompletition(); + void textEdit_cursorPositionChanged(); + void textEdit_textChanged(); + void textEdit_selectionChanged(); + +public slots: + void updateLines(); + void scrollToTop(); + void setFocus() {textCode->setFocus();} + void setText(const QString & t) {textCode->setPlainText(t);} + void setShowSpaces(bool yes); + void setShowLineNumbers(bool yes) {textLines->setVisible(yes);} + +signals: + void textChanged(); + void parseRequest(); + +}; + +//Q_DECLARE_OPERATORS_FOR_FLAGS(QPIConsole::Formats) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCODEEDIT_H diff --git a/qad/widgets/qipedit.cpp b/qad/widgets/qipedit.cpp new file mode 100644 index 0000000..dab01f1 --- /dev/null +++ b/qad/widgets/qipedit.cpp @@ -0,0 +1,82 @@ +#include "qipedit.h" + +QIPEdit::QIPEdit(QWidget * parent, const QString & ip): QWidget(parent) { + layout = new QBoxLayout(QBoxLayout::LeftToRight, this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(1); + QIntValidator * validator = new QIntValidator(0, 255, this); + for (int i = 0; i < 4; i++) { + edits.push_back(new QLineEdit(this)); + edits.back()->setAlignment(Qt::AlignHCenter); + edits.back()->setMaxLength(3); + edits.back()->setValidator(validator); + edits.back()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + layout->addWidget(edits.back()); + if (i < 3) { + dots.push_back(new QLabel(this)); + dots.back()->setText("."); + dots.back()->adjustSize(); + layout->addWidget(dots.back()); + } + } + //for (int i = 0; i < 3; i++) edits[i]->setTabOrder(edits[i+1], edits[i]); + connect(edits[0], SIGNAL(returnPressed()), this, SLOT(returnPressed0())); + connect(edits[1], SIGNAL(returnPressed()), this, SLOT(returnPressed1())); + connect(edits[2], SIGNAL(returnPressed()), this, SLOT(returnPressed2())); + connect(edits[3], SIGNAL(returnPressed()), this, SLOT(returnPressed3())); + connect(edits[0], SIGNAL(textChanged(const QString & )), this, SLOT(textChanged0(const QString & ))); + connect(edits[1], SIGNAL(textChanged(const QString & )), this, SLOT(textChanged1(const QString & ))); + connect(edits[2], SIGNAL(textChanged(const QString & )), this, SLOT(textChanged2(const QString & ))); + connect(edits[3], SIGNAL(textChanged(const QString & )), this, SLOT(textChanged3(const QString & ))); + setLayout(layout); + setIP(ip); + cind = 0; +} + + +QIPEdit::~QIPEdit() { + foreach (QLineEdit * i, edits) + delete i; + foreach (QLabel * i, dots) + delete i; + edits.clear(); + dots.clear(); + delete layout; +} + + +void QIPEdit::setIP(const QString & text) { + QString s, str = text; + s = str.left(str.indexOf('.')); + edits[0]->setText(s == "" ? "0" : s); + str = str.right(str.length() - s.length() - 1); + s = str.left(str.indexOf('.')); + edits[1]->setText(s == "" ? "0" : s); + str = str.right(str.length() - s.length() - 1); + s = str.left(str.indexOf('.')); + edits[2]->setText(s == "" ? "0" : s); + str = str.right(str.length() - s.length() - 1); + edits[3]->setText(str == "" ? "0" : str); +} + + +QString QIPEdit::IP() { + QString s; + if (edits[0]->text() == "") s = "0."; + else s = edits[0]->text() + "."; + if (edits[1]->text() == "") s += "0."; + else s += edits[1]->text() + "."; + if (edits[2]->text() == "") s += "0."; + else s += edits[2]->text() + "."; + if (edits[3]->text() == "") s += "0"; + else s += edits[3]->text(); + return s; +} + + +void QIPEdit::returnPress(int index) { + if (index < 3) { + edits[index + 1]->setFocus(); + edits[index + 1]->setSelection(0, 3); + } +} diff --git a/qad/widgets/qipedit.h b/qad/widgets/qipedit.h new file mode 100644 index 0000000..4d44aef --- /dev/null +++ b/qad/widgets/qipedit.h @@ -0,0 +1,48 @@ +#ifndef QIPEDIT_H +#define QIPEDIT_H + +#include +#include +#include +#include +#include +#include + +class QIPEdit: public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString IP READ IP WRITE setIP) + +public: + QIPEdit(QWidget * parent = 0, const QString & ip = ""); + ~QIPEdit(); + + QString IP(); + +private: + void returnPress(int index); + inline void textChange(int index, const QString & text) {if (text.length() == 3 && isVisible()) returnPress(index); emit valueChanged(IP());} + + int cind; + QBoxLayout * layout; + QVector edits; + QVector dots; + +public slots: + void setIP(const QString & text); + +private slots: + void returnPressed0() {returnPress(0);} + void returnPressed1() {returnPress(1);} + void returnPressed2() {returnPress(2);} + void returnPressed3() {returnPress(3);} + void textChanged0(const QString & text) {textChange(0, text);} + void textChanged1(const QString & text) {textChange(1, text);} + void textChanged2(const QString & text) {textChange(2, text);} + void textChanged3(const QString & text) {textChange(3, text);} + +signals: + void valueChanged(QString); +}; + +#endif // QIPEDIT_H diff --git a/qad/widgets/qpiconfignewdialog.cpp b/qad/widgets/qpiconfignewdialog.cpp new file mode 100644 index 0000000..18c450a --- /dev/null +++ b/qad/widgets/qpiconfignewdialog.cpp @@ -0,0 +1,77 @@ +#include "qpiconfignewdialog.h" +#include "ui_qpiconfignewdialog.h" + + +QPIConfigNewDialog::QPIConfigNewDialog(QWidget * parent): QDialog(parent) { + ui = new Ui::QPIConfigNewDialog(); + ui->setupUi(this); + radios = findChildren(); + ui->widgetValue->hideAll(); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); +} + + +void QPIConfigNewDialog::changeEvent(QEvent * e) { + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + + +void QPIConfigNewDialog::typeChanged() { + foreach (QRadioButton * i, radios) { + if (i->isChecked()) { + ui->widgetValue->setType(i->property("type").toString()); + return; + } + } +} + + +QString QPIConfigNewDialog::type() { + foreach (QRadioButton * i, radios) + if (i->isChecked()) + return i->property("type").toString(); + return " "; +} + + +void QPIConfigNewDialog::reset(bool node) { + ui->lineName->clear(); + ui->lineComment->clear(); + ui->radioType_0->setChecked(true); + ui->lineName->setFocus(); + ui->widgetValue->setType("s"); + ui->widgetValue->value.clear(); + ui->widgetValue->setVisible(!node); + ui->groupType->setVisible(!node); + ui->labelValue->setVisible(!node); + ui->labelComment->setVisible(!node); + ui->lineComment->setVisible(!node); + adjustSize(); +} + + +QString QPIConfigNewDialog::name() { + return ui->lineName->text(); +} + + +QString QPIConfigNewDialog::value() { + return ui->widgetValue->value; +} + + +QString QPIConfigNewDialog::comment() { + return ui->lineComment->text(); +} + + +void QPIConfigNewDialog::on_lineName_textChanged(const QString & text) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); +} diff --git a/qad/widgets/qpiconfignewdialog.h b/qad/widgets/qpiconfignewdialog.h new file mode 100644 index 0000000..ea688fd --- /dev/null +++ b/qad/widgets/qpiconfignewdialog.h @@ -0,0 +1,40 @@ +#ifndef QPICONFIGNEWDIALOG_H +#define QPICONFIGNEWDIALOG_H + +#include +#include + + +namespace Ui { + class QPIConfigNewDialog; +} + + +class QPIConfigNewDialog: public QDialog +{ + Q_OBJECT + +public: + QPIConfigNewDialog(QWidget * parent = 0); + + QString type(); + QString name(); + QString value(); + QString comment(); + void reset(bool node = false); + +protected: + void changeEvent(QEvent * e); + + Ui::QPIConfigNewDialog * ui; + +private slots: + void on_lineName_textChanged(const QString & text); + void typeChanged(); + +private: + QList radios; + +}; + +#endif // QPICONFIGNEWDIALOG_H diff --git a/qad/widgets/qpiconfignewdialog.ui b/qad/widgets/qpiconfignewdialog.ui new file mode 100644 index 0000000..b60137f --- /dev/null +++ b/qad/widgets/qpiconfignewdialog.ui @@ -0,0 +1,432 @@ + + + QPIConfigNewDialog + + + + 0 + 0 + 300 + 316 + + + + + 300 + 0 + + + + Dialog + + + + + + Type + + + + + + string + + + true + + + s + + + + + + + integer + + + n + + + + + + + float + + + f + + + + + + + string list + + + l + + + + + + + boolean + + + b + + + + + + + color + + + c + + + + + + + rectangle + + + r + + + + + + + area + + + a + + + + + + + point + + + p + + + + + + + vector + + + v + + + + + + + ip + + + i + + + + + + + + + + Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + Comment: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Value: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + ConfigValueWidget + QWidget +
qpiconfigvaluewidget.h
+ 1 +
+
+ + lineName + buttonBox + + + + + buttonBox + accepted() + QPIConfigNewDialog + accept() + + + 126 + 326 + + + 110 + 231 + + + + + buttonBox + rejected() + QPIConfigNewDialog + reject() + + + 169 + 326 + + + 149 + 232 + + + + + radioType_0 + clicked() + QPIConfigNewDialog + typeChanged() + + + 33 + 70 + + + 1 + 61 + + + + + radioType_1 + clicked() + QPIConfigNewDialog + typeChanged() + + + 25 + 88 + + + -1 + 99 + + + + + radioType_2 + clicked() + QPIConfigNewDialog + typeChanged() + + + 17 + 119 + + + 2 + 130 + + + + + radioType_3 + clicked() + QPIConfigNewDialog + typeChanged() + + + 26 + 143 + + + 0 + 165 + + + + + radioType_4 + clicked() + QPIConfigNewDialog + typeChanged() + + + 50 + 170 + + + 2 + 195 + + + + + radioType_5 + clicked() + QPIConfigNewDialog + typeChanged() + + + 243 + 37 + + + 312 + 10 + + + + + radioType_6 + clicked() + QPIConfigNewDialog + typeChanged() + + + 275 + 67 + + + 315 + 40 + + + + + radioType_7 + clicked() + QPIConfigNewDialog + typeChanged() + + + 262 + 95 + + + 311 + 72 + + + + + radioType_8 + clicked() + QPIConfigNewDialog + typeChanged() + + + 250 + 113 + + + 313 + 104 + + + + + radioType_9 + clicked() + QPIConfigNewDialog + typeChanged() + + + 286 + 145 + + + 311 + 138 + + + + + radioType_10 + clicked() + QPIConfigNewDialog + typeChanged() + + + 273 + 168 + + + 312 + 167 + + + + + + typeChanged() + +
diff --git a/qad/widgets/qpiconfigvaluewidget.cpp b/qad/widgets/qpiconfigvaluewidget.cpp new file mode 100644 index 0000000..c47eba3 --- /dev/null +++ b/qad/widgets/qpiconfigvaluewidget.cpp @@ -0,0 +1,98 @@ +#include "qpiconfigvaluewidget.h" +#include "qpievaluator.h" + + +ConfigValueWidget::ConfigValueWidget(QWidget * parent): QWidget(parent), lay(QBoxLayout::Down, this) { + lay.setContentsMargins(0, 0, 0, 0); + w_integer.setRange(INT_MIN, INT_MAX); + w_float.setRange(-DBL_MAX, DBL_MAX); + w_float.setDecimals(5); + active = true; + lay.addWidget(&w_string); + lay.addWidget(&w_list); + lay.addWidget(&w_bool); + lay.addWidget(&w_integer); + lay.addWidget(&w_float); + lay.addWidget(&w_color); + lay.addWidget(&w_rect); + lay.addWidget(&w_point); + lay.addWidget(&w_ip); + lay.addWidget(&w_enum); + lay.addWidget(&w_path); + connect(&w_string, SIGNAL(textChanged(QString)), this, SLOT(valueChanged())); + connect(&w_list, SIGNAL(valueChanged()), this, SLOT(valueChanged())); + connect(&w_bool, SIGNAL(toggled(bool)), this, SLOT(valueChanged())); + connect(&w_integer, SIGNAL(valueChanged(int)), this, SLOT(valueChanged())); + connect(&w_float, SIGNAL(valueChanged(double)), this, SLOT(valueChanged())); + connect(&w_color, SIGNAL(colorChanged(QColor)), this, SLOT(valueChanged())); + connect(&w_rect, SIGNAL(valueChanged(QRectF)), this, SLOT(valueChanged())); + connect(&w_point, SIGNAL(valueChanged(QPointF)), this, SLOT(valueChanged())); + connect(&w_ip, SIGNAL(valueChanged(QString)), this, SLOT(valueChanged())); + connect(&w_enum, SIGNAL(currentIndexChanged(int)), this, SLOT(valueChanged())); + connect(&w_path, SIGNAL(valueChanged()), this, SLOT(valueChanged())); +} + + +void ConfigValueWidget::setType(const QString & t) { + hideAll(); + type = t.left(1); + active = false; + if (type == "e") {QStringList en_sl = QPIEvaluator::inBrackets(comment).split(';'); + if (en_sl.size()>1) { + w_enum.show(); w_enum.addItems(en_sl); setValue(value); active = true; return; + } else {type = "s";}} + if (type == "s") {w_string.show(); setValue(value); active = true; return;} + if (type == "l") {w_list.show(); setValue(value); active = true; return;} + if (type == "b") {w_bool.show(); setValue(value); active = true; return;} + if (type == "n") {w_integer.show(); setValue(value); active = true; return;} + if (type == "f") {w_float.show(); setValue(value); active = true; return;} + if (type == "c") {w_color.show(); setValue(value); active = true; return;} + if (type == "r") {w_rect.show(); w_rect.setDecimals(0); setValue(value); active = true; return;} + if (type == "a") {w_rect.show(); w_rect.setDecimals(3); setValue(value); active = true; return;} + if (type == "p") {w_point.show(); w_point.setDecimals(0); setValue(value); active = true; return;} + if (type == "v") {w_point.show(); w_point.setDecimals(3); setValue(value); active = true; return;} + if (type == "i") {w_ip.show(); setValue(value); active = true; return;} + if (type == "F") {w_path.show(); setValue(value); active = true; return;} + if (type == "D") {w_path.show(); setValue(value); active = true; return;} +} + + +void ConfigValueWidget::setValue(const QString & v) { + value = v; + active = false; + if (type == "l") {w_list.setValue(v.split("%|%")); active = true; return;} + if (type == "b") {w_bool.setChecked(v.toInt() > 0 || v.toLower().trimmed() == "true"); active = true; return;} + if (type == "n") {w_integer.setValue(QString2int(v)); active = true; return;} + if (type == "f") {w_float.setValue(v.toDouble()); active = true; return;} + if (type == "c") {w_color.setColor(QString2QColor(v)); active = true; return;} + if (type == "r") {w_rect.setValue(QString2QRectF(v)); active = true; return;} + if (type == "a") {w_rect.setValue(QString2QRectF(v)); active = true; return;} + if (type == "p") {w_point.setValue(QString2QPointF(v)); active = true; return;} + if (type == "v") {w_point.setValue(QString2QPointF(v)); active = true; return;} + if (type == "i") {w_ip.setIP(v); active = true; return;} + if (type == "e") {w_enum.setCurrentIndex(w_enum.findText(v)); active = true; return;} + if (type == "F") {w_path.is_dir = false; w_path.setValue(v); active = true; return;} + if (type == "D") {w_path.is_dir = true; w_path.setValue(v); active = true; return;} + w_string.setText(v); + active = true; +} + + +void ConfigValueWidget::valueChanged() { + if (!active) return; + if (type == "l") {value = w_list.value().join("%|%"); emit changed(this, value); return;} + if (type == "b") {value = w_bool.isChecked() ? "true" : "false"; emit changed(this, value); return;} + if (type == "n") {value = QString::number(w_integer.value()); emit changed(this, value); return;} + if (type == "f") {value = QString::number(w_float.value()); emit changed(this, value); return;} + if (type == "c") {value = QColor2QString(w_color.color()); emit changed(this, value); return;} + if (type == "r") {value = QRectF2QString(w_rect.value()); emit changed(this, value); return;} + if (type == "a") {value = QRectF2QString(w_rect.value()); emit changed(this, value); return;} + if (type == "p") {value = QPointF2QString(w_point.value()); emit changed(this, value); return;} + if (type == "v") {value = QPointF2QString(w_point.value()); emit changed(this, value); return;} + if (type == "i") {value = w_ip.IP(); emit changed(this, value); return;} + if (type == "e") {value = w_enum.currentText(); emit changed(this, value); return;} + if (type == "F") {value = w_path.value(); emit changed(this, value); return;} + if (type == "D") {value = w_path.value(); emit changed(this, value); return;} + value = w_string.text(); + emit changed(this, value); +} diff --git a/qad/widgets/qpiconfigvaluewidget.h b/qad/widgets/qpiconfigvaluewidget.h new file mode 100644 index 0000000..4e9614f --- /dev/null +++ b/qad/widgets/qpiconfigvaluewidget.h @@ -0,0 +1,58 @@ +#ifndef QPICONFIGVALUEWIDGET_H +#define QPICONFIGVALUEWIDGET_H + +#include "qpiconfig.h" +#include "qvariantedit.h" +#include "qrectedit.h" +#include "qpointedit.h" +#include "colorbutton.h" +#include "ecombobox.h" +#include "qipedit.h" +#include "limits.h" +#include "float.h" +#include +#include +#include +#include + + +class ConfigValueWidget: public QWidget +{ + Q_OBJECT + friend class QPIConfigWidget; + friend class QPIConfigNewDialog; +public: + ConfigValueWidget(QWidget * parent = 0); + ~ConfigValueWidget() {hide();} + + void setType(const QString & t); + void setValue(const QString & v); + void setEntry(QPIConfig::Entry * e) {value = e->value(); full_name = e->_full_name; comment = e->comment(); setType(e->type());} + +private: + void hideAll() {w_string.hide(); w_list.hide(); w_bool.hide(); w_integer.hide(); w_float.hide(); w_color.hide(); w_rect.hide(); w_point.hide(); w_ip.hide(); w_enum.hide(); w_path.hide();} + + QString type, value, full_name, comment; + bool active; + QBoxLayout lay; + CLineEdit w_string; + StringListEdit w_list; + ColorButton w_color; + QCheckBox w_bool; + QSpinBox w_integer; + QDoubleSpinBox w_float; + QRectEdit w_rect; + QPointEdit w_point; + QIPEdit w_ip; + QComboBox w_enum; + PathEdit w_path; + +private slots: + void valueChanged(); + +signals: + void changed(ConfigValueWidget * , QString ); + +}; + +#endif // QPICONFIGVALUEWIDGET_H diff --git a/qad/widgets/qpiconfigwidget.cpp b/qad/widgets/qpiconfigwidget.cpp new file mode 100644 index 0000000..22cabd1 --- /dev/null +++ b/qad/widgets/qpiconfigwidget.cpp @@ -0,0 +1,380 @@ +#include "qpiconfigwidget.h" + + +QPIConfigWidget::QPIConfigWidget(QWidget * parent, QPIConfig * c, bool on): QTreeWidget(parent), actionAddItem(this), actionAddNode(this), + actionToItem(this), actionToNode(this), actionRemove(this), + actionExpandAll(this), actionCollapseAll(this) { + active = on; + if (active) { + setColumnCount(4); + setColumnWidth(0, 150); + setColumnWidth(1, 200); + } else setColumnCount(0); + setSelectionMode(ExtendedSelection); + setVerticalScrollMode(ScrollPerPixel); + actionAddItem.setIcon(QIcon(":/icons/item-add.png")); + actionAddNode.setIcon(QIcon(":/icons/node-add.png")); + actionToItem.setIcon(QIcon(":/icons/item.png")); + actionToNode.setIcon(QIcon(":/icons/node.png")); + actionRemove.setIcon(QIcon(":/icons/edit-delete.png")); + popupMenu.addAction(&actionAddItem); + popupMenu.addAction(&actionAddNode); + popupMenu.addSeparator(); + /*popupMenu.addAction(&actionToItem); + popupMenu.addAction(&actionToNode); + popupMenu.addSeparator();*/ + popupMenu.addAction(&actionRemove); + popupMenu.addSeparator(); + popupMenu.addAction(&actionExpandAll); + popupMenu.addAction(&actionCollapseAll); + viewport()->installEventFilter(this); + connect(this, SIGNAL(itemClicked(QTreeWidgetItem * , int)), this, SLOT(itemClicked(QTreeWidgetItem * , int))); + connect(this, SIGNAL(itemChanged(QTreeWidgetItem * , int)), this, SLOT(itemChanged(QTreeWidgetItem * , int))); + connect(&actionAddItem, SIGNAL(triggered()), this, SLOT(on_actionAddItem_triggered())); + connect(&actionAddNode, SIGNAL(triggered()), this, SLOT(on_actionAddNode_triggered())); + connect(&actionRemove, SIGNAL(triggered()), this, SLOT(on_actionRemove_triggered())); + connect(&actionExpandAll, SIGNAL(triggered()), this, SLOT(expandAll())); + connect(&actionCollapseAll, SIGNAL(triggered()), this, SLOT(collapseAll())); + read_only_name = read_only_value = read_only_type = read_only_comment = false; + c_hidden << false << false << false << false; + pi = c_pi = 0; + translate(); + setQPIConfig(c); + //resize(600, 400); + //show(); +} + + +void QPIConfigWidget::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + translate(); + return; + } + //for (int i = 0; i < 4; ++i) + // setColumnHidden(i, c_hidden[i]); + QTreeWidget::changeEvent(e); +} + + +bool QPIConfigWidget::eventFilter(QObject * o, QEvent * e) { + if (e->type() == QEvent::MouseButtonPress) { + if (viewport() == qobject_cast(o)) { + pi = itemAt(((QMouseEvent * )e)->pos()); + if (((QMouseEvent * )e)->buttons() == Qt::RightButton) { + qApp->processEvents(); + itemClicked(pi, 1); + popupMenu.popup(((QMouseEvent * )e)->globalPos()); + } + } + } + return QTreeWidget::eventFilter(o, e); +} + + +void QPIConfigWidget::itemClicked(QTreeWidgetItem * item, int column) { + if (item != 0) { + if ((column == 0 && !read_only_name) || (column == 3 && !read_only_comment)) item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + else item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + bool node = true, ro = read_only_name || read_only_type || read_only_value; + if (item != 0) + if (itemTWidget(item) != 0) + if (itemTWidget(item)->isEnabled()) + node = false; + actionAddItem.setVisible(node && !ro); + actionAddNode.setVisible(node && !ro); + actionRemove.setVisible(!ro && !selectedItems().isEmpty()); +} + + +void QPIConfigWidget::itemChanged(QTreeWidgetItem * item, int column) { + if (item != c_pi) { + c_pi = item; + if (item != 0) { + c_name = item->text(0); + c_comment = item->text(3); + } + return; + } + if (item == 0) return; + if (c_name == item->text(0) && c_comment == item->text(3)) return; + //qDebug() << "change" << item->text(0); + QPIConfig::Entry * e = itemEntry(item); + if (e == 0) return; + if (column == 0) { + buildFullNames(item); + e->setName(item->text(column)); + conf->buildFullNames(e->parent()); + //qDebug() << itemCWidget(item)->full_name; + } + if (column == 3) e->setComment(item->text(column)); + c_name = item->text(0); + c_comment = item->text(3); + emit changed(); +} + + +void QPIConfigWidget::typeChange(int t, UComboBox * c) { + ConfigValueWidget * cw = (ConfigValueWidget * )c->property("qpic_widget").toLongLong(); + cw->setType(types.key(s_types[t])); + conf->getValue(cw->full_name).setType(types.key(s_types[t])); + emit changed(); +} + + +void QPIConfigWidget::valueChange(ConfigValueWidget * w, QString v) { + conf->getValue(w->full_name).setValue(v); + emit changed(); +} + + +void QPIConfigWidget::on_actionAddItem_triggered() { + if (conf == 0 || !active) return; + QString fp; + if (pi == 0) pi = invisibleRootItem(); + else fp = itemCWidget(pi)->full_name + conf->delim; + new_dialog.reset(); + if (new_dialog.exec() == QDialog::Rejected) return; + QPIConfig::Entry * e; + if (pi->childCount() == 0) { + //qDebug() << "pi empty, remove " << itemCWidget(pi)->full_name; + conf->removeEntry(itemCWidget(pi)->full_name, false); + } + //qDebug() << "add " << fp + new_dialog.name(); + e = &(conf->addEntry(fp + new_dialog.name(), new_dialog.value().isEmpty() ? "0" : new_dialog.value(), new_dialog.type(), false)); + expandItem(pi); + pi = addEntry(pi, e); + pi->setText(0, new_dialog.name()); + pi->setText(3, new_dialog.comment()); + int ind = s_types.indexOf(types[new_dialog.type()]); + if (ind < 0) w_types.back()->setCurrentIndex(0); + else w_types.back()->setCurrentIndex(ind); + emit changed(); +} + + +void QPIConfigWidget::on_actionAddNode_triggered() { + if (conf == 0 || !active) return; + QString fp; + if (pi == 0) pi = invisibleRootItem(); + else fp = itemCWidget(pi)->full_name + conf->delim; + new_dialog.reset(true); + if (new_dialog.exec() == QDialog::Rejected) return; + QPIConfig::Entry e; + //e = &(conf->addEntry(fp + new_dialog.name(), "", "", false)); + e._full_name = fp + new_dialog.name(); + expandItem(pi); + pi = addEntry(pi, &e, true); + pi->setText(0, new_dialog.name()); + pi->setText(3, new_dialog.comment()); + setItemWidget(pi, 2, 0); + emit changed(); +} + + +void QPIConfigWidget::on_actionRemove_triggered() { + //hide(); + if (conf == 0 || !active) return; + QList si = selectedItems(); + conf->buildFullNames(&(conf->root)); + QPIConfig::Entry * e; + foreach (QTreeWidgetItem * i, si) { + e = itemEntry(i); + if (e == 0) continue; + //qDebug() << "remove " + e->_full_name; + conf->removeEntry(e->_full_name, false); + deleteEntry(i); + } + emit changed(); + //show(); +} + + +void QPIConfigWidget::clear() { + if (!active) return; + bool hidden = isHidden(); + hide(); + QTreeWidget::clear(); + foreach (ConfigValueWidget * i, w_values) + delete i; + foreach (QComboBox * i, w_types) + delete i; + w_values.clear(); + w_types.clear(); + if (!hidden) show(); +} + + +void QPIConfigWidget::buildTree() { + if (!active) return; + if (conf == 0) return; + bool hidden = isHidden(); + hide(); + clear(); + conf->buildFullNames(&(conf->root)); + buildEntry(invisibleRootItem(), &conf->rootEntry()); + if (!hidden) show(); +} + + +void QPIConfigWidget::setReadOnlyValue(bool yes) { + read_only_value = yes; + foreach (ConfigValueWidget * i, w_values) + i->setEnabled(!yes); +} + + +void QPIConfigWidget::setReadOnlyType(bool yes) { + read_only_type = yes; + foreach (QComboBox * i, w_types) { + i->setEnabled(!yes); + i->setFrame(!yes); + } +} + + +void QPIConfigWidget::buildEntry(QTreeWidgetItem * i, QPIConfig::Entry * e) { + foreach (QPIConfig::Entry * j, e->children()) + buildEntry(addEntry(i, j, !j->isLeaf()), j); +} + + +void QPIConfigWidget::buildFullNames(QTreeWidgetItem * i) { + ConfigValueWidget * cw, * pw; + cw = itemCWidget(i); + if (i->parent() != 0) { + pw = itemCWidget(i->parent()); + cw->full_name = pw->full_name + conf->delim + i->text(0); + } else cw->full_name = i->text(0); + for (int j = 0; j < i->childCount(); ++j) + buildFullNames(i->child(j)); +} + + +QPIConfig::Entry * QPIConfigWidget::itemEntry(QTreeWidgetItem * i) { + ConfigValueWidget * cfw = itemCWidget(i); + if (cfw == 0) return 0; + return &(conf->getValue(cfw->full_name)); +} + + +QTreeWidgetItem * QPIConfigWidget::addEntry(QTreeWidgetItem * i, QPIConfig::Entry * e, bool node) { + if (conf == 0) return 0; + ti = new QTreeWidgetItem(); + ti->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ti->setSizeHint(0, QSize(26, 26)); + ti->setText(0, e->name()); + ti->setText(3, e->comment()); + w_values.push_back(new ConfigValueWidget); + w_values.back()->setEntry(e); + w_values.back()->setEnabled(!read_only_value); + if (!node) { + w_types.push_back(new UComboBox()); + w_types.back()->addItems(s_types); + w_types.back()->setCurrentIndex(s_types.indexOf(types[e->type().leftJustified(1).left(1)])); + w_types.back()->setProperty("qpic_widget", QVariant((qlonglong)w_values.back())); + w_types.back()->setEnabled(!read_only_type); + w_types.back()->setFrame(!read_only_type); + connect(w_types.back(), SIGNAL(currentIndexChanged(int, UComboBox * )), this, SLOT(typeChange(int,UComboBox * ))); + } + connect(w_values.back(), SIGNAL(changed(ConfigValueWidget * , QString)), this, SLOT(valueChange(ConfigValueWidget * , QString))); + i->addChild(ti); + setItemWidget(ti, 1, w_values.back()); + if (!node) { + setItemWidget(ti, 2, w_types.back()); + if (itemTWidget(i) != 0) { //itemTWidget(i)->setEnabled(false); + w_types.remove(w_types.indexOf(itemTWidget(i))); + setItemWidget(i, 2, 0); + } + } + return ti; +} + + +void QPIConfigWidget::deleteEntry(QTreeWidgetItem * i) { + ConfigValueWidget * vw; + UComboBox * cb; + int cc = i->childCount(); + for (int j = 0; j < cc; ++j) + deleteEntry(i->child(0)); + vw = qobject_cast(itemWidget(i, 1)); + cb = qobject_cast(itemWidget(i, 2)); + if (vw != 0) { + w_values.remove(w_values.indexOf(vw)); + delete vw; + } + if (cb != 0) { + w_types.remove(w_types.indexOf(cb)); + delete cb; + } + delete i; +} + + +bool QPIConfigWidget::filter(const QString & f, QTreeWidgetItem * i) { + if (i->childCount() == 0) return filterItem(f, i); + bool found = false; + for (int j = 0; j < i->childCount(); ++j) + if (filter(f, i->child(j))) found = true; + i->setHidden(!found); + return found; +} + + +bool QPIConfigWidget::filterItem(const QString & f, QTreeWidgetItem * i) { + if (f.isEmpty()) { + i->setHidden(false); + return true; + } + bool ret = (!isColumnHidden(0) && i->text(0).indexOf(f, 0, Qt::CaseInsensitive) >= 0) || + (!isColumnHidden(1) && itemCWidget(i)->value.indexOf(f, 0, Qt::CaseInsensitive) >= 0) || + (!isColumnHidden(3) && i->text(3).indexOf(f, 0, Qt::CaseInsensitive) >= 0); + if (itemTWidget(i) != 0) + ret = ret || (!isColumnHidden(2) && itemTWidget(i)->currentText().indexOf(f, 0, Qt::CaseInsensitive) >= 0); + i->setHidden(!ret); + return ret; +} + + +void QPIConfigWidget::translate() { + QStringList l; + l << tr("Name") << tr("Value") << tr("Type") << tr("Comment"); + if (active) setHeaderLabels(l); + types.clear(); + s_types.clear(); + addTrEntry("s", tr("string")); + addTrEntry("l", tr("string list")); + addTrEntry("n", tr("integer")); + addTrEntry("f", tr("float")); + addTrEntry("b", tr("boolean")); + addTrEntry("c", tr("color")); + addTrEntry("r", tr("rectangle")); + addTrEntry("a", tr("area")); + addTrEntry("p", tr("point")); + addTrEntry("v", tr("vector")); + addTrEntry("i", tr("ip")); + actionAddItem.setText(tr("Add item ...")); + actionAddNode.setText(tr("Add node ...")); + actionToItem.setText(tr("Convert to item")); + actionToNode.setText(tr("Convert to node")); + actionRemove.setText(tr("Remove")); + actionExpandAll.setText(tr("Expand all")); + actionCollapseAll.setText(tr("Collapse all")); + if (!active) return; + for (int i = 0; i < 4; ++i) + setColumnHidden(i, c_hidden[i]); +} + + +QString QPIConfigWidget::writeToString() { + if (conf == 0) return QString(); + conf->buildFullNames(&(conf->root)); + return conf->writeAllToString(); +} + + +void QPIConfigWidget::readFromString(QString str) { + if (conf == 0) return; + conf->readAllFromString(str); + buildTree(); +} diff --git a/qad/widgets/qpiconfigwidget.h b/qad/widgets/qpiconfigwidget.h new file mode 100644 index 0000000..130e13a --- /dev/null +++ b/qad/widgets/qpiconfigwidget.h @@ -0,0 +1,111 @@ +#ifndef QPICONFIGWIDGET_H +#define QPICONFIGWIDGET_H + +#include "qpiconfig.h" +#include "qpiconfignewdialog.h" +#include "qpiconfigvaluewidget.h" +#include +#include +#include +#include +#include +#include + + +class UComboBox: public QComboBox +{ + Q_OBJECT +public: + UComboBox(QWidget * parent = 0): QComboBox(parent) {connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(indexChange(int)));} +private slots: + void indexChange(int i) {emit currentIndexChanged(i, this);} +signals: + void currentIndexChanged(int, UComboBox * ); +}; + + +class QPIConfigWidget: public QTreeWidget +{ + Q_OBJECT + Q_PROPERTY(bool readOnlyName READ readOnlyName WRITE setReadOnlyName) + Q_PROPERTY(bool readOnlyValue READ readOnlyValue WRITE setReadOnlyValue) + Q_PROPERTY(bool readOnlyType READ readOnlyType WRITE setReadOnlyType) + Q_PROPERTY(bool readOnlyComment READ readOnlyComment WRITE setReadOnlyComment) + Q_PROPERTY(bool columnNameVisible READ columnNameVisible WRITE setColumnNameVisible) + Q_PROPERTY(bool columnValueVisible READ columnValueVisible WRITE setColumnValueVisible) + Q_PROPERTY(bool columnTypeVisible READ columnTypeVisible WRITE setColumnTypeVisible) + Q_PROPERTY(bool columnCommentVisible READ columnCommentVisible WRITE setColumnCommentVisible) +public: + QPIConfigWidget(QWidget * parent = 0, QPIConfig * c = 0, bool on = true); + ~QPIConfigWidget() {clear();} + + void setQPIConfig(QPIConfig * c) {conf = c; buildTree();} + bool readOnlyName() {return read_only_name;} + bool readOnlyValue() {return read_only_value;} + bool readOnlyType() {return read_only_type;} + bool readOnlyComment() {return read_only_comment;} + bool columnNameVisible() {return !c_hidden[0];} + bool columnValueVisible() {return !c_hidden[1];} + bool columnTypeVisible() {return !c_hidden[2];} + bool columnCommentVisible() {return !c_hidden[3];} + QString writeToString(); + void readFromString(QString str); + +private: + void changeEvent(QEvent * e); + bool eventFilter(QObject * o, QEvent * e); + void buildEntry(QTreeWidgetItem * i, QPIConfig::Entry * e); + void buildFullNames(QTreeWidgetItem * i); + QPIConfig::Entry * itemEntry(QTreeWidgetItem * i); + ConfigValueWidget * itemCWidget(QTreeWidgetItem * i) {return qobject_cast(itemWidget(i, 1));} + UComboBox * itemTWidget(QTreeWidgetItem * i) {return qobject_cast(itemWidget(i, 2));} + QTreeWidgetItem * addEntry(QTreeWidgetItem * i, QPIConfig::Entry * e, bool node = false); + void deleteEntry(QTreeWidgetItem * i); + bool filter(const QString & f, QTreeWidgetItem * i); + bool filterItem(const QString & f, QTreeWidgetItem * i); + void translate(); + void addTrEntry(const QString & s, const QString & f) {types.insert(s, f); s_types << f;} + + QPIConfig * conf; + QPIConfigNewDialog new_dialog; + QAction actionAddItem, actionAddNode, actionToItem, actionToNode, actionRemove, actionExpandAll, actionCollapseAll; + QMenu popupMenu; + QString c_name, c_comment; + QTreeWidgetItem * pi, * ti, * c_pi; + QHash types; + QStringList s_types; + QVector w_values; + QVector w_types; + QVector c_hidden; + bool active, read_only_name, read_only_value, read_only_type, read_only_comment; + +public slots: + void parse() {if (conf == 0) clear(); else conf->readAll();} + void write() {if (conf == 0) return; conf->buildFullNames(&(conf->root)); conf->writeAll();} + void clear(); + void buildTree(); + void filter(const QString & f) {if (!active) return; filter(f, invisibleRootItem());} + void setReadOnlyName(bool yes) {read_only_name = yes;} + void setReadOnlyValue(bool yes); + void setReadOnlyType(bool yes); + void setReadOnlyComment(bool yes) {read_only_comment = yes;} + void setColumnNameVisible(bool yes) {setColumnHidden(0, !yes); c_hidden[0] = !yes;} + void setColumnValueVisible(bool yes) {setColumnHidden(1, !yes); c_hidden[1] = !yes;} + void setColumnTypeVisible(bool yes) {setColumnHidden(2, !yes); c_hidden[2] = !yes;} + void setColumnCommentVisible(bool yes) {setColumnHidden(3, !yes); c_hidden[3] = !yes;} + +private slots: + void itemClicked(QTreeWidgetItem * item, int column); + void itemChanged(QTreeWidgetItem * item, int column); + void typeChange(int t, UComboBox * c); + void valueChange(ConfigValueWidget * w, QString v); + void on_actionAddItem_triggered(); + void on_actionAddNode_triggered(); + void on_actionRemove_triggered(); + +signals: + void changed(); + +}; + +#endif // QPICONFIGWIDGET_H diff --git a/qad/widgets/qpiconsole.cpp b/qad/widgets/qpiconsole.cpp new file mode 100644 index 0000000..1b0d555 --- /dev/null +++ b/qad/widgets/qpiconsole.cpp @@ -0,0 +1,268 @@ +#include "qpiconsole.h" + + +QPIConsole::QPIConsole(QWidget * parent): QTabWidget(parent) { + connect(this, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); + cur_tab = timer = -1; + def_align = Qt::AlignCenter; +} + + +void QPIConsole::timerEvent(QTimerEvent * ) { + for (int i = 0; i < columns().size(); ++i) { + Column & ccol(tabs[cur_tab].columns[i]); + QVector & cvars(ccol.variables); + if (ccol.alignment.testFlag(Qt::AlignLeft)) { + ccol.layout->setLabelAlignment(Qt::AlignLeft); + } else { + ccol.layout->setLabelAlignment(Qt::AlignRight); + } + for (int j = 0; j < cvars.size(); ++j) { + Variable & tv(cvars[j]); + tv.label->setText(tv.name); + if (tv.type >= 0) { + if (ccol.alignment.testFlag(Qt::AlignLeft)) { + tv.label->setAlignment(Qt::AlignLeft); + if (tv.widget != 0) tv.widget->setAlignment(Qt::AlignLeft); + } else { + if (ccol.alignment.testFlag(Qt::AlignRight)) { + tv.label->setAlignment(Qt::AlignRight); + if (tv.widget != 0) tv.widget->setAlignment(Qt::AlignRight); + } else { + tv.label->setAlignment(Qt::AlignRight); + if (tv.widget != 0) tv.widget->setAlignment(Qt::AlignLeft); + } + } + } + if (tv.widget == 0) continue; + if (tv.type <= 0 && tv.ptr == 0) continue; + if (tv.ptr != 0) { + switch (tv.type) { + case 0: tv.widget->setText((tv.ptr != 0 ? *(const QString*)tv.ptr : QString())); break; + case 1: tv.widget->setText((tv.ptr != 0 ? *(const bool*)tv.ptr : false) ? "true" : "false"); break; + case 2: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const int*)tv.ptr : 0, tv.format)); break; + case 3: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const long*)tv.ptr : 0l, tv.format)); break; + case 4: tv.widget->setText(QString(tv.ptr != 0 ? *(const char*)tv.ptr : char(0))); break; + case 5: tv.widget->setText(numFloatString(tv.ptr != 0 ? *(const float*)tv.ptr : 0.f, tv.format)); break; + case 6: tv.widget->setText(numFloatString(tv.ptr != 0 ? *(const double*)tv.ptr : 0., tv.format)); break; + case 7: tv.widget->setText(numFloatString(tv.ptr != 0 ? *(const short*)tv.ptr : short(0), tv.format)); break; + case 8: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const uint*)tv.ptr : 0u, tv.format)); break; + case 9: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const ulong*)tv.ptr : 0ul, tv.format)); break; + case 10: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const ushort*)tv.ptr : ushort(0), tv.format)); break; + case 11: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const uchar*)tv.ptr : uchar(0), tv.format)); break; + case 12: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const llong*)tv.ptr : 0l, tv.format)); break; + case 13: tv.widget->setText(numIntString(tv.ptr != 0 ? *(const ullong*)tv.ptr: 0ull, tv.format)); break; + case 14: tv.widget->setText(numIntString(bitsValue(tv.ptr, tv.bitFrom, tv.bitCount), tv.format, tv.bitCount/8)); break; + default: break; + } + } + } + } +} + + +#define ADD_VAR_BODY tv.name = name; if (!tv.name.isEmpty()) tv.name += ":"; tv.bitFrom = tv.bitCount = 0; tv.format = format; checkColumn(col); +#define ADD_VAR_SBODY tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; checkColumn(col); + +#define ADD_VAR_QT QLabel * lbl = new QLabel(name); QLabel * w = new QLabel(); \ + lbl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); \ + w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); \ + column(col).variables.back().label = lbl; column(col).variables.back().widget = w; \ + lbl->setAlignment(column(col).alignment); \ + applyFormat(lbl, format); applyFormat(w, format); \ + column(col).layout->addRow(lbl, w); + +void QPIConsole::addString(const QString & name, int col, Formats format) { + ADD_VAR_SBODY tv.type = -1; tv.ptr = 0; column(col).push_back(tv); + QLabel * lbl = new QLabel(name); + lbl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + column(col).variables.back().label = lbl; column(col).variables.back().widget = 0; + lbl->setAlignment(column(col).alignment); + applyFormat(lbl, format); + column(col).layout->addRow(lbl); +} +void QPIConsole::addVariable(const QString & name, const QString* ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 0; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const bool * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 1; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const int * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 2; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const long * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 3; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const char * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 4; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const float * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 5; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const double * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 6; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const short * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 7; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const uint * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 8; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const ulong * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 9; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const ushort * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 10; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const uchar * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 11; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const llong * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 12; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addVariable(const QString & name, const ullong * ptr, int col, Formats format) { + ADD_VAR_BODY tv.type = 13; tv.ptr = ptr; column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addBitVariable(const QString & name, const void * ptr, int fromBit, int bitCount, int col, Formats format) { + tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format; + checkColumn(col); column(col).push_back(tv); ADD_VAR_QT} +void QPIConsole::addEmptyLine(int col, uint count) { + tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal; + for (uint i = 0; i < count; ++i) { + checkColumn(col); + column(col).push_back(tv); + QLabel * lbl = new QLabel(); + lbl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + column(col).variables.back().label = lbl; column(col).variables.back().widget = 0; + lbl->setAlignment(column(col).alignment); + applyFormat(lbl, tv.format); + column(col).layout->addRow(lbl); + } +} + + +int QPIConsole::addTab(const QString & name, char bind_key) { + QWidget * w = new QWidget(); + QVBoxLayout * lay = new QVBoxLayout(); + QHBoxLayout * clay = new QHBoxLayout(); + QLabel * lbl = new QLabel(); + lay->setContentsMargins(2, 2, 2, 2); + clay->setContentsMargins(0, 0, 0, 0); + lay->addLayout(clay); + lay->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Preferred, QSizePolicy::Expanding)); + lay->addWidget(lbl); + w->setLayout(lay); + QTabWidget::addTab(w, name); + tabs.push_back(Tab(name, bind_key)); + tabs.back().layout = clay; + tabs.back().widget = lbl; + cur_tab = tabs.size() - 1; + setCurrentIndex(cur_tab); + return tabs.size(); +} + + +void QPIConsole::checkColumn(int col) { + while (columns().size() < col) { + QFormLayout * lay = new QFormLayout(); + lay->setContentsMargins(2, 2, 2, 2); + lay->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + columns().push_back(Column(def_align)); + columns().back().layout = lay; + tabs[cur_tab].layout->addLayout(lay); + } +} + + +int QPIConsole::bitsValue(const void * src, int offset, int count) const { + int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8; + char cbyte = reinterpret_cast(src)[stbyte]; + for (int i = 0; i < count; i++) { + ret |= ((cbyte >> cbit & 1) << i); + cbit++; + if (cbit == 8) { + cbit = 0; + stbyte++; + cbyte = reinterpret_cast(src)[stbyte]; + } + } + return ret; +} + + +const QString & QPIConsole::toBin(const void * d, int s) { + binstr.clear(); + uchar cc, b; + for (int i = 0; i < s; ++i) { + cc = ((const uchar *)d)[i]; + b = 1; + for (int j = 0; j < 8; ++j) { + binstr.prepend(cc & b ? "1" : "0"); + b <<= 1; + } + if (i < s - 1) binstr.prepend(" "); + } + return binstr; +} + + +void QPIConsole::applyFormat(QLabel * l, QPIConsole::Formats f) { + QColor fcol = Qt::black, bcol = QColor(0xFFFFFF); + QFont fnt = font(); + + if (f.testFlag(QPIConsole::Bold)) fnt.setBold(true); + if (f.testFlag(QPIConsole::Italic)) fnt.setItalic(true); + if (f.testFlag(QPIConsole::Underline)) fnt.setUnderline(true); + + if (f.testFlag(QPIConsole::Black)) fcol = Qt::black; + if (f.testFlag(QPIConsole::Red)) fcol = Qt::red; + if (f.testFlag(QPIConsole::Green)) fcol = Qt::green; + if (f.testFlag(QPIConsole::Yellow)) fcol = Qt::yellow; + if (f.testFlag(QPIConsole::Blue)) fcol = Qt::blue; + if (f.testFlag(QPIConsole::Magenta)) fcol = Qt::magenta; + if (f.testFlag(QPIConsole::Cyan)) fcol = Qt::cyan; + if (f.testFlag(QPIConsole::White)) fcol = Qt::white; + if (f.testFlag(QPIConsole::Lighter)) fcol = fcol.lighter(150); + if (f.testFlag(QPIConsole::Darker)) fcol = fcol.darker(150); + + if (f.testFlag(QPIConsole::BackBlack)) bcol = Qt::black; + if (f.testFlag(QPIConsole::BackRed)) bcol = Qt::red; + if (f.testFlag(QPIConsole::BackGreen)) bcol = Qt::green; + if (f.testFlag(QPIConsole::BackYellow)) bcol = Qt::yellow; + if (f.testFlag(QPIConsole::BackBlue)) bcol = Qt::blue; + if (f.testFlag(QPIConsole::BackMagenta)) bcol = Qt::magenta; + if (f.testFlag(QPIConsole::BackCyan)) bcol = Qt::cyan; + if (f.testFlag(QPIConsole::BackWhite)) bcol = Qt::white; + if (f.testFlag(QPIConsole::BackLighter)) bcol = bcol.lighter(150); + //if (f.testFlag(QPIConsole::BackDarker)) bcol = bcol.darker(150); + + if (f.testFlag(QPIConsole::Inverse)) { + QColor tc = fcol; + fcol = bcol; + bcol = tc; + } + + l->setFont(fnt); + QPalette pal = palette(); + pal.setColor(QPalette::WindowText, fcol); + pal.setColor(QPalette::Window, bcol); + l->setPalette(pal); + l->setAutoFillBackground(bcol != QColor(0xFFFFFF)); +} + + +bool QPIConsole::removeTab(uint index) { + if (int(index) >= tabs.size()) return false; + delete QTabWidget::widget(index); + tabs.remove(index); + return true; +} + + +bool QPIConsole::setTab(uint index) { + if (int(index) >= tabs.size()) return false; + setCurrentIndex(index); + return true; +} + + +bool QPIConsole::renameTab(uint index, const QString & new_name) { + if (int(index) >= tabs.size()) return false; + if (tabs[index].name == new_name) return true; + setTabText(index, new_name); + tabs[index].name = new_name; + return true; +} + + +void QPIConsole::setTabEnabled(int index, bool on) { + if (int(index) >= tabs.size()) return; + if (isTabEnabled(index) == on) return; + QTabWidget::setTabEnabled(index, on); +} diff --git a/qad/widgets/qpiconsole.h b/qad/widgets/qpiconsole.h new file mode 100644 index 0000000..5e72d33 --- /dev/null +++ b/qad/widgets/qpiconsole.h @@ -0,0 +1,187 @@ +#ifndef QPICONSOLE_H +#define QPICONSOLE_H + +#include +#include +#include +#include +#include +#include + +typedef long long llong; +typedef unsigned char uchar; +typedef unsigned short int ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned long long ullong; +typedef long double ldouble; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QPIConsole: public QTabWidget { + Q_OBJECT +public: + QPIConsole(QWidget * parent = 0); + + enum Format {Normal = 0x01, + Bold = 0x02, + Italic = 0x08, + Underline = 0x10, + Inverse = 0x40, + Black = 0x100, + Red = 0x200, + Green = 0x400, + Yellow = 0x800, + Blue = 0x1000, + Magenta = 0x2000, + Cyan = 0x4000, + White = 0x8000, + BackBlack = 0x10000, + BackRed = 0x20000, + BackGreen = 0x40000, + BackYellow = 0x80000, + BackBlue = 0x100000, + BackMagenta = 0x200000, + BackCyan = 0x400000, + BackWhite = 0x800000, + Dec = 0x1000000, + Hex = 0x2000000, + Oct = 0x4000000, + Bin = 0x8000000, + Scientific = 0x10000000, + Lighter = 0x20000000, + Darker = 0x40000000, + BackLighter = 0x80000000 + }; + + Q_DECLARE_FLAGS(Formats, Format) + Q_FLAGS(Formats) + Q_ENUMS(Format) + + Q_PROPERTY(Qt::Alignment defaultAlignment READ defaultAlignment WRITE setDefaultAlignment) + + void addString(const QString & name, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const QString * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const char * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const bool * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const short * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const int * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const long * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const llong * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const uchar * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const ushort * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const uint * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const ulong * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const ullong * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const float * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addVariable(const QString & name, const double * ptr, int column = 1, Formats format = QPIConsole::Normal); + void addBitVariable(const QString & name, const void * ptr, int fromBit, int bitCount, int column = 1, Formats format = QPIConsole::Normal); + void addEmptyLine(int column = 1, uint count = 1); + + uint tabsCount() const {return tabs.size();} + QString currentTab() const {return tabs[cur_tab].name;} + int addTab(const QString & name, char bind_key = 0); + bool removeTab(uint index); + bool removeTab(const QString & name) {return removeTab(tabIndex(name));} + bool renameTab(uint index, const QString & new_name); + bool renameTab(const QString & name, const QString & new_name) {return renameTab(tabIndex(name), new_name);} + void setTabEnabled(int index, bool on); + bool setTab(uint index); + bool setTab(const QString & name) {return setTab(tabIndex(name));} + //void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();} + + void addCustomStatus(const QString & str, Formats format = QPIConsole::Normal) {tabs[cur_tab].widget->setText(str); applyFormat(tabs[cur_tab].widget, format);} + void clearCustomStatus() {tabs[cur_tab].widget->clear();} + Qt::Alignment defaultAlignment() const {return def_align;} + void setDefaultAlignment(Qt::Alignment align) {def_align = align;} + void setColumnAlignment(int col, Qt::Alignment align) {if (col < 0 || col >= columns().size()) return; column(col).alignment = align;} + void setColumnAlignmentToAll(Qt::Alignment align) {for (int i = 0; i < tabs.size(); ++i) for (int j = 0; j < tabs[i].columns.size(); ++j) tabs[i].columns[j].alignment = align;/* fillLabels();*/} + + void clearVariables() {clearVariables(true);} + void clearVariables(bool clearScreen) {/*if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();}*/ columns().clear();} + +private: + void timerEvent(QTimerEvent * ); + QSize sizeHint() const {return QSize(100, 100);} + + void checkColumn(int col); + void applyFormat(QLabel * l, Formats f); + int bitsValue(const void * src, int offset, int count) const; + int tabIndex(const QString & n) const {for (int i = 0; i < tabs.size(); ++i) if (tabs[i].name == n) return i; return -1;} + const QString & toBin(const void * d, int s); + template + QString numIntString(T v, Formats f, int bits = 0) { + if (f.testFlag(QPIConsole::Hex)) return "0x" + QString::number(v, 16).toUpper(); + if (f.testFlag(QPIConsole::Dec)) return QString::number(v); + if (f.testFlag(QPIConsole::Oct)) return "0" + QString::number(v, 8); + if (f.testFlag(QPIConsole::Bin)) return toBin(&v, bits); + return QString::number(v); + } + template + QString numFloatString(T v, Formats f) { + if (f.testFlag(QPIConsole::Scientific)) return QString::number(v, 'E', 5); + return QString::number(v); + } + + struct Variable { + Variable() {label = widget = 0;} + QString name; + Formats format; + int type; + int bitFrom; + int bitCount; + const void * ptr; + QLabel * label; + QLabel * widget; + void operator =(const Variable & src) {name = src.name; format = src.format; type = src.type; + bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr;} + }; + + struct Column { + Column(Qt::Alignment align = Qt::AlignRight) {variables.reserve(16); alignment = align;} + QVector variables; + Qt::Alignment alignment; + QFormLayout * layout; + int size() const {return variables.size();} + Variable & operator [](int index) {return variables[index];} + const Variable & operator [](int index) const {return variables[index];} + void push_back(const Variable & v) {variables.push_back(v);} + void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;} + }; + + struct Tab { + Tab(QString n = "", char k = 0) {columns.reserve(16); name = n; key = k;} + QVector columns; + QString name; + char key; + QHBoxLayout * layout; + QLabel * widget; + }; + + QVector & columns() {return tabs[cur_tab].columns;} + Column & column(int index) {return tabs[cur_tab].columns[index - 1];} + + Qt::Alignment def_align; + QVector tabs; + QString binstr; + Variable tv; + int cur_tab, timer; + +private slots: + void tabChanged(int tab) {cur_tab = tab;} + +public slots: + void start(float freq = 40) {if (timer >= 0) killTimer(timer); timer = startTimer(freq > 0. ? 1000 / freq : 25);} + void stop() {if (timer >= 0) killTimer(timer); timer = -1;} + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QPIConsole::Formats) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPICONSOLE_H diff --git a/qad/widgets/qpointedit.cpp b/qad/widgets/qpointedit.cpp new file mode 100644 index 0000000..ebd0aae --- /dev/null +++ b/qad/widgets/qpointedit.cpp @@ -0,0 +1,34 @@ +#include "qpointedit.h" +#include "float.h" + + +QPointEdit::QPointEdit(QWidget * parent): QWidget(parent), lay(QBoxLayout::LeftToRight, this) { + s_x = new QDoubleSpinBox(this); + s_y = new QDoubleSpinBox(this); + s_x->setMinimum(-DBL_MAX); + s_x->setMaximum(DBL_MAX); + s_y->setMinimum(-DBL_MAX); + s_y->setMaximum(DBL_MAX); + s_x->setToolTip(tr("X")); + s_y->setToolTip(tr("Y")); + lbl = new QLabel(this); + lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + lbl->setText("x"); + lay.setContentsMargins(0, 0, 0, 0); + lay.setSpacing(1); + lay.addWidget(s_x); + lay.addWidget(lbl); + lay.addWidget(s_y); + connect(s_x, SIGNAL(valueChanged(double)), this, SLOT(changed())); + connect(s_y, SIGNAL(valueChanged(double)), this, SLOT(changed())); +} + + +void QPointEdit::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + s_x->setToolTip(tr("X")); + s_y->setToolTip(tr("Y")); + return; + } + QWidget::changeEvent(e); +} diff --git a/qad/widgets/qpointedit.h b/qad/widgets/qpointedit.h new file mode 100644 index 0000000..15119c7 --- /dev/null +++ b/qad/widgets/qpointedit.h @@ -0,0 +1,42 @@ +#ifndef QPOINTEDIT_H +#define QPOINTEDIT_H + +#include +#include +#include +#include + + +class QPointEdit: public QWidget +{ + Q_OBJECT + Q_PROPERTY(QPointF value READ value WRITE setValue) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + +public: + explicit QPointEdit(QWidget * parent = 0); + ~QPointEdit() {delete s_x; delete s_y; delete lbl;} + + QPointF value() const {return QPointF(s_x->value(), s_y->value());} + int decimals() const {return s_x->decimals();} + +public slots: + void setValue(QPointF v) {s_x->setValue(v.x()); s_y->setValue(v.y());} + void setDecimals(int d) {s_x->setDecimals(d); s_y->setDecimals(d);} + +private: + virtual void changeEvent(QEvent * e); + + QBoxLayout lay; + QDoubleSpinBox * s_x, * s_y; + QLabel * lbl; + +private slots: + void changed() {emit valueChanged(QPointF(s_x->value(), s_y->value()));} + +signals: + void valueChanged(QPointF); + +}; + +#endif // QPOINTEDIT_H diff --git a/qad/widgets/qrectedit.cpp b/qad/widgets/qrectedit.cpp new file mode 100644 index 0000000..e1387a4 --- /dev/null +++ b/qad/widgets/qrectedit.cpp @@ -0,0 +1,56 @@ +#include "qrectedit.h" +#include "float.h" + + +QRectEdit::QRectEdit(QWidget * parent): QWidget(parent), lay(QBoxLayout::LeftToRight, this) { + s_x = new QDoubleSpinBox(this); + s_y = new QDoubleSpinBox(this); + s_w = new QDoubleSpinBox(this); + s_h = new QDoubleSpinBox(this); + s_x->setMinimum(-DBL_MAX); + s_x->setMaximum(DBL_MAX); + s_y->setMinimum(-DBL_MAX); + s_y->setMaximum(DBL_MAX); + s_w->setMinimum(-DBL_MAX); + s_w->setMaximum(DBL_MAX); + s_h->setMinimum(-DBL_MAX); + s_h->setMaximum(DBL_MAX); + s_x->setToolTip(tr("X")); + s_y->setToolTip(tr("Y")); + s_w->setToolTip(tr("Height")); + s_h->setToolTip(tr("Width")); + lbl_0 = new QLabel(this); + lbl_0->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + lbl_0->setText("x"); + lbl_1 = new QLabel(this); + lbl_1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + lbl_1->setText(";"); + lbl_2 = new QLabel(this); + lbl_2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + lbl_2->setText("x"); + lay.setContentsMargins(0, 0, 0, 0); + lay.setSpacing(1); + lay.addWidget(s_x); + lay.addWidget(lbl_0); + lay.addWidget(s_y); + lay.addWidget(lbl_1); + lay.addWidget(s_w); + lay.addWidget(lbl_2); + lay.addWidget(s_h); + connect(s_x, SIGNAL(valueChanged(double)), this, SLOT(changed())); + connect(s_y, SIGNAL(valueChanged(double)), this, SLOT(changed())); + connect(s_w, SIGNAL(valueChanged(double)), this, SLOT(changed())); + connect(s_h, SIGNAL(valueChanged(double)), this, SLOT(changed())); +} + + +void QRectEdit::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + s_x->setToolTip(tr("X")); + s_y->setToolTip(tr("Y")); + s_w->setToolTip(tr("Height")); + s_h->setToolTip(tr("Width")); + return; + } + QWidget::changeEvent(e); +} diff --git a/qad/widgets/qrectedit.h b/qad/widgets/qrectedit.h new file mode 100644 index 0000000..7e4064d --- /dev/null +++ b/qad/widgets/qrectedit.h @@ -0,0 +1,51 @@ +#ifndef QRECTEDIT_H +#define QRECTEDIT_H + +#include +#include +#include +#include + + +class QRectEdit: public QWidget +{ + Q_OBJECT + Q_PROPERTY(QRectF value READ value WRITE setValue) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_PROPERTY(double maximum READ maximum WRITE setMaximum) + Q_PROPERTY(double minimum READ minimum WRITE setMinimum) + Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep) + +public: + explicit QRectEdit(QWidget * parent = 0); + ~QRectEdit() {delete s_x; delete s_y; delete s_w; delete s_h; delete lbl_0; delete lbl_1; delete lbl_2;} + + QRectF value() const {return QRectF(s_x->value(), s_y->value(), s_w->value(), s_h->value());} + int decimals() const {return s_x->decimals();} + double maximum() const {return s_x->maximum();} + double minimum() const {return s_x->minimum();} + double singleStep() const {return s_x->singleStep();} + +public slots: + void setValue(QRectF v) {s_x->setValue(v.x()); s_y->setValue(v.y()); s_w->setValue(v.width()); s_h->setValue(v.height());} + void setDecimals(int d) {s_x->setDecimals(d); s_y->setDecimals(d); s_w->setDecimals(d); s_h->setDecimals(d);} + void setMaximum(double m) {s_x->setMaximum(m); s_y->setMaximum(m); s_w->setMaximum(m); s_h->setMaximum(m);} + void setMinimum(double m) {s_x->setMinimum(m); s_y->setMinimum(m); s_w->setMinimum(m); s_h->setMinimum(m);} + void setSingleStep(double m) {s_x->setSingleStep(m); s_y->setSingleStep(m); s_w->setSingleStep(m); s_h->setSingleStep(m);} + +private: + virtual void changeEvent(QEvent * e); + + QBoxLayout lay; + QDoubleSpinBox * s_x, * s_y, * s_w, * s_h; + QLabel * lbl_0, * lbl_1, * lbl_2; + +private slots: + void changed() {emit valueChanged(QRectF(s_x->value(), s_y->value(), s_w->value(), s_h->value()));} + +signals: + void valueChanged(QRectF); + +}; + +#endif // QRECTEDIT_H diff --git a/qad/widgets/qvariantedit.cpp b/qad/widgets/qvariantedit.cpp new file mode 100644 index 0000000..9aff068 --- /dev/null +++ b/qad/widgets/qvariantedit.cpp @@ -0,0 +1,449 @@ +#include "qvariantedit.h" +#include +#include + + +StringListEdit::~StringListEdit() { + delete combo; + delete butt_add; + delete butt_del; + delete butt_clear; +} + + +QStringList StringListEdit::value() const { + QStringList l; + for (int i = 0; i < combo->count(); ++i) l << combo->itemText(i); + return l; +} + + +void StringListEdit::setValue(const QStringList & v) { + combo->clear(); + if (!v.isEmpty()) { + combo->addItems(v); + combo->setCurrentIndex(0); + } +} + + +void StringListEdit::addItem() { + combo->addItem(combo->currentText()); + emit valueChanged(); +} + + +void StringListEdit::delItem() { + if (combo->currentIndex() < 0) return; + combo->removeItem(combo->currentIndex()); + emit valueChanged(); +} + + +void StringListEdit::clear() { + if (combo->count() == 0) return; + combo->clear(); + emit valueChanged(); +} + + +StringListEdit::StringListEdit(QWidget * parent): QWidget(parent), lay(QBoxLayout::LeftToRight, this) { + combo = new EComboBox(this); + combo->setEditable(true); + combo->setLineEdit(new CLineEdit); + combo->setInsertPolicy(QComboBox::NoInsert); + butt_add = new QPushButton(this); + butt_del = new QPushButton(this); + butt_clear = new QPushButton(this); + /*butt_add->setIconSize(QSize(16, 16)); + butt_del->setIconSize(QSize(16, 16)); + butt_clear->setIconSize(QSize(16, 16));*/ + butt_add->setMaximumWidth(combo->height()); + butt_del->setMaximumWidth(combo->height()); + butt_clear->setMaximumWidth(combo->height()); + butt_add->setIcon(QIcon(":/icons/list-add.png")); + butt_del->setIcon(QIcon(":/icons/edit-delete.png")); + butt_clear->setIcon(QIcon(":/icons/edit-clear.png")); + butt_add->setToolTip(tr("Add")); + butt_del->setToolTip(tr("Remove")); + butt_clear->setToolTip(tr("Clear")); + lay.setContentsMargins(0, 0, 0, 0); + lay.setSpacing(2); + lay.addWidget(combo); + lay.addWidget(butt_add); + lay.addWidget(butt_del); + lay.addWidget(butt_clear); + connect(combo->lineEdit(), SIGNAL(returnPressed()), this, SLOT(editItem())); + connect(butt_add, SIGNAL(clicked(bool)), this, SLOT(addItem())); + connect(butt_del, SIGNAL(clicked(bool)), this, SLOT(delItem())); + connect(butt_clear, SIGNAL(clicked(bool)), this, SLOT(clear())); +} + + +void StringListEdit::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + butt_add->setToolTip(tr("Add")); + butt_del->setToolTip(tr("Remove")); + butt_clear->setToolTip(tr("Clear")); + return; + } + QWidget::changeEvent(e); +} + + +void StringListEdit::editItem() { + int ci = combo->currentIndex(); + if (ci < 0) return; + combo->setItemText(ci, combo->currentText()); +} + + + + +PathEdit::PathEdit(QWidget * parent): QWidget(parent), lay(QBoxLayout::LeftToRight, this) { + is_dir = is_abs = false; + filter = tr("All files(*)"); + line = new CLineEdit(this); + butt_select = new QPushButton(this); + //butt_select->setIconSize(QSize(16, 16)); + butt_select->setMaximumWidth(line->height()); + butt_select->setIcon(QIcon(":/icons/document-open.png")); + butt_select->setToolTip(tr("Choose") + " ..."); + lay.setContentsMargins(0, 0, 0, 0); + lay.setSpacing(2); + lay.addWidget(line); + lay.addWidget(butt_select); + connect(line, SIGNAL(textChanged(QString)), this, SIGNAL(valueChanged())); + connect(butt_select, SIGNAL(clicked(bool)), this, SLOT(select())); +} + + +void PathEdit::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + butt_select->setToolTip(tr("Choose") + " ..."); + return; + } + QWidget::changeEvent(e); +} + + +void PathEdit::select() { + QString ret; + if (is_dir) ret = QFileDialog::getExistingDirectory(this, tr("Select directory"), value()); + else ret = QFileDialog::getOpenFileName(this, tr("Select file"), value(), filter); + if (ret.isEmpty()) return; + if (!is_abs) + ret = QDir::current().relativeFilePath(ret); + line->setText(ret); + emit valueChanged(); +} + + + + +QVariantEdit::QVariantEdit(QWidget * parent): QWidget(parent) { + _empty = 0; + _line = 0; + _check = 0; + _color = 0; + _list = 0; + _date = 0; + _spin = 0; + _rect = 0; + _point = 0; + _path = 0; + _enum = 0; + _cur_edit = 0; + _recreate(QVariant()); +} + + +QVariantEdit::~QVariantEdit() { + _delete(); +} + + +void QVariantEdit::resizeEvent(QResizeEvent * e) { + _resize(); + QWidget::resizeEvent(e); +} + + +void QVariantEdit::_recreate(const QVariant & new_value) { + if (!new_value.isValid()) { + if (_cur_edit != _empty) _delete(); + if (_empty == 0) { + _empty = new QLabel(trUtf8("Invalid value"), this); + _empty->setAlignment(Qt::AlignCenter); + _cur_edit = _empty; + _resize(); + } + _value = new_value; + return; + } + if (_value.userType() == new_value.userType()) { + _value = new_value; + return; + } + _delete(); + switch (new_value.type()) { + case QVariant::Bool: + _check = new QCheckBox(this); + _check->setAutoFillBackground(true); + _cur_edit = _check; + connect(_check, SIGNAL(toggled(bool)), this, SLOT(_changed())); + break; + case QVariant::Int: + _spin = new QDoubleSpinBox(this); + _spin->setDecimals(0); + _spin->setRange(-0x7FFFFFFF, 0x7FFFFFFF); + _cur_edit = _spin; + connect(_spin, SIGNAL(valueChanged(double)), this, SLOT(_changed())); + break; + case QVariant::UInt: + _spin = new QDoubleSpinBox(this); + _spin->setDecimals(0); + _spin->setRange(0, 0xFFFFFFFF); + _cur_edit = _spin; + connect(_spin, SIGNAL(valueChanged(double)), this, SLOT(_changed())); + break; + case QVariant::LongLong: + _spin = new QDoubleSpinBox(this); + _spin->setDecimals(0); + _spin->setRange(-0x7FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL); + _cur_edit = _spin; + connect(_spin, SIGNAL(valueChanged(double)), this, SLOT(_changed())); + break; + case QVariant::ULongLong: + _spin = new QDoubleSpinBox(this); + _spin->setDecimals(0); + _spin->setRange(0L, 0x7FFFFFFFFFFFFFFFL); + _cur_edit = _spin; + connect(_spin, SIGNAL(valueChanged(double)), this, SLOT(_changed())); + break; + case QVariant::Double: + _spin = new QDoubleSpinBox(this); + _spin->setDecimals(5); + _spin->setRange(-1E+199, 1E+199); + _cur_edit = _spin; + connect(_spin, SIGNAL(valueChanged(double)), this, SLOT(_changed())); + break; + case QVariant::Color: + _color = new ColorButton(this); + _color->setUseAlphaChannel(true); + _cur_edit = _color; + connect(_color, SIGNAL(colorChanged(QColor)), this, SLOT(_changed())); + break; + case QVariant::String: + _line = new CLineEdit(this); + _cur_edit = _line; + connect(_line, SIGNAL(textChanged(QString)), this, SLOT(_changed())); + break; + case QVariant::StringList: + _list = new StringListEdit(this); + _cur_edit = _list; + connect(_list, SIGNAL(valueChanged()), this, SLOT(_changed())); + break; + case QVariant::Rect: + _rect = new QRectEdit(this); + _rect->setDecimals(0); + _cur_edit = _rect; + connect(_rect, SIGNAL(valueChanged(QRectF)), this, SLOT(_changed())); + break; + case QVariant::RectF: + _rect = new QRectEdit(this); + _rect->setDecimals(3); + _cur_edit = _rect; + connect(_rect, SIGNAL(valueChanged(QRectF)), this, SLOT(_changed())); + break; + case QVariant::Point: + _point = new QPointEdit(this); + _point->setDecimals(0); + _cur_edit = _point; + connect(_point, SIGNAL(valueChanged(QPointF)), this, SLOT(_changed())); + break; + case QVariant::PointF: + _point = new QPointEdit(this); + _point->setDecimals(3); + _cur_edit = _point; + connect(_point, SIGNAL(valueChanged(QPointF)), this, SLOT(_changed())); + break; + case QVariant::Date: + _date = new QDateEdit(this); + _cur_edit = _date; + connect(_date, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(_changed())); + break; + case QVariant::Time: + _date = new QTimeEdit(this); + _cur_edit = _date; + connect(_date, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(_changed())); + break; + case QVariant::DateTime: + _date = new QDateTimeEdit(this); + _cur_edit = _date; + connect(_date, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(_changed())); + break; + default: break; + } + if (!_cur_edit) { + if (new_value.canConvert()) { + _enum = new EComboBox(this); + _setEnum(new_value.value()); + _cur_edit = _enum; + connect(_enum, SIGNAL(currentIndexChanged(int)), this, SLOT(_changed())); + } + if (new_value.canConvert()) { + _path = new PathEdit(this); + _setFile(new_value.value()); + _cur_edit = _path; + connect(_path, SIGNAL(valueChanged()), this, SLOT(_changed())); + } + if (new_value.canConvert()) { + _path = new PathEdit(this); + _setDir(new_value.value()); + _cur_edit = _path; + connect(_path, SIGNAL(valueChanged()), this, SLOT(_changed())); + } + } + //qDebug() << _cur_edit; + if (_cur_edit) { + _resize(); + _cur_edit->show(); + } + _value = new_value; +} + + +QVariant QVariantEdit::value() const { + switch (_value.type()) { + case QVariant::Bool: return _check->isChecked(); + case QVariant::Int: return int(_spin->value()); + case QVariant::UInt: return (unsigned int)(_spin->value()); + case QVariant::LongLong: return qlonglong(_spin->value()); + case QVariant::ULongLong: return qulonglong(_spin->value()); + case QVariant::Double: return double(_spin->value()); + case QVariant::Color: return _color->color(); + case QVariant::String: return _line->text(); + case QVariant::StringList: return _list->value(); + case QVariant::Rect: return _rect->value().toRect(); + case QVariant::RectF: return _rect->value(); + case QVariant::Point: return _point->value().toPoint(); + case QVariant::PointF: return _point->value(); + case QVariant::Date: return _date->date(); + case QVariant::Time: return _date->time(); + case QVariant::DateTime: return _date->dateTime(); + default: + if (_value.canConvert() && _enum) { + QAD::Enum ret; + for (int i = 0; i < _enum->count(); ++i) + ret.enum_list << QAD::Enumerator(_enum->itemData(i).toInt(), _enum->itemText(i)); + ret.enum_name = _enum->property("enum_name").toString(); + ret.selected = _enum->currentText(); + return QVariant::fromValue(ret); + } + if (_value.canConvert() && _path) { + if (!_path->is_dir) { + QAD::File ret; + ret.file = _path->value(); + ret.filter = _path->filter; + ret.is_abs = _path->is_abs; + return QVariant::fromValue(ret); + } + } + if (_value.canConvert() && _path) { + if (_path->is_dir) { + QAD::Dir ret; + ret.dir = _path->value(); + ret.is_abs = _path->is_abs; + return QVariant::fromValue(ret); + } + } + } + return QVariant(); +} + + +void QVariantEdit::setValue(const QVariant & v) { + _recreate(v); + if (_cur_edit) _cur_edit->blockSignals(true); + if (_line) {_line->setText(v.toString());} + if (_check) {_check->setChecked(v.toBool()); _check->setText(v.toBool() ? "true" : "false");} + if (_color) {_color->setColor(v.value());} + if (_list) {_list->setValue(v.toStringList());} + if (_date) {_date->setDateTime(v.toDateTime());} + if (_spin) {_spin->setValue(v.toDouble());} + if (_rect) {_rect->setValue(v.toRectF());} + if (_point) {_point->setValue(v.toPointF());} + if (_path) { + if (_path->is_dir) _setDir(v.value()); + else _setFile(v.value()); + } + if (_enum) {_setEnum(v.value());} + if (_cur_edit) _cur_edit->blockSignals(false); +} + + +void QVariantEdit::_delete() { + if (_cur_edit) + delete _cur_edit; + _cur_edit = 0; + _empty = 0; + _line = 0; + _check = 0; + _color = 0; + _list = 0; + _date = 0; + _spin = 0; + _rect = 0; + _point = 0; + _path = 0; + _enum = 0; +} + + +void QVariantEdit::_newPath() { + _delete(); + _path = new PathEdit(this); + _cur_edit = _path; + _value = _value.toString(); + connect(_path, SIGNAL(valueChanged()), this, SLOT(_changed())); + _resize(); + _cur_edit->show(); +} + + +void QVariantEdit::_setEnum(const QAD::Enum & v) { + _enum->clear(); + _enum->setProperty("enum_name", v.enum_name); + foreach (const QAD::Enumerator & e, v.enum_list) + _enum->addItem(e.name, QVariant(e.value)); + int i(0); + for (i = 0; i < _enum->count(); ++i) + if (_enum->itemText(i) == v.selected) { + _enum->setCurrentIndex(i); + break; + } + if (i == _enum->count()) + _enum->setCurrentIndex(-1); +} + + +void QVariantEdit::_setFile(const QAD::File & v) { + _path->is_dir = false; + _path->setValue(v.file); + _path->filter = v.filter; + _path->is_abs = v.is_abs; +} + + +void QVariantEdit::_setDir(const QAD::Dir & v) { + _path->is_dir = true; + _path->setValue(v.dir); + _path->is_abs = v.is_abs; +} + +void QVariantEdit::_changed() { + if (_check) _check->setText(_check->isChecked() ? "true" : "false"); + emit valueChanged(value()); +} + diff --git a/qad/widgets/qvariantedit.h b/qad/widgets/qvariantedit.h new file mode 100644 index 0000000..a552b70 --- /dev/null +++ b/qad/widgets/qvariantedit.h @@ -0,0 +1,129 @@ +#ifndef QVARIANTEDIT_H +#define QVARIANTEDIT_H + +#include "clineedit.h" +#include "ecombobox.h" +#include "colorbutton.h" +#include "qrectedit.h" +#include "qpointedit.h" +#include "qad_types.h" +#include +#include + + +class StringListEdit: public QWidget +{ + Q_OBJECT +public: + StringListEdit(QWidget * parent = 0); + ~StringListEdit(); + + QStringList value() const; + +private: + virtual void changeEvent(QEvent * e); + + QBoxLayout lay; + EComboBox * combo; + QPushButton * butt_add, * butt_del, * butt_clear; + +public slots: + void setValue(const QStringList & v); + +private slots: + void editItem(); + void addItem(); + void delItem(); + void clear(); + +signals: + void valueChanged(); + +}; + + + + +class PathEdit: public QWidget +{ + Q_OBJECT +public: + PathEdit(QWidget * parent = 0); + ~PathEdit() {delete line; delete butt_select;} + + QString value() const {return line->text();} + + bool is_dir, is_abs; + QString filter; + +private: + virtual void changeEvent(QEvent * e); + + QBoxLayout lay; + CLineEdit * line; + QPushButton * butt_select; + +public slots: + void setValue(const QString & v) {line->setText(v);} + +private slots: + void select(); + +signals: + void valueChanged(); + +}; + + + + +class QVariantEdit: public QWidget +{ + Q_OBJECT + Q_PROPERTY(QVariant value READ value WRITE setValue) + +public: + explicit QVariantEdit(QWidget * parent = 0); + ~QVariantEdit(); + + QVariant value() const; + QSize sizeHint() const {if (_cur_edit) return _cur_edit->sizeHint(); return QWidget::sizeHint();} + QSize minimumSizeHint() const {if (_cur_edit) return _cur_edit->minimumSizeHint(); return QWidget::minimumSizeHint();} + +protected: + void resizeEvent(QResizeEvent * ); + void _recreate(const QVariant & new_value); + void _delete(); + void _resize() {if (_cur_edit) _cur_edit->resize(size());} + void _newPath(); + void _setEnum(const QAD::Enum & v); + void _setFile(const QAD::File & v); + void _setDir(const QAD::Dir & v); + + + QLabel * _empty; + CLineEdit * _line; + QCheckBox * _check; + ColorButton * _color; + StringListEdit * _list; + QDateTimeEdit * _date; + QDoubleSpinBox * _spin; + QRectEdit * _rect; + QPointEdit * _point; + PathEdit * _path; + EComboBox * _enum; + QWidget * _cur_edit; + QVariant _value; + +private slots: + void _changed(); + +public slots: + void setValue(const QVariant & v); + +signals: + void valueChanged(QVariant); + +}; + +#endif // QVARIANTEDIT_H diff --git a/qad/widgets/session_manager.cpp b/qad/widgets/session_manager.cpp new file mode 100644 index 0000000..8dbcd35 --- /dev/null +++ b/qad/widgets/session_manager.cpp @@ -0,0 +1,123 @@ +/* + Peri4 Paint + Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "session_manager.h" + + +void SessionManager::save() { + if (file_.isEmpty()) return; + QPIConfig sr(file_); + for (int i = 0; i < mwindows.size(); ++i) { + sr.setValue(mwindows[i].first + " state", mwindows[i].second->saveState(), false); + sr.setValue(mwindows[i].first + " window state", (int)mwindows[i].second->windowState(), false); + sr.setValue(mwindows[i].first + " geometry " + QString::number((int)mwindows[i].second->windowState()), mwindows[i].second->saveGeometry(), false); + QList sp = mwindows[i].second->findChildren(); + foreach (QSplitter * s, sp) + sr.setValue(mwindows[i].first + " splitter " + s->objectName(), s->saveState(), false); + } + for (int i = 0; i < widgets.size(); ++i) { + sr.setValue(widgets[i].first + " geometry " + QString::number((int)widgets[i].second->windowState()), widgets[i].second->saveGeometry(), false); + sr.setValue(widgets[i].first + " window state", (int)widgets[i].second->windowState(), false); + } + for (int i = 0; i < checks.size(); ++i) + sr.setValue(checks[i].first, checks[i].second->isChecked(), false); + for (int i = 0; i < lines.size(); ++i) + sr.setValue(lines[i].first, lines[i].second->text(), "s", false); + for (int i = 0; i < combos.size(); ++i) + sr.setValue(combos[i].first, combos[i].second->currentIndex(), false); + for (int i = 0; i < dspins.size(); ++i) + sr.setValue(dspins[i].first, dspins[i].second->value(), false); + for (int i = 0; i < spins.size(); ++i) + sr.setValue(spins[i].first, spins[i].second->value(), false); + for (int i = 0; i < spinsliders.size(); ++i) + sr.setValue(spinsliders[i].first, spinsliders[i].second->value(), false); + for (int i = 0; i < tabs.size(); ++i) + sr.setValue(tabs[i].first, tabs[i].second->currentIndex(), false); + for (int i = 0; i < actions.size(); ++i) + sr.setValue(actions[i].first, actions[i].second->isChecked(), false); + for (int i = 0; i < stringlists.size(); ++i) + sr.setValue(stringlists[i].first, *stringlists[i].second, false); + for (int i = 0; i < strings.size(); ++i) + sr.setValue(strings[i].first, *strings[i].second, "s", false); + for (int i = 0; i < colors.size(); ++i) + sr.setValue(colors[i].first, *colors[i].second, false); + for (int i = 0; i < bools.size(); ++i) + sr.setValue(bools[i].first, *bools[i].second, false); + for (int i = 0; i < ints.size(); ++i) + sr.setValue(ints[i].first, *ints[i].second, false); + for (int i = 0; i < floats.size(); ++i) + sr.setValue(floats[i].first, *floats[i].second, false); + sr.writeAll(); + emit saving(sr); +} + + +void SessionManager::load(bool onlyMainwindow) { + if (file_.isEmpty()) return; + QPIConfig sr(file_); + for (int i = 0; i < mwindows.size(); ++i) { + mwindows[i].second->restoreState(sr.getValue(mwindows[i].first + " state", QByteArray())); + mwindows[i].second->restoreGeometry(sr.getValue(mwindows[i].first + " geometry " + QString::number((int)mwindows[i].second->windowState()), QByteArray())); + mwindows[i].second->setWindowState((Qt::WindowState)(int)sr.getValue(mwindows[i].first + " window state", 0)); + QList sp = mwindows[i].second->findChildren(); + foreach (QSplitter * s, sp) + s->restoreState(sr.getValue(mwindows[i].first + " splitter " + s->objectName(), QByteArray())); + } + for (int i = 0; i < widgets.size(); ++i) { + widgets[i].second->restoreGeometry(sr.getValue(widgets[i].first + " geometry " + QString::number((int)widgets[i].second->windowState()), QByteArray())); + widgets[i].second->setWindowState((Qt::WindowState)(int)sr.getValue(widgets[i].first + " window state", 0)); + } + if (onlyMainwindow) return; + for (int i = 0; i < checks.size(); ++i) + checks[i].second->setChecked(sr.getValue(checks[i].first, checks[i].second->isChecked())); + for (int i = 0; i < lines.size(); ++i) + lines[i].second->setText(sr.getValue(lines[i].first, lines[i].second->text())); + for (int i = 0; i < combos.size(); ++i) { + QComboBox * c = combos[i].second; + int v = sr.getValue(combos[i].first, c->currentIndex()); + if (v >= 0 && v < c->count()) + c->setCurrentIndex(v); + } + for (int i = 0; i < dspins.size(); ++i) + dspins[i].second->setValue(sr.getValue(dspins[i].first, dspins[i].second->value())); + for (int i = 0; i < spins.size(); ++i) + spins[i].second->setValue(sr.getValue(spins[i].first, spins[i].second->value())); + for (int i = 0; i < spinsliders.size(); ++i) + spinsliders[i].second->setValue(sr.getValue(spinsliders[i].first, spinsliders[i].second->value())); + for (int i = 0; i < tabs.size(); ++i) { + QTabWidget * t = tabs[i].second; + int v = sr.getValue(tabs[i].first, t->currentIndex()); + if (v >= 0 && v < t->count()) + t->setCurrentIndex(v); + } + for (int i = 0; i < actions.size(); ++i) + actions[i].second->setChecked(sr.getValue(actions[i].first, actions[i].second->isChecked())); + for (int i = 0; i < stringlists.size(); ++i) + *stringlists[i].second = sr.getValue(stringlists[i].first, *stringlists[i].second); + for (int i = 0; i < strings.size(); ++i) + *strings[i].second = sr.getValue(strings[i].first, *strings[i].second).stringValue(); + for (int i = 0; i < colors.size(); ++i) + *colors[i].second = sr.getValue(colors[i].first, *colors[i].second); + for (int i = 0; i < bools.size(); ++i) + *bools[i].second = sr.getValue(bools[i].first, *bools[i].second); + for (int i = 0; i < ints.size(); ++i) + *ints[i].second = sr.getValue(ints[i].first, *ints[i].second); + for (int i = 0; i < floats.size(); ++i) + *floats[i].second = sr.getValue(floats[i].first, *floats[i].second); + emit loading(sr); +} diff --git a/qad/widgets/session_manager.h b/qad/widgets/session_manager.h new file mode 100644 index 0000000..d5d9adb --- /dev/null +++ b/qad/widgets/session_manager.h @@ -0,0 +1,99 @@ +/* + Peri4 Paint + Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef SESSION_MANAGER_H +#define SESSION_MANAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "spinslider.h" +#include "qpiconfig.h" + +class SessionManager: public QObject +{ + Q_OBJECT +public: + SessionManager(const QString & file = QString()) {setFile(file);} + ~SessionManager() {;} + + inline void setFile(const QString & file) {file_ = file;} + + inline void addEntry(QMainWindow * e) {mwindows.push_back(QPair(e->objectName(), e));} + inline void addEntry(QCheckBox * e) {checks.push_back(QPair(e->objectName(), e));} + inline void addEntry(QLineEdit * e) {lines.push_back(QPair(e->objectName(), e));} + inline void addEntry(QComboBox * e) {combos.push_back(QPair(e->objectName(), e));} + inline void addEntry(QDoubleSpinBox * e) {dspins.push_back(QPair(e->objectName(), e));} + inline void addEntry(QSpinBox * e) {spins.push_back(QPair(e->objectName(), e));} + inline void addEntry(SpinSlider * e) {spinsliders.push_back(QPair(e->objectName(), e));} + inline void addEntry(QTabWidget * e) {tabs.push_back(QPair(e->objectName(), e));} + inline void addEntry(QAction * e) {actions.push_back(QPair(e->objectName(), e));} + inline void addMainWidget(QWidget * e) {widgets.push_back(QPair(e->objectName(), e));} + + inline void addEntry(const QString & name, QMainWindow * e) {mwindows.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QCheckBox * e) {checks.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QLineEdit * e) {lines.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QComboBox * e) {combos.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QDoubleSpinBox * e) {dspins.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QSpinBox * e) {spins.push_back(QPair(name, e));} + inline void addEntry(const QString & name, SpinSlider * e) {spinsliders.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QTabWidget * e) {tabs.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QAction * e) {actions.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QStringList * e) {stringlists.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QString * e) {strings.push_back(QPair(name, e));} + inline void addEntry(const QString & name, QColor * e) {colors.push_back(QPair(name, e));} + inline void addEntry(const QString & name, bool * e) {bools.push_back(QPair(name, e));} + inline void addEntry(const QString & name, int * e) {ints.push_back(QPair(name, e));} + inline void addEntry(const QString & name, float * e) {floats.push_back(QPair(name, e));} + inline void addMainWidget(const QString & name, QWidget * e) {widgets.push_back(QPair(name, e));} + + void save(); + void load(bool onlyMainwindow = false); + +private: + QVector > mwindows; + QVector > widgets; + QVector > checks; + QVector > lines; + QVector > combos; + QVector > dspins; + QVector > spins; + QVector > spinsliders; + QVector > tabs; + QVector > actions; + QVector > stringlists; + QVector > strings; + QVector > colors; + QVector > bools; + QVector > ints; + QVector > floats; + QString file_; + +signals: + void loading(QPIConfig & ); + void saving(QPIConfig & ); + +}; + +#endif // SESSION_MANAGER_H diff --git a/qad/widgets/shortcuts.cpp b/qad/widgets/shortcuts.cpp new file mode 100644 index 0000000..234a637 --- /dev/null +++ b/qad/widgets/shortcuts.cpp @@ -0,0 +1,233 @@ +#include "shortcuts.h" + + +void ShortcutEdit::keyPressEvent(QKeyEvent * e) { + Qt::KeyboardModifiers km = e->modifiers(); + km &= ~Qt::KeypadModifier; + km &= ~Qt::GroupSwitchModifier; + if (e->key() != Qt::Key_Control && e->key() != Qt::Key_Shift && + e->key() != Qt::Key_Alt && e->key() != Qt::Key_Meta) + setText(QKeySequence(km | e->key()).toString()); +} + + + +Shortcuts::Shortcuts(QWidget * parent, bool on): QTreeWidget(parent) { + aw = 0; + QImage ti(QSize(16, 16), QImage::Format_ARGB32_Premultiplied); + QPainter p(&ti); + p.setCompositionMode(QPainter::CompositionMode_Clear); + p.eraseRect(ti.rect()); + p.end(); + empty_icon = QPixmap::fromImage(ti); + bfont = font(); + bfont.setWeight(QFont::Bold); + active = on; + setColumnCount(2); +#if QT_VERSION < 0x050000 + header()->setResizeMode(0, QHeaderView::ResizeToContents); + header()->setResizeMode(1, QHeaderView::ResizeToContents); +#else + header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); +#endif + header()->setStretchLastSection(true); + setColumnWidth(1, 200); + setSortingEnabled(true); + QStringList l; + l << tr("Command") << tr("Shortcut"); + setHeaderLabels(l); + assignWindow(parent); +} + + +Shortcuts::~Shortcuts() { + foreach (ShortcutEdit * i, edits) + delete i; + edits.clear(); +} + + +void Shortcuts::changeEvent(QEvent * e) { + if (e->type() == QEvent::LanguageChange) { + QStringList l; + l << tr("Command") << tr("Shortcut"); + setHeaderLabels(l); + } +} + + +void Shortcuts::assignWindow(QWidget * w) { + if (w == 0) return; + while ((qobject_cast(w) == 0) && (w->parentWidget() != 0)) + w = w->parentWidget(); + aw = qobject_cast(w); + updateShortcuts(); +} + + +QStringList Shortcuts::actionTree(QAction * a) { + QStringList tree; + QList aw = a->associatedWidgets(); + if (aw.size() == 0) return tree; + QWidget * cw = 0; + QMenu * tm; + QToolBar * tt; + foreach (QWidget * i, aw) { + tm = qobject_cast(i); + if (tm == 0) continue; + cw = i; + while (cw != 0) { + tm = qobject_cast(cw); + if (tm != 0) { + if (!tm->title().isEmpty()) + tree.push_front(tm->title()); + cw = cw->parentWidget(); + } else break; + } + if (!tree.isEmpty()) return tree; + } + foreach (QWidget * i, aw) { + tt = qobject_cast(i); + if (tt == 0) continue; + cw = i; + if (!tt->windowTitle().isEmpty()) + tree.push_front(tt->windowTitle()); + break; + } + return tree; +} + + +QList > Shortcuts::shortcuts() { + QList > l; + foreach (ShortcutEdit * i, edits) { + if (i->action()->objectName().isEmpty()) continue; + l << QPair(i->action()->objectName(), i->text()); + } + return l; +} + + +void Shortcuts::clear() { + foreach (ShortcutEdit * i, edits) + delete i; + edits.clear(); + hide(); + QList tl = findItems("", Qt::MatchContains); + foreach (QTreeWidgetItem * i, tl) + delete i; + show(); +} + + +bool Shortcuts::checkAction(QAction * a) { + if (a->menu() != 0) return false; + if (a->isSeparator()) return false; + if (a->text().isEmpty()) return false; + if (a->associatedWidgets().isEmpty()) return false; + if (QString(a->metaObject()->className()) != "QAction") return false; + if (qobject_cast(a) != 0) return false; + return true; +} + + +void Shortcuts::updateShortcuts() { + //return; + if (aw == 0 || !active) return; + hide(); + int cpos = verticalScrollBar()->value(); + clear(); +#if QT_VERSION < 0x050000 + header()->setResizeMode(0, QHeaderView::Fixed); +#else + header()->setSectionResizeMode(0, QHeaderView::Fixed); +#endif + QList al = aw->findChildren(); + QTreeWidgetItem * pi, * ci; + QStringList tree; + bool s = isSortingEnabled(), isFound; + setSortingEnabled(false); + foreach (QAction * i, al) { + if (!checkAction(i)) continue; + edits.push_back(new ShortcutEdit()); + tree = actionTree(i); + pi = invisibleRootItem(); + foreach (QString t, tree) { + isFound = false; + for (int j = 0; j < pi->childCount(); ++j) { + if (pi->child(j)->text(0) == t) { + pi = pi->child(j); + isFound = true; + break; + } + } + if (isFound) continue; + ci = new QTreeWidgetItem(pi); + ci->setText(0, t); + ci->setToolTip(0, t); + ci->setFont(0, bfont); + pi->addChild(ci); + pi = ci; + } + ci = new QTreeWidgetItem(pi); + ci->setText(0, i->text()); + ci->setToolTip(0, i->text()); + if (i->icon().isNull()) + ci->setIcon(0, empty_icon); + else + ci->setIcon(0, i->icon()); + edits.back()->ti = ci; + edits.back()->assignAction(i); + pi->addChild(ci); + //qDebug() << "set widget" << edits.back(); + setItemWidget(ci, 1, edits.back()); + } + setSortingEnabled(s); +#if QT_VERSION < 0x050000 + header()->setResizeMode(0, QHeaderView::ResizeToContents); +#else + header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); +#endif + expandAll(); + verticalScrollBar()->setValue(cpos); + show(); +} + + +void Shortcuts::commit() { + foreach (ShortcutEdit * i, edits) + i->commit(); +} + + +void Shortcuts::reset() { + foreach (ShortcutEdit * i, edits) + i->reset(); + updateShortcuts(); +} + + +void Shortcuts::filter(const QString & what) { + hide(); + for (int i = 0; i < topLevelItemCount(); ++i) + filterTree(topLevelItem(i), what); + show(); +} + + +bool Shortcuts::filterTree(QTreeWidgetItem * ti, QString f) { + if (f.isEmpty()) { + for (int i = 0; i < ti->childCount(); ++i) + filterTree(ti->child(i), f); + ti->setHidden(false); + return true; + } + bool isFound = false; + for (int i = 0; i < ti->childCount(); ++i) + if (filterTree(ti->child(i), f)) isFound = true; + if (ti->text(0).indexOf(f, 0, Qt::CaseInsensitive) >= 0 || + ti->text(1).indexOf(f, 0, Qt::CaseInsensitive) >= 0) isFound = true; + ti->setHidden(!isFound); + return isFound; +} diff --git a/qad/widgets/shortcuts.h b/qad/widgets/shortcuts.h new file mode 100644 index 0000000..1bddb1a --- /dev/null +++ b/qad/widgets/shortcuts.h @@ -0,0 +1,90 @@ +#ifndef SHORTCUTS_H +#define SHORTCUTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clineedit.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class ShortcutEdit: public CLineEdit +{ + Q_OBJECT + friend class Shortcuts; +public: + explicit ShortcutEdit(QWidget * parent = 0): CLineEdit(parent) {ti = 0; ca = 0; connect(this, SIGNAL(textChanged(QString)), this, SLOT(textChanged_(QString)));} + + void assignAction(QAction * a) {clear(); ca = a; reset();} + QAction * action() const {return ca;} + bool isEmpty() const {return text().isEmpty();} + void commit() {if (ca == 0) return; ca->setShortcut(QKeySequence(text()));} + void reset() {if (ca == 0) return; setText(ca->shortcut().toString());} + +private slots: + void textChanged_(QString t) {if (ti != 0) ti->setText(1, t);} + +private: + void keyPressEvent(QKeyEvent * e); + + QAction * ca; + QTreeWidgetItem * ti; + +}; + + +class Shortcuts: public QTreeWidget +{ + Q_OBJECT + +public: + explicit Shortcuts(QWidget * parent = 0, bool on = true); + ~Shortcuts(); + + void assignWindow(QWidget * w); + void setActive(bool on) {active = on;} + QList > shortcuts(); + QStringList actionTree(QAction * a); + static bool checkAction(QAction * a); + +public slots: + void clear(); + void updateShortcuts(); + void commit(); + void reset(); + void filter(const QString & what); + +private: + virtual void updateEditorGeometries() {foreach (ShortcutEdit * i, edits) i->setGeometry(visualRect(indexFromItem(i->ti, 1)));} + virtual void changeEvent(QEvent * ); + bool filterTree(QTreeWidgetItem * ti, QString f); + + QMainWindow * aw; + QVector edits; + QIcon empty_icon; + QFont bfont; + bool active; + +private slots: + +signals: + void shortcutChanged(QAction * , QShortcut & ); + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // SPINSLIDER_H diff --git a/qad/widgets/spinslider.cpp b/qad/widgets/spinslider.cpp new file mode 100644 index 0000000..29ac431 --- /dev/null +++ b/qad/widgets/spinslider.cpp @@ -0,0 +1,85 @@ +#include "spinslider.h" +#include + + +SpinSlider::SpinSlider(QWidget * parent): QWidget(parent) { + min_ = val_ = 0.; + max_ = 100.; + dec_ = 1; + page = 10.; + ticks_ = 1; + direc = LeftToRight; + square = false; + slider = new QSlider(); + slider->setOrientation(Qt::Horizontal); + slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + spin = new QDoubleSpinBox(); + adjust(); + layout = new QBoxLayout(QBoxLayout::LeftToRight); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(slider); + layout->addWidget(spin); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int))); + connect(spin, SIGNAL(valueChanged(double)), this, SLOT(spinChanged(double))); + setLayout(layout); +} + + +SpinSlider::~SpinSlider() { + delete spin; + delete slider; + delete layout; +} + + +void SpinSlider::setOrientation(Qt::Orientation orient) { + slider->setOrientation(orient); + if (orient == Qt::Horizontal) + slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + else + slider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); +} + + +void SpinSlider::adjust() { + adjusting = true; + delim = qPow(10, dec_); + spin->setDecimals(dec_); + spin->setRange(min_, max_); + if (square) slider->setRange(sqrt(min_ * delim), sqrt(max_ * delim)); + else slider->setRange(min_ * delim, max_ * delim); + if (val_ < min_) val_ = min_; + if (val_ > max_) val_ = max_; + spin->setValue(val_); + if (square) slider->setValue(static_cast(sqrt(val_ * delim))); + else slider->setValue(static_cast(val_ * delim)); + slider->setPageStep(qRound(page * delim)); + slider->setTickInterval(qRound(ticks_ * delim)); + emit valueChanged(val_); + emit valueChanged(qRound(val_)); + adjusting = false; +} + + +void SpinSlider::sliderChanged(int value) { + if (adjusting) return; + adjusting = true; + if (square) spin->setValue(static_cast(sqr(value) / delim)); + else spin->setValue(static_cast(value) / delim); + val_ = spin->value(); + emit valueChanged(val_); + emit valueChanged(qRound(val_)); + adjusting = false; +} + + +void SpinSlider::spinChanged(double value) { + if (adjusting) return; + adjusting = true; + val_ = value; + if (square) slider->setValue(static_cast(sqrt(value * delim))); + else slider->setValue(qRound(value * delim)); + emit valueChanged(val_); + emit valueChanged(qRound(val_)); + adjusting = false; +} diff --git a/qad/widgets/spinslider.h b/qad/widgets/spinslider.h new file mode 100644 index 0000000..6c9d0c8 --- /dev/null +++ b/qad/widgets/spinslider.h @@ -0,0 +1,102 @@ +#ifndef SPINSLIDER_H +#define SPINSLIDER_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class SpinSlider: public QWidget +{ + Q_OBJECT + Q_ENUMS(Direction) + Q_PROPERTY(double minimum READ minimum WRITE setMinimum) + Q_PROPERTY(double maximum READ maximum WRITE setMaximum) + Q_PROPERTY(double value READ value WRITE setValue) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep) + Q_PROPERTY(double pageStep READ pageStep WRITE setPageStep) + Q_PROPERTY(QString prefix READ prefix WRITE setPrefix) + Q_PROPERTY(QString suffix READ suffix WRITE setSuffix) + Q_PROPERTY(QSlider::TickPosition tickPosition READ tickPosition WRITE setTickPosition) + Q_PROPERTY(int tickInterval READ tickInterval WRITE setTickInterval) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) + Q_PROPERTY(Direction direction READ direction WRITE setDirection) + Q_PROPERTY(bool invertedAppearance READ invertedAppearance WRITE setInvertedAppearance) + Q_PROPERTY(bool squareScale READ squareScale WRITE setSquareScale) + Q_PROPERTY(double spinMinimum READ spinMinimum WRITE setSpinMinimum) + Q_PROPERTY(double spinMaximum READ spinMaximum WRITE setSpinMaximum) + +public: + explicit SpinSlider(QWidget * parent = 0); + ~SpinSlider(); + + enum Direction {LeftToRight, RightToLeft, TopToBottom, BottomToTop}; + + double minimum() const {return min_;} + double maximum() const {return max_;} + double spinMinimum() const {return spin->minimum();} + double spinMaximum() const {return spin->maximum();} + double value() const {return val_;} + int decimals() const {return dec_;} + double singleStep() const {return spin->singleStep();} + double pageStep() const {return page;} + QString prefix() const {return spin->prefix();} + QString suffix() const {return spin->suffix();} + QSlider::TickPosition tickPosition() const {return slider->tickPosition();} + int tickInterval() const {return ticks_;} + Qt::Orientation orientation() const {return slider->orientation();} + Direction direction() const {return direc;} + bool invertedAppearance() const {return slider->invertedAppearance();} + bool squareScale() const {return square;} + + void setSingleStep(double step) {spin->setSingleStep(step); slider->setPageStep(qRound(step * delim));} + void setPageStep(double step) {page = step; slider->setPageStep(qRound(page * delim));} + void setPrefix(QString prefix) {spin->setPrefix(prefix);} + void setSuffix(QString suffix) {spin->setSuffix(suffix);} + void setTickPosition(QSlider::TickPosition tp) {slider->setTickPosition(tp);} + void setTickInterval(int ti) {ticks_ = ti; slider->setTickInterval(qRound(ticks_ * delim));} + void setOrientation(Qt::Orientation orient); + void setDirection(Direction d) {direc = d; layout->setDirection((QBoxLayout::Direction)d);} + void setInvertedAppearance(bool yes) {slider->setInvertedAppearance(yes);} + void setSquareScale(bool yes) {square = yes; adjust();} + +public slots: + void setMinimum(double value) {min_ = value; adjust();} + void setMaximum(double value) {max_ = value; adjust();} + void setSpinMinimum(double value) {spin->setMinimum(value);} + void setSpinMaximum(double value) {spin->setMaximum(value);} + void setValue(double value) {val_ = value; spin->setValue(value);} + void setDecimals(int value) {dec_ = value; adjust();} + void reset() {val_ = 0.; spin->setValue(0.);} + +private: + void adjust(); + double sqr(const double & v) {return v * v;} + + double min_, max_, val_, delim, page; + int dec_, ticks_; + bool adjusting, square; + QSlider * slider; + QDoubleSpinBox * spin; + QBoxLayout * layout; + Direction direc; + +private slots: + void sliderChanged(int value); + void spinChanged(double value); + +signals: + void valueChanged(double); + void valueChanged(int); + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // SPINSLIDER_H diff --git a/qcd_utils/CMakeLists.txt b/qcd_utils/CMakeLists.txt index 83174ea..5cca884 100644 --- a/qcd_utils/CMakeLists.txt +++ b/qcd_utils/CMakeLists.txt @@ -2,55 +2,14 @@ project(qcd_utils) cmake_minimum_required(VERSION 2.6) if (NOT LIBPROJECT) find_package(PIP REQUIRED) -endif () -if (MINGW) - find_package(MinGW REQUIRED) endif() -find_package(Qt4 REQUIRED) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${PIP_INCLUDES} ${QT_INCLUDES}) -set(PULT_NAME "cd_pult") -option(PULT "Build ${PULT_NAME}" 1) -option(LIB "System install" 1) -option(DEBUG "Build with -g3" 0) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") -if (DEBUG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") -endif () -file(GLOB CPPS "*.cpp") -file(GLOB MOCS "*.h") -file(GLOB UIS "*.ui") -file(GLOB RES "*.qrc") -qt4_wrap_cpp(CMOCS ${MOCS} OPTIONS -nw) -qt4_wrap_ui(CUIS ${UIS}) -qt4_add_resources(RESS ${RES}) -add_library(${PROJECT_NAME} SHARED ${CPPS} ${CMOCS} ${CUIS} ${RESS} ${MOCS}) -set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${PIP_LIBRARY} qad_utils qad_widgets cd_utils piqt) -target_link_libraries(${PROJECT_NAME} ${LIBS}) - +find_package(QAD REQUIRED) +include_directories(${PIP_INCLUDES} ${QAD_INCLUDES}) +set(LIBS ${PIP_LIBRARY} ${QAD_UTILS_LIBRARY} ${QAD_WIDGETS_LIBRARY} cd_utils piqt) +qt_project(${PROJECT_NAME} "LIB" "${LIBS}" H CPP) +sdk_install("" ${PROJECT_NAME} "${H}") if (NOT DEFINED ENV{QNX_HOST}) if (PULT) add_subdirectory(pult) endif () endif () - if (LIB) - if (WIN32) - set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) - install(FILES ${MOCS} DESTINATION ${MINGW_INCLUDE}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN}) - get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) - install(TARGETS ${PROJECT_NAME} DESTINATION ${QTDIR}) - else () - if(APPLE) - set(CMAKE_INSTALL_PREFIX /usr/local) - else() - set(CMAKE_INSTALL_PREFIX /usr) - endif() - install(FILES ${MOCS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) - install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) - endif () - message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") -else () - install(TARGETS ${PROJECT_NAME} DESTINATION bin) - message(STATUS "Install to local \"bin\"") -endif () diff --git a/qcd_utils/clean.bat b/qcd_utils/clean.bat deleted file mode 100644 index 3a657d9..0000000 --- a/qcd_utils/clean.bat +++ /dev/null @@ -1,4 +0,0 @@ -#make clean -del /q /f /s CMakeFiles -rmdir /q /s CMakeFiles -del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *.user* *~ *cxx moc_* ui_* qrc_* *.o *.exe *.a *.dll *.lib core *.qrc.depends diff --git a/qcd_utils/make_lib.bat b/qcd_utils/make_lib.bat deleted file mode 100644 index 0148a43..0000000 --- a/qcd_utils/make_lib.bat +++ /dev/null @@ -1 +0,0 @@ -cmake -G "MinGW Makefiles" -DLIB=1 && make install . %* diff --git a/qcd_utils/pult/CMakeLists.txt b/qcd_utils/pult/CMakeLists.txt index 6ab75ee..589292f 100644 --- a/qcd_utils/pult/CMakeLists.txt +++ b/qcd_utils/pult/CMakeLists.txt @@ -1,21 +1,8 @@ -project(cd_pult) -cmake_minimum_required(VERSION 2.6) if (NOT LIBPROJECT) find_package(PIP REQUIRED) endif () if (MINGW) find_package(MinGW REQUIRED) endif() -find_package(Qt4 REQUIRED) -find_package(OpenGL REQUIRED) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${PIP_INCLUDES} ${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR}/../) -file(GLOB PULT_CPPS "*.cpp") -file(GLOB PULT_MOCS "*.h") -file(GLOB PULT_UIS "*.ui") -file(GLOB PULT_RES "*.qrc") -qt4_wrap_cpp(PULT_CMOCS ${PULT_MOCS} OPTIONS -nw) -qt4_wrap_ui(PULT_CUIS ${PULT_UIS}) -qt4_add_resources(PULT_RESS ${PULT_RES}) -add_executable(${PROJECT_NAME} ${PULT_CPPS} ${PULT_CMOCS} ${PULT_CUIS} ${PULT_RESS} ${PULT_MOCS}) -set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES} ${PIP_LIBRARY} qad_graphic qad_utils qad_widgets qcd_utils) -target_link_libraries(${PROJECT_NAME} ${LIBS} cd_utils) +set(LIBS ${QAD_GRAPHIC_LIBRARY} ${QAD_UTILS_LIBRARY} ${QAD_WIDGETS_LIBRARY} qcd_utils) +qt_project(cd_pult "EXE" "${LIBS}" H CPP) diff --git a/touch_widgets/CMakeLists.txt b/touch_widgets/CMakeLists.txt deleted file mode 100644 index 2213e3f..0000000 --- a/touch_widgets/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -project(touch_widgets) -cmake_minimum_required(VERSION 2.6) -find_package(Qt4 REQUIRED) -if (MINGW) - find_package(MinGW REQUIRED) -endif() -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES}) -option(LIB "System install" 0) -option(DEBUG "Build with -g3" 0) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") -if (DEBUG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") -endif () -set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) -file(GLOB MOCS "./*.h") -file(GLOB CPPS "./*.cpp") -file(GLOB UIS "./*.ui") -file(GLOB RES "./*.qrc") -qt4_wrap_ui(CUIS ${UIS}) -qt4_wrap_cpp(CMOCS ${MOCS} OPTIONS -nw) -qt4_add_resources(CRES ${RES}) -add_library(${PROJECT_NAME} SHARED ${CPPS} ${CUIS} ${CMOCS} ${CRES} ${MOCS}) -target_link_libraries(${PROJECT_NAME} ${LIBS}) -if (LIB) - if (WIN32) - set(CMAKE_INSTALL_PREFIX ${MINGW_DIR}) - install(FILES ${MOCS} DESTINATION ${MINGW_INCLUDE}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB}) - install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN}) - get_filename_component(QTDIR ${QT_QMAKE_EXECUTABLE} PATH) - install(TARGETS ${PROJECT_NAME} DESTINATION ${QTDIR}) - else () - if(APPLE) - set(CMAKE_INSTALL_PREFIX /usr/local) - else() - set(CMAKE_INSTALL_PREFIX /usr) - endif() - install(FILES ${MOCS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) - install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) - endif () - message(STATUS "Install to system \"${CMAKE_INSTALL_PREFIX}\"") -else () - install(TARGETS ${PROJECT_NAME} DESTINATION bin) - message(STATUS "Install to local \"bin\"") -endif () -add_subdirectory(plugin) diff --git a/touch_widgets/clean b/touch_widgets/clean deleted file mode 100644 index ecba637..0000000 --- a/touch_widgets/clean +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/bash -VERBOSE=1 make clean -rm -rvf CMakeFiles -rm -vf CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *.dll *.a *.so *.user* *~ *cxx moc_* ui_* qrc_* *.o diff --git a/touch_widgets/clean.bat b/touch_widgets/clean.bat deleted file mode 100644 index 3a657d9..0000000 --- a/touch_widgets/clean.bat +++ /dev/null @@ -1,4 +0,0 @@ -#make clean -del /q /f /s CMakeFiles -rmdir /q /s CMakeFiles -del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *.user* *~ *cxx moc_* ui_* qrc_* *.o *.exe *.a *.dll *.lib core *.qrc.depends diff --git a/touch_widgets/make_lib.bat b/touch_widgets/make_lib.bat deleted file mode 100644 index 0148a43..0000000 --- a/touch_widgets/make_lib.bat +++ /dev/null @@ -1 +0,0 @@ -cmake -G "MinGW Makefiles" -DLIB=1 && make install . %* diff --git a/touch_widgets/plugin/CMakeLists.txt b/touch_widgets/plugin/CMakeLists.txt deleted file mode 100644 index b72017a..0000000 --- a/touch_widgets/plugin/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -project(touch_widgets_plugin) -cmake_minimum_required(VERSION 2.6) -find_package(Qt4 REQUIRED) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QT_INCLUDES} "..") -option(DEBUG "Build with -g3" 0) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") -if (DEBUG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") -endif () -set(LIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES}) -add_definitions(-DQT_PLUGIN) -add_definitions(-DQT_NO_DEBUG) -add_definitions(-DQT_SHARED) -add_definitions(-DQDESIGNER_EXPORT_WIDGETS) -file(GLOB PMOCS "./*.h") -file(GLOB PCPPS "./*.cpp") -qt4_wrap_cpp(PCMOCS ${PMOCS} OPTIONS -nw) -add_library(${PROJECT_NAME} SHARED ${PCMOCS} ${PCPPS} ${PMOCS}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${QT_QTDESIGNER_LIBRARY} touch_widgets) -install(TARGETS ${PROJECT_NAME} DESTINATION ${QT_PLUGINS_DIR}/designer) diff --git a/touch_widgets/touch_widgets.qrc b/touch_widgets/touch_widgets.qrc deleted file mode 100644 index 6f204a4..0000000 --- a/touch_widgets/touch_widgets.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - icons/touchbuttframe.png - icons/touchbutton.png - icons/touchslider.png - -