From ac8d347e9e7a3392f9ae3a81373977ad63942056 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 5 Jul 2016 12:07:31 +0200 Subject: [PATCH 01/46] we have html output and autodoc functionality --- CMakeLists.txt | 4 + cmake/FindSphinx.cmake | 145 +++++++++++++++ docs/CMakeLists.txt | 27 +++ docs/sphinx/run_sphinx_build.sh.in | 7 + docs/sphinx/source/conf.py.in | 275 +++++++++++++++++++++++++++++ docs/sphinx/source/index.rst | 19 ++ docs/sphinx/source/mwbase.rst | 33 ++++ docs/sphinx/source/openmw.rst | 16 ++ 8 files changed, 526 insertions(+) create mode 100644 cmake/FindSphinx.cmake create mode 100644 docs/CMakeLists.txt create mode 100644 docs/sphinx/run_sphinx_build.sh.in create mode 100644 docs/sphinx/source/conf.py.in create mode 100644 docs/sphinx/source/index.rst create mode 100644 docs/sphinx/source/mwbase.rst create mode 100644 docs/sphinx/source/openmw.rst diff --git a/CMakeLists.txt b/CMakeLists.txt index 14a1c15c8..e5ecd1f62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -829,3 +829,7 @@ if (DOXYGEN_FOUND) WORKING_DIRECTORY ${OpenMW_BINARY_DIR} COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) endif () + + +OPTION(WANT_DOCS "Build documentation." OFF ) +ADD_SUBDIRECTORY(docs) diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake new file mode 100644 index 000000000..4607f7806 --- /dev/null +++ b/cmake/FindSphinx.cmake @@ -0,0 +1,145 @@ +# - This module looks for Sphinx +# Find the Sphinx documentation generator +# +# This modules defines +# SPHINX_EXECUTABLE +# SPHINX_FOUND + +find_program(SPHINX_EXECUTABLE + NAMES sphinx-build + PATHS + /usr/bin + /usr/local/bin + /opt/local/bin + DOC "Sphinx documentation generator" +) + +if( NOT SPHINX_EXECUTABLE ) + set(_Python_VERSIONS + 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0 1.6 1.5 + ) + + foreach( _version ${_Python_VERSIONS} ) + set( _sphinx_NAMES sphinx-build-${_version} ) + + find_program( SPHINX_EXECUTABLE + NAMES ${_sphinx_NAMES} + PATHS + /usr/bin + /usr/local/bin + /opt/loca/bin + DOC "Sphinx documentation generator" + ) + endforeach() +endif() + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(Sphinx DEFAULT_MSG + SPHINX_EXECUTABLE +) + + +option( SPHINX_HTML_OUTPUT "Build a single HTML with the whole content." ON ) +option( SPHINX_DIRHTML_OUTPUT "Build HTML pages, but with a single directory per document." OFF ) +option( SPHINX_HTMLHELP_OUTPUT "Build HTML pages with additional information for building a documentation collection in htmlhelp." OFF ) +option( SPHINX_QTHELP_OUTPUT "Build HTML pages with additional information for building a documentation collection in qthelp." OFF ) +option( SPHINX_DEVHELP_OUTPUT "Build HTML pages with additional information for building a documentation collection in devhelp." OFF ) +option( SPHINX_EPUB_OUTPUT "Build HTML pages with additional information for building a documentation collection in epub." OFF ) +option( SPHINX_LATEX_OUTPUT "Build LaTeX sources that can be compiled to a PDF document using pdflatex." OFF ) +option( SPHINX_MAN_OUTPUT "Build manual pages in groff format for UNIX systems." OFF ) +option( SPHINX_TEXT_OUTPUT "Build plain text files." OFF ) + + +mark_as_advanced( + SPHINX_EXECUTABLE + SPHINX_HTML_OUTPUT + SPHINX_DIRHTML_OUTPUT + SPHINX_HTMLHELP_OUTPUT + SPHINX_QTHELP_OUTPUT + SPHINX_DEVHELP_OUTPUT + SPHINX_EPUB_OUTPUT + SPHINX_LATEX_OUTPUT + SPHINX_MAN_OUTPUT + SPHINX_TEXT_OUTPUT +) + +function( Sphinx_add_target target_name builder conf source destination ) + add_custom_target( ${target_name} ALL + COMMAND ${SPHINX_EXECUTABLE} -b ${builder} + -c ${conf} + ${source} + ${destination} + COMMENT "Generating sphinx documentation: ${builder}" + ) + + set_property( + DIRECTORY APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES + ${destination} + ) +endfunction() + +# Target dependencies can be optionally listed at the end. +function( Sphinx_add_targets target_base_name conf source base_destination ) + + set( _dependencies ) + + foreach( arg IN LISTS ARGN ) + set( _dependencies ${_dependencies} ${arg} ) + endforeach() + + if( ${SPHINX_HTML_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_html html ${conf} ${source} ${base_destination}/html ) + + add_dependencies( ${target_base_name}_html ${_dependencies} ) + endif() + + if( ${SPHINX_DIRHTML_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_dirhtml dirhtml ${conf} ${source} ${base_destination}/dirhtml ) + + add_dependencies( ${target_base_name}_dirhtml ${_dependencies} ) + endif() + + if( ${SPHINX_QTHELP_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_qthelp qthelp ${conf} ${source} ${base_destination}/qthelp ) + + add_dependencies( ${target_base_name}_qthelp ${_dependencies} ) + endif() + + if( ${SPHINX_DEVHELP_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_devhelp devhelp ${conf} ${source} ${base_destination}/devhelp ) + + add_dependencies( ${target_base_name}_devhelp ${_dependencies} ) + endif() + + if( ${SPHINX_EPUB_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_epub epub ${conf} ${source} ${base_destination}/epub ) + + add_dependencies( ${target_base_name}_epub ${_dependencies} ) + endif() + + if( ${SPHINX_LATEX_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_latex latex ${conf} ${source} ${base_destination}/latex ) + + add_dependencies( ${target_base_name}_latex ${_dependencies} ) + endif() + + if( ${SPHINX_MAN_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_man man ${conf} ${source} ${base_destination}/man ) + + add_dependencies( ${target_base_name}_man ${_dependencies} ) + endif() + + if( ${SPHINX_TEXT_OUTPUT} ) + Sphinx_add_target( ${target_base_name}_text text ${conf} ${source} ${base_destination}/text ) + + add_dependencies( ${target_base_name}_text ${_dependencies} ) + endif() + + if( ${BUILD_TESTING} ) + sphinx_add_target( ${target_base_name}_linkcheck linkcheck ${conf} ${source} ${base_destination}/linkcheck ) + + add_dependencies( ${target_base_name}_linkcheck ${_dependencies} ) + endif() +endfunction() diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 000000000..c63d6dc18 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,27 @@ +IF( WANT_DOCS ) + # Builds the documentation. + FIND_PACKAGE( Sphinx REQUIRED ) + FIND_PACKAGE( Doxygen REQUIRED ) + + SET( SPHINX_SOURCE_DIR ${CMAKE_SOURCE_DIR}/docs/sphinx ) + SET( DOCUMENTATION_DIR ${OpenMW_BINARY_DIR}/docs ) + + FILE(MAKE_DIRECTORY ${DOCUMENTATION_DIR}/_static) + FILE(MAKE_DIRECTORY ${DOCUMENTATION_DIR}/_templates) + + CONFIGURE_FILE( + ${SPHINX_SOURCE_DIR}/source/conf.py.in + ${DOCUMENTATION_DIR}/conf.py + @ONLY) + + CONFIGURE_FILE( + ${SPHINX_SOURCE_DIR}/run_sphinx_build.sh.in + ${DOCUMENTATION_DIR}/run_sphinx_build.sh + @ONLY) + + IF(UNIX) + EXECUTE_PROCESS(COMMAND chmod +x ${DOCUMENTATION_DIR}/run_sphinx_build.sh OUTPUT_QUIET) + EXECUTE_PROCESS(COMMAND ${DOCUMENTATION_DIR}/run_sphinx_build.sh OUTPUT_QUIET) + ENDIF(UNIX) + +ENDIF() diff --git a/docs/sphinx/run_sphinx_build.sh.in b/docs/sphinx/run_sphinx_build.sh.in new file mode 100644 index 000000000..ddd4dc2bb --- /dev/null +++ b/docs/sphinx/run_sphinx_build.sh.in @@ -0,0 +1,7 @@ +#!/bin/bash +echo "Creating Sphinx documentation in: @SPHINX_DESTINATION@" + +LD_LIBRARY_PATH="@CMAKE_INSTALL_PREFIX@/lib:$LD_LIBRARY_PATH" + +@SPHINX_EXECUTABLE@ -b html -c @CMAKE_CURRENT_BINARY_DIR@/ @SPHINX_SOURCE_DIR@/source @DOCUMENTATION_DIR@/html +@SPHINX_EXECUTABLE@ -b man -c @CMAKE_CURRENT_BINARY_DIR@/ @SPHINX_SOURCE_DIR@/source @DOCUMENTATION_DIR@/man \ No newline at end of file diff --git a/docs/sphinx/source/conf.py.in b/docs/sphinx/source/conf.py.in new file mode 100644 index 000000000..218ef8b6d --- /dev/null +++ b/docs/sphinx/source/conf.py.in @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# +# OpenMW documentation build configuration file, created by +# sphinx-quickstart on Wed May 14 15:16:35 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('@CMAKE_SOURCE_DIR@')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', + 'breathe', +] + +# Where breathe can find the source files +breathe_projects_source = { + "openmw": ("@CMAKE_SOURCE_DIR@/apps/openmw", ["engine.hpp", + "mwbase/dialoguemanager.hpp", "mwbase/environment.hpp", + "mwbase/inputmanager.hpp", "mwbase/journal.hpp", "mwbase/mechanicsmanager.hpp", + "mwbase/scriptmanager.hpp", "mwbase/soundmanager.hpp", "mwbase/statemanager.hpp", + "mwbase/windowmanager.hpp", "mwbase/world.hpp"]) + } + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'OpenMW' +copyright = u'2016, OpenMW Team' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '@OPENMW_VERSION@' +# The full version, including alpha/beta/rc tags. +release = '@OPENMW_VERSION@' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +primary_domain = 'c' + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'OpenMWdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'OpenMW.tex', u'OpenMW Documentation', + u'Bret Curtis', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'openmw', u'OpenMW Documentation', + [u'Bret Curtis'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'OpenMW', u'OpenMW Documentation', + u'Bret Curtis', 'OpenMW', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst new file mode 100644 index 000000000..64c3c9796 --- /dev/null +++ b/docs/sphinx/source/index.rst @@ -0,0 +1,19 @@ + +Welcome to OpenMW's documentation! +===================================== + +Components +---------- + +.. toctree:: + :maxdepth: 2 + + openmw + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` + diff --git a/docs/sphinx/source/mwbase.rst b/docs/sphinx/source/mwbase.rst new file mode 100644 index 000000000..4044fbc97 --- /dev/null +++ b/docs/sphinx/source/mwbase.rst @@ -0,0 +1,33 @@ +openmw/mwbase +============= + +.. autodoxygenfile:: mwbase/dialoguemanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/environment.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/inputmanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/journal.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/mechanicsmanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/scriptmanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/soundmanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/statemanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/windowmanager.hpp + :project: openmw + +.. autodoxygenfile:: mwbase/world.hpp + :project: openmw + diff --git a/docs/sphinx/source/openmw.rst b/docs/sphinx/source/openmw.rst new file mode 100644 index 000000000..2da7caa5f --- /dev/null +++ b/docs/sphinx/source/openmw.rst @@ -0,0 +1,16 @@ +openmw +====== + +.. toctree:: + :maxdepth: 2 + + mwbase + +.. autodoxygenfile:: engine.hpp + :project: openmw + +Indices and tables +================== + +* :ref:`genindex` + * :ref:`search` \ No newline at end of file From 95d2c7ea5ca603548f79c19c8a0dc665aa5c233f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Jul 2016 02:48:57 +0100 Subject: [PATCH 02/46] Attempt to unescape characters when constructing file paths, introducing compilation errors. --- apps/openmw/main.cpp | 4 ++-- components/fallback/validate.hpp | 18 +++++++++++++++++ components/files/configurationmanager.cpp | 24 +++++++++++++++++++++++ components/files/configurationmanager.hpp | 5 +++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index f54905a2c..64b74276e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -76,7 +76,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat desc.add_options() ("help", "print help message") ("version", "print version information and quit") - ("data", bpo::value()->default_value(Files::PathContainer(), "data") + ("data", bpo::value()->default_value(Files::EscapePathContainer(), "data") ->multitoken()->composing(), "set data directories (later directories have higher priority)") ("data-local", bpo::value()->default_value(""), @@ -193,7 +193,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // directory settings engine.enableFSStrict(variables["fs-strict"].as()); - Files::PathContainer dataDirs(variables["data"].as()); + Files::PathContainer dataDirs(variables["data"].as().mContainer); std::string local(variables["data-local"].as().toStdString()); if (!local.empty()) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index d82ef5770..4f0933e6e 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -4,6 +4,7 @@ #include #include +#include // Parses and validates a fallback map from boost program_options. // Note: for boost to pick up the validate function, you need to pull in the namespace e.g. @@ -66,6 +67,23 @@ namespace Files { for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) eSV->mVector.push_back(EscapeHashString(*it)); } + + struct EscapePathContainer { + PathContainer mContainer; + }; + + std::istream & operator>> (std::istream & istream, EscapePathContainer & escapePathContainer) + { + std::cout << "The new dodgy operator>> is being used" << std::endl; + + boost::iostreams::filtering_istream filteredStream; + filteredStream.push(unescape_hash_filter()); + filteredStream.push(istream); + + filteredStream >> escapePathContainer.mContainer; + + return istream; + } } #endif diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 3a7f57949..bbac62731 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -237,6 +237,30 @@ int escape_hash_filter::get(Source & src) return retval; } +template +int unescape_hash_filter::get(Source & src) +{ + int character = boost::iostreams::get(src); + if (character == escape_hash_filter::sEscape) + { + int nextChar = boost::iostreams::get(src); + switch (nextChar) + { + case escape_hash_filter::sEscapeIdentifier: + return escape_hash_filter::sEscape; + break; + case escape_hash_filter::sHashIdentifier: + return '#'; + break; + default: + return '?'; + break; + } + } + else + return character; +} + std::string EscapeHashString::processString(const std::string & str) { std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 3ce995983..d31ac1ecd 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -88,6 +88,11 @@ struct escape_hash_filter : public boost::iostreams::input_filter bool mFinishLine; }; +struct unescape_hash_filter : public boost::iostreams::input_filter +{ + template int get(Source & src); +}; + /** * \class EscapeHashString */ From 40297701d034b3383a72159f8dbdb9893004353a Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Thu, 7 Jul 2016 23:45:02 -0400 Subject: [PATCH 03/46] Base key config/shortcut implementation --- apps/opencs/CMakeLists.txt | 7 +- apps/opencs/model/prefs/shortcut.cpp | 139 +++++++++++++ apps/opencs/model/prefs/shortcut.hpp | 71 +++++++ apps/opencs/model/prefs/shortcutmanager.cpp | 197 +++++++++++++++++++ apps/opencs/model/prefs/shortcutmanager.hpp | 51 +++++ apps/opencs/model/prefs/shortcutsetting.cpp | 43 ++++ apps/opencs/model/prefs/shortcutsetting.hpp | 30 +++ apps/opencs/model/prefs/state.cpp | 41 +++- apps/opencs/model/prefs/state.hpp | 7 + apps/opencs/view/render/cameracontroller.cpp | 110 +++++++---- apps/opencs/view/render/cameracontroller.hpp | 26 ++- apps/opencs/view/render/scenewidget.cpp | 72 ++++++- apps/opencs/view/render/scenewidget.hpp | 5 + 13 files changed, 750 insertions(+), 49 deletions(-) create mode 100644 apps/opencs/model/prefs/shortcut.cpp create mode 100644 apps/opencs/model/prefs/shortcut.hpp create mode 100644 apps/opencs/model/prefs/shortcutmanager.cpp create mode 100644 apps/opencs/model/prefs/shortcutmanager.hpp create mode 100644 apps/opencs/model/prefs/shortcutsetting.cpp create mode 100644 apps/opencs/model/prefs/shortcutsetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f8cf1e2d8..d95317aaf 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -86,12 +86,12 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode - orbitcameramode pathgridmode selectionmode pathgridselectionmode + orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller ) opencs_units_noqt (view/render lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase - cellarrow cellmarker cellborder cameracontroller pathgrid + cellarrow cellmarker cellborder pathgrid ) opencs_hdrs_noqt (view/render @@ -112,7 +112,8 @@ opencs_units (view/prefs ) opencs_units (model/prefs - state setting intsetting doublesetting boolsetting enumsetting coloursetting + state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut + shortcutmanager shortcutsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp new file mode 100644 index 000000000..f691cede9 --- /dev/null +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -0,0 +1,139 @@ +#include "shortcut.hpp" + +#include +#include +#include + +#include "state.hpp" +#include "shortcutmanager.hpp" + +namespace CSMPrefs +{ + Shortcut::Shortcut(const std::string& name, QObject* parent) + : QObject(parent) + , mName(name) + , mCurrentPos(0) + , mLastPos(0) + { + State::get().getShortcutManager().addShortcut(this); + setSequence(State::get().getShortcutManager().getSequence(name)); + } + + Shortcut::~Shortcut() + { + State::get().getShortcutManager().removeShortcut(this); + } + + const std::string& Shortcut::getName() const + { + return mName; + } + + const QKeySequence& Shortcut::getSequence() const + { + return mSequence; + } + + void Shortcut::setSequence(const QKeySequence& sequence) + { + mSequence = sequence; + mCurrentPos = 0; + mLastPos = sequence.count() - 1; + } + + void Shortcut::keyPressEvent(QKeyEvent* event) + { + int withMod = event->key() | event->modifiers(); + int noMod = event->key(); + + if (withMod == mSequence[mCurrentPos] || (mCurrentPos > 0 && noMod == mSequence[mCurrentPos])) + { + if (mCurrentPos == mLastPos) + { + activated(true); + } + else + ++mCurrentPos; + } + } + + void Shortcut::keyReleaseEvent(QKeyEvent* event) + { + const int KeyMask = 0x01FFFFFF; + + if ((mSequence[mCurrentPos] & KeyMask) == event->key()) + { + if (mCurrentPos == mLastPos) + { + activated(false); + mCurrentPos = 0; // Resets to start, maybe shouldn't? + } + else if (mCurrentPos > 0) + { + --mCurrentPos; + } + } + } + + void Shortcut::mousePressEvent(QMouseEvent* event) + { + int withMod = event->button() | (int)event->modifiers(); + int noMod = event->button(); + + if (withMod == mSequence[mCurrentPos] || (mCurrentPos > 0 && noMod == mSequence[mCurrentPos])) + { + if (mCurrentPos == mLastPos) + activated(true); + else + ++mCurrentPos; + } + } + + void Shortcut::mouseReleaseEvent(QMouseEvent* event) + { + const int MouseMask = 0x0000001F; + + if ((mSequence[mCurrentPos] & MouseMask) == event->button()) + { + if (mCurrentPos == mLastPos) + { + activated(false); + mCurrentPos = 0; + } + else if (mCurrentPos > 0) + { + --mCurrentPos; + } + } + } + + QShortcutWrapper::QShortcutWrapper(const std::string& name, QShortcut* shortcut) + : QObject(shortcut) + , mName(name) + , mShortcut(shortcut) + { + State::get().getShortcutManager().addShortcut(this); + setSequence(State::get().getShortcutManager().getSequence(name)); + } + + QShortcutWrapper::~QShortcutWrapper() + { + State::get().getShortcutManager().removeShortcut(this); + } + + const std::string& QShortcutWrapper::getName() const + { + return mName; + } + + const QKeySequence& QShortcutWrapper::getSequence() const + { + return mSequence; + } + + void QShortcutWrapper::setSequence(const QKeySequence& sequence) + { + mSequence = sequence; + mShortcut->setKey(sequence); + } +} diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp new file mode 100644 index 000000000..b121c0610 --- /dev/null +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -0,0 +1,71 @@ +#ifndef CSM_PREFS_SHORTCUT_H +#define CSM_PREFS_SHORTCUT_H + +#include +#include + +class QKeyEvent; +class QMouseEvent; +class QShortcut; + +namespace CSMPrefs +{ + /// A class similar in purpose to QShortcut, but with the ability to use mouse buttons + class Shortcut : public QObject + { + Q_OBJECT + + public: + + Shortcut(const std::string& name, QObject* parent); + ~Shortcut(); + + const std::string& getName() const; + const QKeySequence& getSequence() const; + + void setSequence(const QKeySequence& sequence); + + private: + + std::string mName; + QKeySequence mSequence; + int mCurrentPos; + int mLastPos; + + public slots: + + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + + signals: + + /// Triggered when the shortcut is activated or deactived; can be determined from \p active + void activated(bool active); + }; + + /// Wraps a QShortcut object so that the sequence can be modified by the settings + class QShortcutWrapper : public QObject + { + Q_OBJECT + + public: + + QShortcutWrapper(const std::string& name, QShortcut* shortcut); + ~QShortcutWrapper(); + + const std::string& getName() const; + const QKeySequence& getSequence() const; + + void setSequence(const QKeySequence& sequence); + + private: + + std::string mName; + QKeySequence mSequence; + QShortcut* mShortcut; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp new file mode 100644 index 000000000..3e81a5e3d --- /dev/null +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -0,0 +1,197 @@ +#include "shortcutmanager.hpp" + +#include +#include + +#include + +#include "shortcut.hpp" + +namespace CSMPrefs +{ + void ShortcutManager::addShortcut(Shortcut* shortcut) + { + mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut)); + } + + void ShortcutManager::addShortcut(QShortcutWrapper* wrapper) + { + mShortcutWrappers.insert(std::make_pair(wrapper->getName(), wrapper)); + } + + void ShortcutManager::removeShortcut(Shortcut* shortcut) + { + std::pair range = mShortcuts.equal_range(shortcut->getName()); + + for (ShortcutMap::iterator it = range.first; it != range.second;) + { + if (it->second == shortcut) + { + it = mShortcuts.erase(it); + } + else + { + ++it; + } + } + } + + void ShortcutManager::removeShortcut(QShortcutWrapper* wrapper) + { + std::pair range = mShortcutWrappers.equal_range( + wrapper->getName()); + + for (ShortcutWrapperMap::iterator it = range.first; it != range.second;) + { + if (it->second == wrapper) + { + it = mShortcutWrappers.erase(it); + } + else + { + ++it; + } + } + } + + QKeySequence ShortcutManager::getSequence(const std::string& name) const + { + QKeySequence sequence; + SequenceMap::const_iterator item = mSequences.find(name); + + if (item != mSequences.end()) + { + sequence = item->second; + } + + return sequence; + } + + void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence) + { + // Add to map/modify + SequenceMap::iterator item = mSequences.find(name); + + if (item != mSequences.end()) + { + item->second = sequence; + } + else + { + mSequences.insert(std::make_pair(name, sequence)); + } + + // Change active shortcuts + std::pair rangeS = mShortcuts.equal_range(name); + std::pair rangeW = mShortcutWrappers.equal_range(name); + + for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) + { + it->second->setSequence(sequence); + } + + for (ShortcutWrapperMap::iterator it = rangeW.first; it != rangeW.second; ++it) + { + it->second->setSequence(sequence); + } + } + + std::string ShortcutManager::sequenceToString(const QKeySequence& seq) + { + const int MouseMask = 0x0000001F; // Conflicts with key + const int KeyMask = 0x01FFFFFF; + const int ModMask = 0x7E000000; + + const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); + const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); + + std::string output; + + for (int i = 0; i < seq.count(); ++i) + { + if (seq[i] & ModMask) + { + // TODO separate out modifiers to allow more than 1 + output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(seq[i] & ModMask)); + output.append("+"); + } + + if (seq[i] & KeyMask & ~MouseMask) + { + // Is a key + output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(seq[i] & KeyMask)); + output.append(","); + } + else if (seq[i] & MouseMask) + { + std::stringstream ss; + std::string num; + + unsigned int value = (unsigned int)(seq[i] & MouseMask); + + // value will never be 0 + int exponent = 1; // Offset by 1 + while (value >>= 1) + ++exponent; + + ss << exponent; + ss >> num; + + // Is a mouse button + output.append("Mouse"); + output.append(num); + output.append(","); + } + } + + // Remove last comma + if (output.size() > 0) + { + output.resize(output.size() - 1); + } + + return output; + } + + QKeySequence ShortcutManager::stringToSequence(const std::string& input) + { + const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); + const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); + + int keys[4] = { 0, 0, 0, 0 }; + + QRegExp splitRX("[, ]"); + QStringList keyStrs = QString(input.c_str()).split(splitRX, QString::SkipEmptyParts); + + for (int i = 0; i < keyStrs.size(); ++i) + { + QRegExp modSeparator("[+]"); + + QStringList separatedList = keyStrs[i].split(modSeparator, QString::SkipEmptyParts); + for (int j = 0; j < separatedList.size(); ++j) + { + if (separatedList[j].startsWith("Mouse")) + { + QString num = separatedList[j].mid(5); + if (num > 0) + { + keys[i] |= 1 << (num.toInt() - 1); // offset by 1 + } + } + else if (staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(separatedList[j].toUtf8().data()) != -1) + { + keys[i] |= staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(separatedList[j].toUtf8().data()); + } + else if (staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(separatedList[j].toUtf8().data()) != -1) + { + keys[i] |= staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(separatedList[j].toUtf8().data()); + } + } + } + + // TODO remove + std::cout << input << '.' << keys[0] << '.'<< keys[1] << '.'<< keys[2] << '.'<< keys[3] << std::endl; + + return QKeySequence(keys[0], keys[1], keys[2], keys[3]); + } +} diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp new file mode 100644 index 000000000..f2534347a --- /dev/null +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -0,0 +1,51 @@ +#ifndef CSM_PREFS_SHORTCUTMANAGER_H +#define CSM_PREFS_SHORTCUTMANAGER_H + +#include + +#include +#include + +namespace CSMPrefs +{ + class Shortcut; + class QShortcutWrapper; + + /// Class used to track and update shortcuts/sequences + class ShortcutManager : public QObject + { + Q_OBJECT + + public: + + /// The shortcut class will do this automatically + void addShortcut(Shortcut* shortcut); + /// The wrapper class will do this automatically + void addShortcut(QShortcutWrapper* wrapper); + + /// The shortcut class will do this automatically + void removeShortcut(Shortcut* shortcut); + /// The wrapper class will do this automatically + void removeShortcut(QShortcutWrapper* wrapper); + + QKeySequence getSequence(const std::string& name) const; + void setSequence(const std::string& name, const QKeySequence& sequence); + + std::string sequenceToString(const QKeySequence& sequence); + QKeySequence stringToSequence(const std::string& str); + + private: + + // Need a multimap in case multiple shortcuts share the same name + typedef std::multimap ShortcutMap; + typedef std::multimap ShortcutWrapperMap; + + typedef std::map SequenceMap; + + ShortcutMap mShortcuts; + ShortcutWrapperMap mShortcutWrappers; + SequenceMap mSequences; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp new file mode 100644 index 000000000..5b2008241 --- /dev/null +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -0,0 +1,43 @@ +#include "shortcutsetting.hpp" + +#include +#include +#include + +#include "state.hpp" +#include "shortcutmanager.hpp" + +namespace CSMPrefs +{ + ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, + const std::string& label, const QKeySequence& default_) + : Setting(parent, values, mutex, key, label) + , mDefault(default_) + { + State::get().getShortcutManager().setSequence(key, mDefault); + } + + std::pair ShortcutSetting::makeWidgets(QWidget* parent) + { + QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent); + QLineEdit* widget = new QLineEdit(State::get().getShortcutManager().sequenceToString(mDefault).c_str(), parent); + + connect(widget, SIGNAL(textChanged(const QString&)), this, SLOT(valueChanged(const QString&))); + + return std::make_pair(label, widget); + } + + void ShortcutSetting::valueChanged(const QString& text) + { + { + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), text.toUtf8().data()); + + QKeySequence sequence = State::get().getShortcutManager().stringToSequence(text.toUtf8().data()); + + State::get().getShortcutManager().setSequence(getKey(), sequence); + } + + getParent()->getState()->update(*this); + } +} diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp new file mode 100644 index 000000000..893b01f93 --- /dev/null +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -0,0 +1,30 @@ +#ifndef CSM_PREFS_SHORTCUTSETTING_H +#define CSM_PREFS_SHORTCUTSETTING_H + +#include + +#include "setting.hpp" + +namespace CSMPrefs +{ + class ShortcutSetting : public Setting + { + Q_OBJECT + + QKeySequence mDefault; + + public: + + ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, + const std::string& label, const QKeySequence& default_); + + // TODO replace with custom page + virtual std::pair makeWidgets(QWidget* parent); + + private slots: + + void valueChanged(const QString& text); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c70e71deb..f2a0b31e1 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -5,10 +5,13 @@ #include #include +#include + #include "intsetting.hpp" #include "doublesetting.hpp" #include "boolsetting.hpp" #include "coloursetting.hpp" +#include "shortcutsetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -224,6 +227,15 @@ void CSMPrefs::State::declare() addValues (insertOutsideCell); declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert). addValues (insertOutsideVisibleCell); + + declareCategory ("Key Bindings"); + declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W)); + declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); + declareShortcut ("free-left", "Free camera left", QKeySequence(Qt::Key_A)); + declareShortcut ("free-right", "Free camera right", QKeySequence(Qt::Key_D)); + declareShortcut ("free-roll-left", "Free camera roll left", QKeySequence(Qt::Key_Q)); + declareShortcut ("free-roll-right", "Free camera roll right", QKeySequence(Qt::Key_E)); + declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -340,6 +352,26 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, return *setting; } +CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label, + const QKeySequence& default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + std::string seqStr = getShortcutManager().sequenceToString(default_); + setDefault (key, seqStr); + + QKeySequence seq = getShortcutManager().stringToSequence(mSettings.getString(key, + mCurrentCategory->second.getKey())); + + CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, + key, label, seq); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::declareSeparator() { if (mCurrentCategory==mCategories.end()) @@ -369,10 +401,10 @@ CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) if (sThis) throw std::logic_error ("An instance of CSMPRefs::State already exists"); + sThis = this; + load(); declare(); - - sThis = this; } CSMPrefs::State::~State() @@ -396,6 +428,11 @@ CSMPrefs::State::Iterator CSMPrefs::State::end() return mCategories.end(); } +CSMPrefs::ShortcutManager& CSMPrefs::State::getShortcutManager() +{ + return mShortcutManager; +} + CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key) { Iterator iter = mCategories.find (key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index fffadee5e..15f6e6d1b 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -16,6 +16,7 @@ #include "category.hpp" #include "setting.hpp" #include "enumsetting.hpp" +#include "shortcutmanager.hpp" class QColor; @@ -25,6 +26,7 @@ namespace CSMPrefs class DoubleSetting; class BoolSetting; class ColourSetting; + class ShortcutSetting; /// \brief User settings state /// @@ -45,6 +47,7 @@ namespace CSMPrefs const std::string mConfigFile; const Files::ConfigurationManager& mConfigurationManager; + ShortcutManager mShortcutManager; Settings::Manager mSettings; Collection mCategories; Iterator mCurrentCategory; @@ -71,6 +74,8 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); + ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, const QKeySequence& default_); + void declareSeparator(); void setDefault (const std::string& key, const std::string& default_); @@ -87,6 +92,8 @@ namespace CSMPrefs Iterator end(); + ShortcutManager& getShortcutManager(); + Category& operator[](const std::string& key); void update (const Setting& setting); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index dc356827a..ec78db011 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -14,6 +14,10 @@ #include +#include "../../model/prefs/shortcut.hpp" + +#include "scenewidget.hpp" + namespace CSVRender { @@ -140,7 +144,7 @@ namespace CSVRender Free Camera Controller */ - FreeCameraController::FreeCameraController() + FreeCameraController::FreeCameraController(SceneWidget* scene) : mLockUpright(false) , mModified(false) , mFast(false) @@ -155,6 +159,33 @@ namespace CSVRender , mRotSpeed(osg::PI / 2) , mSpeedMult(8) { + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", this); + scene->addShortcut(forwardShortcut); + connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); + + CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", this); + scene->addShortcut(leftShortcut); + connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool))); + + CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", this); + scene->addShortcut(backShortcut); + connect(backShortcut, SIGNAL(activated(bool)), this, SLOT(backward(bool))); + + CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", this); + scene->addShortcut(rightShortcut); + connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool))); + + CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", this); + scene->addShortcut(rollLeftShortcut); + connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool))); + + CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", this); + scene->addShortcut(rollRightShortcut); + connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool))); + + CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", this); + scene->addShortcut(speedModeShortcut); + connect(speedModeShortcut, SIGNAL(activated(bool)), this, SLOT(swapSpeedMode(bool))); } double FreeCameraController::getLinearSpeed() const @@ -204,39 +235,6 @@ namespace CSVRender if (!isActive()) return false; - if (event->key() == Qt::Key_Q) - { - mRollLeft = pressed; - } - else if (event->key() == Qt::Key_E) - { - mRollRight = pressed; - } - else if (event->key() == Qt::Key_A) - { - mLeft = pressed; - } - else if (event->key() == Qt::Key_D) - { - mRight = pressed; - } - else if (event->key() == Qt::Key_W) - { - mForward = pressed; - } - else if (event->key() == Qt::Key_S) - { - mBackward = pressed; - } - else if (event->key() == Qt::Key_Shift) - { - mFast = pressed; - } - else - { - return false; - } - return true; } @@ -368,11 +366,53 @@ namespace CSVRender getCamera()->setViewMatrixAsLookAt(eye, center, mUp); } + void FreeCameraController::forward(bool active) + { + if (isActive()) + mForward = active; + } + + void FreeCameraController::left(bool active) + { + if (isActive()) + mLeft = active; + } + + void FreeCameraController::backward(bool active) + { + if (isActive()) + mBackward = active; + } + + void FreeCameraController::right(bool active) + { + if (isActive()) + mRight = active; + } + + void FreeCameraController::rollLeft(bool active) + { + if (isActive()) + mRollLeft = active; + } + + void FreeCameraController::rollRight(bool active) + { + if (isActive()) + mRollRight = active; + } + + void FreeCameraController::swapSpeedMode(bool active) + { + if (isActive() && active) + mFast = !mFast; + } + /* Orbit Camera Controller */ - OrbitCameraController::OrbitCameraController() + OrbitCameraController::OrbitCameraController(SceneWidget* widget) : mInitialized(false) , mFast(false) , mLeft(false) diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index f9021f04b..2131e1f02 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include @@ -16,8 +18,12 @@ namespace osg namespace CSVRender { - class CameraController + class SceneWidget; + + class CameraController : public QObject { + Q_OBJECT + public: static const osg::Vec3d WorldUp; @@ -69,9 +75,11 @@ namespace CSVRender class FreeCameraController : public CameraController { + Q_OBJECT + public: - FreeCameraController(); + FreeCameraController(SceneWidget* widget); double getLinearSpeed() const; double getRotationalSpeed() const; @@ -107,13 +115,25 @@ namespace CSVRender double mLinSpeed; double mRotSpeed; double mSpeedMult; + + private slots: + + void forward(bool active); + void left(bool active); + void backward(bool active); + void right(bool active); + void rollLeft(bool active); + void rollRight(bool active); + void swapSpeedMode(bool active); }; class OrbitCameraController : public CameraController { + Q_OBJECT + public: - OrbitCameraController(); + OrbitCameraController(SceneWidget* widget); osg::Vec3d getCenter() const; double getOrbitSpeed() const; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index b2b5b30d6..48fe4abdc 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -19,6 +19,7 @@ #include "../widget/scenetoolmode.hpp" #include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcut.hpp" #include "lighting.hpp" #include "mask.hpp" @@ -158,11 +159,15 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys , mHasDefaultAmbient(false) , mPrevMouseX(0) , mPrevMouseY(0) - , mFreeCamControl(new FreeCameraController()) - , mOrbitCamControl(new OrbitCameraController()) - , mCurrentCamControl(mFreeCamControl.get()) + , mFreeCamControl(0) + , mOrbitCamControl(0) + , mCurrentCamControl(0) , mCamPositionSet(false) { + mFreeCamControl.reset(new FreeCameraController(this)); + mOrbitCamControl.reset(new OrbitCameraController(this)); + mCurrentCamControl = mFreeCamControl.get(); + mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); selectNavigationMode("free"); @@ -175,11 +180,11 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys // Recieve mouse move event even if mouse button is not pressed setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); + setFocusPolicy(Qt::ClickFocus); /// \todo make shortcut configurable - QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); - connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); + //QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); + //connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), this, SLOT (settingChanged (const CSMPrefs::Setting *))); @@ -271,17 +276,57 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); } +bool SceneWidget::event(QEvent *event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + SceneWidget::keyPressEvent(keyEvent); + } + else if (event->type() == QEvent::KeyRelease) + { + QKeyEvent* keyEvent = static_cast(event); + SceneWidget::keyReleaseEvent(keyEvent); + } + else if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* keyEvent = static_cast(event); + SceneWidget::mousePressEvent(keyEvent); + } + else if (event->type() == QEvent::MouseButtonRelease) + { + QMouseEvent* keyEvent = static_cast(event); + SceneWidget::mouseReleaseEvent(keyEvent); + } + else + { + return RenderWidget::event(event); + } + + return true; +} + void SceneWidget::mousePressEvent (QMouseEvent *event) { mMouseMode = mapButton(event); mPrevMouseX = event->x(); mPrevMouseY = event->y(); + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->mousePressEvent(event); + } } void SceneWidget::mouseReleaseEvent (QMouseEvent *event) { mMouseMode = ""; + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->mouseReleaseEvent(event); + } } void SceneWidget::mouseMoveEvent (QMouseEvent *event) @@ -305,11 +350,21 @@ void SceneWidget::wheelEvent(QWheelEvent *event) void SceneWidget::keyPressEvent (QKeyEvent *event) { mCurrentCamControl->handleKeyEvent(event, true); + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->keyPressEvent(event); + } } void SceneWidget::keyReleaseEvent (QKeyEvent *event) { mCurrentCamControl->handleKeyEvent(event, false); + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->keyReleaseEvent(event); + } } void SceneWidget::update(double dt) @@ -453,4 +508,9 @@ std::string SceneWidget::mapButton (QMouseEvent *event) return ""; } +void SceneWidget::addShortcut(CSMPrefs::Shortcut* shortcut) +{ + mShortcuts.push_back(shortcut); +} + } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 4df49543a..0744cc645 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -36,6 +36,7 @@ namespace CSVWidget namespace CSMPrefs { class Setting; + class Shortcut; } namespace CSVRender @@ -84,12 +85,15 @@ namespace CSVRender void setDefaultAmbient (const osg::Vec4f& colour); ///< \note The actual ambient colour may differ based on lighting settings. + void addShortcut(CSMPrefs::Shortcut* shortcut); + protected: void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. void setAmbient(const osg::Vec4f& ambient); + virtual bool event(QEvent *event); virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseMoveEvent (QMouseEvent *event); @@ -120,6 +124,7 @@ namespace CSVRender CameraController* mCurrentCamControl; std::map, std::string> mButtonMapping; + std::vector mShortcuts; private: bool mCamPositionSet; From 3fa4fdb8390509447b8b8c285094e876d269648d Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 15 Jul 2016 23:26:47 -0400 Subject: [PATCH 04/46] Remove use of c++11 feature and add some missing headers. --- apps/opencs/model/prefs/shortcutmanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 3e81a5e3d..740179b25 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include "shortcut.hpp" @@ -27,7 +29,7 @@ namespace CSMPrefs { if (it->second == shortcut) { - it = mShortcuts.erase(it); + mShortcuts.erase(it++); } else { @@ -45,7 +47,7 @@ namespace CSMPrefs { if (it->second == wrapper) { - it = mShortcutWrappers.erase(it); + mShortcutWrappers.erase(it++); } else { From e8626e588a9a761df8688a0190897506d7e3a987 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 17 Jul 2016 19:32:35 -0400 Subject: [PATCH 05/46] Changes in shortcut design. - Handle input in centralized class for potential conflict resolution. - Remove wrapper class for QShortcut; it should be unnecessary. - Added customizable shortcut usage to orbit camera mode. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/shortcut.cpp | 108 +++-------- apps/opencs/model/prefs/shortcut.hpp | 52 +++--- .../model/prefs/shortcuteventhandler.cpp | 171 +++++++++++++++++ .../model/prefs/shortcuteventhandler.hpp | 54 ++++++ apps/opencs/model/prefs/shortcutmanager.cpp | 29 --- apps/opencs/model/prefs/shortcutmanager.hpp | 8 - apps/opencs/model/prefs/state.cpp | 9 + apps/opencs/view/render/cameracontroller.cpp | 172 +++++++++++------- apps/opencs/view/render/cameracontroller.hpp | 22 ++- apps/opencs/view/render/scenewidget.cpp | 78 +------- apps/opencs/view/render/scenewidget.hpp | 13 +- 12 files changed, 428 insertions(+), 290 deletions(-) create mode 100644 apps/opencs/model/prefs/shortcuteventhandler.cpp create mode 100644 apps/opencs/model/prefs/shortcuteventhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d95317aaf..266a9c250 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -113,7 +113,7 @@ opencs_units (view/prefs opencs_units (model/prefs state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut - shortcutmanager shortcutsetting + shortcuteventhandler shortcutmanager shortcutsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index f691cede9..b8820ae8b 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -14,6 +14,8 @@ namespace CSMPrefs , mName(name) , mCurrentPos(0) , mLastPos(0) + , mActive(false) + , mEnabled(true) { State::get().getShortcutManager().addShortcut(this); setSequence(State::get().getShortcutManager().getSequence(name)); @@ -24,116 +26,64 @@ namespace CSMPrefs State::get().getShortcutManager().removeShortcut(this); } - const std::string& Shortcut::getName() const + bool Shortcut::isActive() const { - return mName; + return mActive; } - const QKeySequence& Shortcut::getSequence() const + bool Shortcut::isEnabled() const { - return mSequence; + return mEnabled; } - void Shortcut::setSequence(const QKeySequence& sequence) + const std::string& Shortcut::getName() const { - mSequence = sequence; - mCurrentPos = 0; - mLastPos = sequence.count() - 1; + return mName; } - void Shortcut::keyPressEvent(QKeyEvent* event) + const QKeySequence& Shortcut::getSequence() const { - int withMod = event->key() | event->modifiers(); - int noMod = event->key(); - - if (withMod == mSequence[mCurrentPos] || (mCurrentPos > 0 && noMod == mSequence[mCurrentPos])) - { - if (mCurrentPos == mLastPos) - { - activated(true); - } - else - ++mCurrentPos; - } + return mSequence; } - void Shortcut::keyReleaseEvent(QKeyEvent* event) + int Shortcut::getPosition() const { - const int KeyMask = 0x01FFFFFF; - - if ((mSequence[mCurrentPos] & KeyMask) == event->key()) - { - if (mCurrentPos == mLastPos) - { - activated(false); - mCurrentPos = 0; // Resets to start, maybe shouldn't? - } - else if (mCurrentPos > 0) - { - --mCurrentPos; - } - } + return mCurrentPos; } - void Shortcut::mousePressEvent(QMouseEvent* event) + int Shortcut::getLastPosition() const { - int withMod = event->button() | (int)event->modifiers(); - int noMod = event->button(); - - if (withMod == mSequence[mCurrentPos] || (mCurrentPos > 0 && noMod == mSequence[mCurrentPos])) - { - if (mCurrentPos == mLastPos) - activated(true); - else - ++mCurrentPos; - } + return mLastPos; } - void Shortcut::mouseReleaseEvent(QMouseEvent* event) + void Shortcut::setPosition(int pos) { - const int MouseMask = 0x0000001F; - - if ((mSequence[mCurrentPos] & MouseMask) == event->button()) - { - if (mCurrentPos == mLastPos) - { - activated(false); - mCurrentPos = 0; - } - else if (mCurrentPos > 0) - { - --mCurrentPos; - } - } + mCurrentPos = pos; } - QShortcutWrapper::QShortcutWrapper(const std::string& name, QShortcut* shortcut) - : QObject(shortcut) - , mName(name) - , mShortcut(shortcut) + void Shortcut::setSequence(const QKeySequence& sequence) { - State::get().getShortcutManager().addShortcut(this); - setSequence(State::get().getShortcutManager().getSequence(name)); + mSequence = sequence; + mCurrentPos = 0; + mLastPos = sequence.count() - 1; } - QShortcutWrapper::~QShortcutWrapper() + void Shortcut::activate(bool state) { - State::get().getShortcutManager().removeShortcut(this); - } + mActive = state; + emit activated(state); - const std::string& QShortcutWrapper::getName() const - { - return mName; + if (state) + emit activated(); } - const QKeySequence& QShortcutWrapper::getSequence() const + void Shortcut::enable(bool state) { - return mSequence; + mEnabled = state; } - void QShortcutWrapper::setSequence(const QKeySequence& sequence) + QString Shortcut::toString() const { - mSequence = sequence; - mShortcut->setKey(sequence); + return QString(State::get().getShortcutManager().sequenceToString(mSequence).data()); } } diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index b121c0610..25bb13556 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -1,8 +1,11 @@ #ifndef CSM_PREFS_SHORTCUT_H #define CSM_PREFS_SHORTCUT_H +#include + #include #include +#include class QKeyEvent; class QMouseEvent; @@ -20,10 +23,24 @@ namespace CSMPrefs Shortcut(const std::string& name, QObject* parent); ~Shortcut(); + bool isActive() const; + bool isEnabled() const; + const std::string& getName() const; const QKeySequence& getSequence() const; + /// The position in the sequence + int getPosition() const; + /// The position in the sequence + int getLastPosition() const; void setSequence(const QKeySequence& sequence); + /// The position in the sequence + void setPosition(int pos); + + void activate(bool state); + void enable(bool state); + + QString toString() const; private: @@ -32,39 +49,16 @@ namespace CSMPrefs int mCurrentPos; int mLastPos; - public slots: - - void keyPressEvent(QKeyEvent* event); - void keyReleaseEvent(QKeyEvent* event); - void mousePressEvent(QMouseEvent* event); - void mouseReleaseEvent(QMouseEvent* event); + bool mActive; + bool mEnabled; signals: - /// Triggered when the shortcut is activated or deactived; can be determined from \p active - void activated(bool active); - }; - - /// Wraps a QShortcut object so that the sequence can be modified by the settings - class QShortcutWrapper : public QObject - { - Q_OBJECT - - public: + /// Triggered when the shortcut is activated or deactived; can be determined from \p state + void activated(bool state); - QShortcutWrapper(const std::string& name, QShortcut* shortcut); - ~QShortcutWrapper(); - - const std::string& getName() const; - const QKeySequence& getSequence() const; - - void setSequence(const QKeySequence& sequence); - - private: - - std::string mName; - QKeySequence mSequence; - QShortcut* mShortcut; + /// Trigger when activated; convenience signal. + void activated(); }; } diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp new file mode 100644 index 000000000..49b13ff99 --- /dev/null +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -0,0 +1,171 @@ +#include "shortcuteventhandler.hpp" + +#include +#include + +#include +#include +#include +#include + +#include "shortcut.hpp" + +namespace CSMPrefs +{ + ShortcutEventHandler::ShortcutEventHandler(QObject* parent) + : QObject(parent) + { + } + + void ShortcutEventHandler::addShortcut(Shortcut* shortcut) + { + mShortcuts.push_back(shortcut); + } + + void ShortcutEventHandler::removeShortcut(Shortcut* shortcut) + { + std::remove(mShortcuts.begin(), mShortcuts.end(), shortcut); + } + + bool ShortcutEventHandler::eventFilter(QObject* watched, QEvent* event) + { + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + unsigned int mod = (unsigned int) keyEvent->modifiers(); + unsigned int key = (unsigned int) keyEvent->key(); + + if (!keyEvent->isAutoRepeat()) + return activate(mod, key); + } + else if (event->type() == QEvent::KeyRelease) + { + QKeyEvent* keyEvent = static_cast(event); + unsigned int key = (unsigned int) keyEvent->key(); + + if (!keyEvent->isAutoRepeat()) + return deactivate(key); + } + else if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* mouseEvent = static_cast(event); + unsigned int mod = (unsigned int) mouseEvent->modifiers(); + unsigned int button = (unsigned int) mouseEvent->button(); + + return activate(mod, button); + } + else if (event->type() == QEvent::MouseButtonRelease) + { + QMouseEvent* mouseEvent = static_cast(event); + unsigned int button = (unsigned int) mouseEvent->button(); + + return deactivate(button); + } + else if (event->type() == QEvent::FocusOut) + { + // Deactivate in case events are missed + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + Shortcut* shortcut = *it; + + if (shortcut->isActive()) + shortcut->activate(false); + } + } + + return false; + } + + bool ShortcutEventHandler::activate(unsigned int mod, unsigned int button) + { + std::vector > potentials; + bool used = false; + + // Find potential activations + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + Shortcut* shortcut = *it; + int pos = shortcut->getPosition(); + int lastPos = shortcut->getLastPosition(); + MatchResult result = match(mod, button, shortcut->getSequence()[pos]); + + if (!shortcut->isEnabled()) + continue; + + if (result == Matches_WithMod || result == Matches_NoMod) + { + if (pos < lastPos && (result == Matches_WithMod || pos > 0)) + { + shortcut->setPosition(pos+1); + used = true; + } + else if (pos == lastPos) + { + potentials.push_back(std::make_pair(result, shortcut)); + } + } + } + + // Only activate the best match; in exact conflicts, this will favor the first shortcut added. + if (!potentials.empty()) + { + std::sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort); + potentials.front().second->activate(true); + used = true; + } + + return used; + } + + bool ShortcutEventHandler::deactivate(unsigned int button) + { + const int KeyMask = 0x01FFFFFF; + + bool used = false; + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + Shortcut* shortcut = *it; + int pos = shortcut->getPosition(); + MatchResult result = match(0, button, shortcut->getSequence()[pos] & KeyMask); + + if (result != Matches_Not) + { + if (shortcut->isActive()) + shortcut->activate(false); + + shortcut->setPosition(0); + + used = true; + } + } + + return used; + } + + ShortcutEventHandler::MatchResult ShortcutEventHandler::match(unsigned int mod, unsigned int button, + unsigned int value) + { + if ((mod | button) == value) + { + return Matches_WithMod; + } + else if (button == value) + { + return Matches_NoMod; + } + else + { + return Matches_Not; + } + } + + bool ShortcutEventHandler::sort(const std::pair& left, + const std::pair& right) + { + if (left.first == Matches_WithMod && left.first != right.first) + return true; + else + return left.second->getPosition() >= right.second->getPosition(); + } +} diff --git a/apps/opencs/model/prefs/shortcuteventhandler.hpp b/apps/opencs/model/prefs/shortcuteventhandler.hpp new file mode 100644 index 000000000..c1ce48f7e --- /dev/null +++ b/apps/opencs/model/prefs/shortcuteventhandler.hpp @@ -0,0 +1,54 @@ +#ifndef CSM_PREFS_SHORTCUT_EVENT_HANDLER_H +#define CSM_PREFS_SHORTCUT_EVENT_HANDLER_H + +#include + +#include + +class QEvent; +class QWidget; + +namespace CSMPrefs +{ + class Shortcut; + + /// Users of this class should install it as an event handler + class ShortcutEventHandler : public QObject + { + Q_OBJECT + + public: + + ShortcutEventHandler(QObject* parent=0); + + void addShortcut(Shortcut* shortcut); + void removeShortcut(Shortcut* shortcut); + + protected: + + bool eventFilter(QObject* watched, QEvent* event); + + private: + + enum MatchResult + { + Matches_WithMod, + Matches_NoMod, + Matches_Not + }; + + bool activate(unsigned int mod, unsigned int button); + + bool deactivate(unsigned int button); + + MatchResult match(unsigned int mod, unsigned int button, unsigned int value); + + // Prefers Matches_WithMod and a larger number of buttons + static bool sort(const std::pair& left, + const std::pair& right); + + std::vector mShortcuts; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 740179b25..a4b9b1818 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -16,11 +16,6 @@ namespace CSMPrefs mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut)); } - void ShortcutManager::addShortcut(QShortcutWrapper* wrapper) - { - mShortcutWrappers.insert(std::make_pair(wrapper->getName(), wrapper)); - } - void ShortcutManager::removeShortcut(Shortcut* shortcut) { std::pair range = mShortcuts.equal_range(shortcut->getName()); @@ -38,24 +33,6 @@ namespace CSMPrefs } } - void ShortcutManager::removeShortcut(QShortcutWrapper* wrapper) - { - std::pair range = mShortcutWrappers.equal_range( - wrapper->getName()); - - for (ShortcutWrapperMap::iterator it = range.first; it != range.second;) - { - if (it->second == wrapper) - { - mShortcutWrappers.erase(it++); - } - else - { - ++it; - } - } - } - QKeySequence ShortcutManager::getSequence(const std::string& name) const { QKeySequence sequence; @@ -85,17 +62,11 @@ namespace CSMPrefs // Change active shortcuts std::pair rangeS = mShortcuts.equal_range(name); - std::pair rangeW = mShortcutWrappers.equal_range(name); for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) { it->second->setSequence(sequence); } - - for (ShortcutWrapperMap::iterator it = rangeW.first; it != rangeW.second; ++it) - { - it->second->setSequence(sequence); - } } std::string ShortcutManager::sequenceToString(const QKeySequence& seq) diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index f2534347a..2510ec77e 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -9,7 +9,6 @@ namespace CSMPrefs { class Shortcut; - class QShortcutWrapper; /// Class used to track and update shortcuts/sequences class ShortcutManager : public QObject @@ -20,13 +19,9 @@ namespace CSMPrefs /// The shortcut class will do this automatically void addShortcut(Shortcut* shortcut); - /// The wrapper class will do this automatically - void addShortcut(QShortcutWrapper* wrapper); /// The shortcut class will do this automatically void removeShortcut(Shortcut* shortcut); - /// The wrapper class will do this automatically - void removeShortcut(QShortcutWrapper* wrapper); QKeySequence getSequence(const std::string& name) const; void setSequence(const std::string& name, const QKeySequence& sequence); @@ -38,12 +33,9 @@ namespace CSMPrefs // Need a multimap in case multiple shortcuts share the same name typedef std::multimap ShortcutMap; - typedef std::multimap ShortcutWrapperMap; - typedef std::map SequenceMap; ShortcutMap mShortcuts; - ShortcutWrapperMap mShortcutWrappers; SequenceMap mSequences; }; } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index f2a0b31e1..abb5c7f18 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -236,6 +236,15 @@ void CSMPrefs::State::declare() declareShortcut ("free-roll-left", "Free camera roll left", QKeySequence(Qt::Key_Q)); declareShortcut ("free-roll-right", "Free camera roll right", QKeySequence(Qt::Key_E)); declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); + declareSeparator (); + declareShortcut ("orbit-up", "Orbit camera up", QKeySequence(Qt::Key_W)); + declareShortcut ("orbit-down", "Orbit camera down", QKeySequence(Qt::Key_S)); + declareShortcut ("orbit-left", "Orbit camera left", QKeySequence(Qt::Key_A)); + declareShortcut ("orbit-right", "Orbit camera right", QKeySequence(Qt::Key_D)); + declareShortcut ("orbit-roll-left", "Orbit camera roll left", QKeySequence(Qt::Key_Q)); + declareShortcut ("orbit-roll-right", "Orbit camera roll right", QKeySequence(Qt::Key_E)); + declareShortcut ("orbit-speed-mode", "Orbit camera speed mode toggle", QKeySequence(Qt::Key_F)); + declareShortcut ("orbit-center-selection", "Centers the camera on the selected item", QKeySequence(Qt::Key_C)); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index ec78db011..73d8aef52 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -15,6 +15,7 @@ #include #include "../../model/prefs/shortcut.hpp" +#include "../../model/prefs/shortcuteventhandler.hpp" #include "scenewidget.hpp" @@ -81,7 +82,25 @@ namespace CSVRender mActive = (mCamera != NULL); if (mActive) + { onActivate(); + + QList shortcuts = findChildren(); + + for (QList::iterator it = shortcuts.begin(); it != shortcuts.end(); ++it) + { + (*it)->enable(true); + } + } + else + { + QList shortcuts = findChildren(); + + for (QList::iterator it = shortcuts.begin(); it != shortcuts.end(); ++it) + { + (*it)->enable(false); + } + } } void CameraController::setCameraSensitivity(double value) @@ -144,7 +163,7 @@ namespace CSVRender Free Camera Controller */ - FreeCameraController::FreeCameraController(SceneWidget* scene) + FreeCameraController::FreeCameraController(CSMPrefs::ShortcutEventHandler* handler) : mLockUpright(false) , mModified(false) , mFast(false) @@ -160,31 +179,38 @@ namespace CSVRender , mSpeedMult(8) { CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", this); - scene->addShortcut(forwardShortcut); + forwardShortcut->enable(false); + handler->addShortcut(forwardShortcut); connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", this); - scene->addShortcut(leftShortcut); + leftShortcut->enable(false); + handler->addShortcut(leftShortcut); connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool))); CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", this); - scene->addShortcut(backShortcut); + backShortcut->enable(false); + handler->addShortcut(backShortcut); connect(backShortcut, SIGNAL(activated(bool)), this, SLOT(backward(bool))); CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", this); - scene->addShortcut(rightShortcut); + rightShortcut->enable(false); + handler->addShortcut(rightShortcut); connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool))); CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", this); - scene->addShortcut(rollLeftShortcut); + rollLeftShortcut->enable(false); + handler->addShortcut(rollLeftShortcut); connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool))); CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", this); - scene->addShortcut(rollRightShortcut); + rollRightShortcut->enable(false); + handler->addShortcut(rollRightShortcut); connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool))); CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", this); - scene->addShortcut(speedModeShortcut); + speedModeShortcut->enable(false); + handler->addShortcut(speedModeShortcut); connect(speedModeShortcut, SIGNAL(activated(bool)), this, SLOT(swapSpeedMode(bool))); } @@ -230,14 +256,6 @@ namespace CSVRender mLockUpright = false; } - bool FreeCameraController::handleKeyEvent(QKeyEvent* event, bool pressed) - { - if (!isActive()) - return false; - - return true; - } - bool FreeCameraController::handleMouseMoveEvent(std::string mode, int x, int y) { if (!isActive()) @@ -412,7 +430,7 @@ namespace CSVRender Orbit Camera Controller */ - OrbitCameraController::OrbitCameraController(SceneWidget* widget) + OrbitCameraController::OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler) : mInitialized(false) , mFast(false) , mLeft(false) @@ -427,6 +445,40 @@ namespace CSVRender , mOrbitSpeed(osg::PI / 4) , mOrbitSpeedMult(4) { + CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", this); + upShortcut->enable(false); + handler->addShortcut(upShortcut); + connect(upShortcut, SIGNAL(activated(bool)), this, SLOT(up(bool))); + + CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("orbit-left", this); + leftShortcut->enable(false); + handler->addShortcut(leftShortcut); + connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool))); + + CSMPrefs::Shortcut* downShortcut = new CSMPrefs::Shortcut("orbit-down", this); + downShortcut->enable(false); + handler->addShortcut(downShortcut); + connect(downShortcut, SIGNAL(activated(bool)), this, SLOT(down(bool))); + + CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("orbit-right", this); + rightShortcut->enable(false); + handler->addShortcut(rightShortcut); + connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool))); + + CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("orbit-roll-left", this); + rollLeftShortcut->enable(false); + handler->addShortcut(rollLeftShortcut); + connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool))); + + CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("orbit-roll-right", this); + rollRightShortcut->enable(false); + handler->addShortcut(rollRightShortcut); + connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool))); + + CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("orbit-speed-mode", this); + speedModeShortcut->enable(false); + handler->addShortcut(speedModeShortcut); + connect(speedModeShortcut, SIGNAL(activated(bool)), this, SLOT(swapSpeedMode(bool))); } osg::Vec3d OrbitCameraController::getCenter() const @@ -477,50 +529,6 @@ namespace CSVRender mPickingMask = value; } - bool OrbitCameraController::handleKeyEvent(QKeyEvent* event, bool pressed) - { - if (!isActive()) - return false; - - if (!mInitialized) - initialize(); - - if (event->key() == Qt::Key_Q) - { - mRollLeft = pressed; - } - else if (event->key() == Qt::Key_E) - { - mRollRight = pressed; - } - else if (event->key() == Qt::Key_A) - { - mLeft = pressed; - } - else if (event->key() == Qt::Key_D) - { - mRight = pressed; - } - else if (event->key() == Qt::Key_W) - { - mUp = pressed; - } - else if (event->key() == Qt::Key_S) - { - mDown = pressed; - } - else if (event->key() == Qt::Key_Shift) - { - mFast = pressed; - } - else - { - return false; - } - - return true; - } - bool OrbitCameraController::handleMouseMoveEvent(std::string mode, int x, int y) { if (!isActive()) @@ -687,4 +695,46 @@ namespace CSVRender getCamera()->setViewMatrixAsLookAt(mCenter + offset, mCenter, up); } + + void OrbitCameraController::up(bool active) + { + if (isActive()) + mUp = active; + } + + void OrbitCameraController::left(bool active) + { + if (isActive()) + mLeft = active; + } + + void OrbitCameraController::down(bool active) + { + if (isActive()) + mDown = active; + } + + void OrbitCameraController::right(bool active) + { + if (isActive()) + mRight = active; + } + + void OrbitCameraController::rollLeft(bool active) + { + if (isActive()) + mRollLeft = active; + } + + void OrbitCameraController::rollRight(bool active) + { + if (isActive()) + mRollRight = active; + } + + void OrbitCameraController::swapSpeedMode(bool active) + { + if (isActive() && active) + mFast = !mFast; + } } diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index 2131e1f02..297a58f58 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -16,6 +16,11 @@ namespace osg class Group; } +namespace CSMPrefs +{ + class ShortcutEventHandler; +} + namespace CSVRender { class SceneWidget; @@ -52,7 +57,6 @@ namespace CSVRender // moves the camera to an intelligent position void setup(osg::Group* root, unsigned int mask, const osg::Vec3d& up); - virtual bool handleKeyEvent(QKeyEvent* event, bool pressed) = 0; virtual bool handleMouseMoveEvent(std::string mode, int x, int y) = 0; virtual void update(double dt) = 0; @@ -79,7 +83,7 @@ namespace CSVRender public: - FreeCameraController(SceneWidget* widget); + FreeCameraController(CSMPrefs::ShortcutEventHandler* handler); double getLinearSpeed() const; double getRotationalSpeed() const; @@ -92,7 +96,6 @@ namespace CSVRender void fixUpAxis(const osg::Vec3d& up); void unfixUpAxis(); - bool handleKeyEvent(QKeyEvent* event, bool pressed); bool handleMouseMoveEvent(std::string mode, int x, int y); void update(double dt); @@ -133,7 +136,7 @@ namespace CSVRender public: - OrbitCameraController(SceneWidget* widget); + OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler); osg::Vec3d getCenter() const; double getOrbitSpeed() const; @@ -145,7 +148,6 @@ namespace CSVRender void setOrbitSpeedMultiplier(double value); void setPickingMask(unsigned int value); - bool handleKeyEvent(QKeyEvent* event, bool pressed); bool handleMouseMoveEvent(std::string mode, int x, int y); void update(double dt); @@ -172,6 +174,16 @@ namespace CSVRender double mOrbitSpeed; double mOrbitSpeedMult; + + private slots: + + void up(bool active); + void left(bool active); + void down(bool active); + void right(bool active); + void rollLeft(bool active); + void rollRight(bool active); + void swapSpeedMode(bool active); }; } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 48fe4abdc..bb1ca4008 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -20,6 +20,7 @@ #include "../../model/prefs/state.hpp" #include "../../model/prefs/shortcut.hpp" +#include "../../model/prefs/shortcuteventhandler.hpp" #include "lighting.hpp" #include "mask.hpp" @@ -159,13 +160,13 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys , mHasDefaultAmbient(false) , mPrevMouseX(0) , mPrevMouseY(0) - , mFreeCamControl(0) - , mOrbitCamControl(0) - , mCurrentCamControl(0) , mCamPositionSet(false) { - mFreeCamControl.reset(new FreeCameraController(this)); - mOrbitCamControl.reset(new OrbitCameraController(this)); + mShortcutHandler = new CSMPrefs::ShortcutEventHandler(this); + installEventFilter(mShortcutHandler); + + mFreeCamControl.reset(new FreeCameraController(mShortcutHandler)); + mOrbitCamControl.reset(new OrbitCameraController(mShortcutHandler)); mCurrentCamControl = mFreeCamControl.get(); mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); @@ -201,6 +202,8 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys SceneWidget::~SceneWidget() { + removeEventFilter(mShortcutHandler); + // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } @@ -276,57 +279,17 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); } -bool SceneWidget::event(QEvent *event) -{ - if (event->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(event); - SceneWidget::keyPressEvent(keyEvent); - } - else if (event->type() == QEvent::KeyRelease) - { - QKeyEvent* keyEvent = static_cast(event); - SceneWidget::keyReleaseEvent(keyEvent); - } - else if (event->type() == QEvent::MouseButtonPress) - { - QMouseEvent* keyEvent = static_cast(event); - SceneWidget::mousePressEvent(keyEvent); - } - else if (event->type() == QEvent::MouseButtonRelease) - { - QMouseEvent* keyEvent = static_cast(event); - SceneWidget::mouseReleaseEvent(keyEvent); - } - else - { - return RenderWidget::event(event); - } - - return true; -} - void SceneWidget::mousePressEvent (QMouseEvent *event) { mMouseMode = mapButton(event); mPrevMouseX = event->x(); mPrevMouseY = event->y(); - - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) - { - (*it)->mousePressEvent(event); - } } void SceneWidget::mouseReleaseEvent (QMouseEvent *event) { mMouseMode = ""; - - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) - { - (*it)->mouseReleaseEvent(event); - } } void SceneWidget::mouseMoveEvent (QMouseEvent *event) @@ -347,26 +310,6 @@ void SceneWidget::wheelEvent(QWheelEvent *event) mCurrentCamControl->handleMouseMoveEvent("t-navi", event->delta(), 0); } -void SceneWidget::keyPressEvent (QKeyEvent *event) -{ - mCurrentCamControl->handleKeyEvent(event, true); - - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) - { - (*it)->keyPressEvent(event); - } -} - -void SceneWidget::keyReleaseEvent (QKeyEvent *event) -{ - mCurrentCamControl->handleKeyEvent(event, false); - - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) - { - (*it)->keyReleaseEvent(event); - } -} - void SceneWidget::update(double dt) { if (mCamPositionSet) @@ -508,9 +451,4 @@ std::string SceneWidget::mapButton (QMouseEvent *event) return ""; } -void SceneWidget::addShortcut(CSMPrefs::Shortcut* shortcut) -{ - mShortcuts.push_back(shortcut); -} - } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 0744cc645..07f5f03cf 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -7,14 +7,15 @@ #include #include +#include +#include + #include #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" -#include -#include namespace Resource { @@ -37,6 +38,7 @@ namespace CSMPrefs { class Setting; class Shortcut; + class ShortcutEventHandler; } namespace CSVRender @@ -85,21 +87,16 @@ namespace CSVRender void setDefaultAmbient (const osg::Vec4f& colour); ///< \note The actual ambient colour may differ based on lighting settings. - void addShortcut(CSMPrefs::Shortcut* shortcut); - protected: void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. void setAmbient(const osg::Vec4f& ambient); - virtual bool event(QEvent *event); virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseMoveEvent (QMouseEvent *event); virtual void wheelEvent (QWheelEvent *event); - virtual void keyPressEvent (QKeyEvent *event); - virtual void keyReleaseEvent (QKeyEvent *event); virtual void focusOutEvent (QFocusEvent *event); /// \return Is \a key a button mapping setting? (ignored otherwise) @@ -124,7 +121,7 @@ namespace CSVRender CameraController* mCurrentCamControl; std::map, std::string> mButtonMapping; - std::vector mShortcuts; + CSMPrefs::ShortcutEventHandler *mShortcutHandler; private: bool mCamPositionSet; From d8fa3fd1de1d8e64b0bb774d7d982262ae7a9d7a Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 17 Jul 2016 19:36:33 -0400 Subject: [PATCH 06/46] Added orbit "center on selection" shortcut. --- apps/opencs/view/render/orbitcameramode.cpp | 26 +++++++++++++++++--- apps/opencs/view/render/orbitcameramode.hpp | 14 +++++++++-- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/orbitcameramode.cpp b/apps/opencs/view/render/orbitcameramode.cpp index e6f3612c6..6c4fb1f1e 100644 --- a/apps/opencs/view/render/orbitcameramode.cpp +++ b/apps/opencs/view/render/orbitcameramode.cpp @@ -2,22 +2,42 @@ #include +#include "../../model/prefs/shortcut.hpp" +#include "../../model/prefs/shortcuteventhandler.hpp" + #include "worldspacewidget.hpp" namespace CSVRender { - OrbitCameraMode::OrbitCameraMode(WorldspaceWidget* worldspaceWidget, const QIcon& icon, const QString& tooltip, - QWidget* parent) + OrbitCameraMode::OrbitCameraMode(WorldspaceWidget* worldspaceWidget, CSMPrefs::ShortcutEventHandler* handler, + const QIcon& icon, const QString& tooltip, QWidget* parent) : ModeButton(icon, tooltip, parent) , mWorldspaceWidget(worldspaceWidget) + , mShortcutHandler(handler) , mCenterOnSelection(0) { + mCenterShortcut = new CSMPrefs::Shortcut("orbit-center-selection", this); + mCenterShortcut->enable(false); + mShortcutHandler->addShortcut(mCenterShortcut); + connect(mCenterShortcut, SIGNAL(activated()), this, SLOT(centerSelection())); + } + + OrbitCameraMode::~OrbitCameraMode() + { + mShortcutHandler->removeShortcut(mCenterShortcut); } void OrbitCameraMode::activate(CSVWidget::SceneToolbar* toolbar) { - mCenterOnSelection = new QAction("Center on selected object", this); + mCenterOnSelection = new QAction("Center on selected object\t" + mCenterShortcut->toString(), this); connect(mCenterOnSelection, SIGNAL(triggered()), this, SLOT(centerSelection())); + + mCenterShortcut->enable(true); + } + + void OrbitCameraMode::deactivate(CSVWidget::SceneToolbar* toolbar) + { + mCenterShortcut->enable(false); } bool OrbitCameraMode::createContextMenu(QMenu* menu) diff --git a/apps/opencs/view/render/orbitcameramode.hpp b/apps/opencs/view/render/orbitcameramode.hpp index cd8387084..990999b22 100644 --- a/apps/opencs/view/render/orbitcameramode.hpp +++ b/apps/opencs/view/render/orbitcameramode.hpp @@ -3,6 +3,12 @@ #include "../widget/modebutton.hpp" +namespace CSMPrefs +{ + class Shortcut; + class ShortcutEventHandler; +} + namespace CSVRender { class WorldspaceWidget; @@ -13,16 +19,20 @@ namespace CSVRender public: - OrbitCameraMode(WorldspaceWidget* worldspaceWidget, const QIcon& icon, const QString& tooltip = "", - QWidget* parent = 0); + OrbitCameraMode(WorldspaceWidget* worldspaceWidget, CSMPrefs::ShortcutEventHandler* shortcutHandler, + const QIcon& icon, const QString& tooltip = "", QWidget* parent = 0); + ~OrbitCameraMode(); virtual void activate(CSVWidget::SceneToolbar* toolbar); + virtual void deactivate(CSVWidget::SceneToolbar* toolbar); virtual bool createContextMenu(QMenu* menu); private: WorldspaceWidget* mWorldspaceWidget; + CSMPrefs::ShortcutEventHandler* mShortcutHandler; QAction* mCenterOnSelection; + CSMPrefs::Shortcut* mCenterShortcut; private slots: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 782dc5354..e1706ca77 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -148,7 +148,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
  • Hold shift to speed up movement
  • " ""); tool->addButton( - new CSVRender::OrbitCameraMode(this, QIcon(":scenetoolbar/orbiting-camera"), + new CSVRender::OrbitCameraMode(this, mShortcutHandler, QIcon(":scenetoolbar/orbiting-camera"), "Orbiting Camera" "
    • Always facing the centre point
    • " "
    • Rotate around the centre point via WASD or by moving the mouse while holding the left button
    • " From faa84e0a3565221538db8f343d90e994476991d0 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Tue, 19 Jul 2016 22:04:15 -0400 Subject: [PATCH 07/46] - Further extended usage of new shortcut class - Refactored camera classes to take advantage of Qt's reference counting - Removed some of the old implementation --- .../model/prefs/shortcuteventhandler.cpp | 3 + apps/opencs/model/prefs/state.cpp | 14 ++ apps/opencs/view/render/cameracontroller.cpp | 110 ++++++---- apps/opencs/view/render/cameracontroller.hpp | 16 +- .../view/render/pagedworldspacewidget.cpp | 13 +- .../view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 101 ++------- apps/opencs/view/render/scenewidget.hpp | 28 ++- apps/opencs/view/render/worldspacewidget.cpp | 202 +++++++++--------- apps/opencs/view/render/worldspacewidget.hpp | 51 +++-- 10 files changed, 265 insertions(+), 275 deletions(-) diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index 49b13ff99..3119623ae 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -69,7 +69,10 @@ namespace CSMPrefs Shortcut* shortcut = *it; if (shortcut->isActive()) + { shortcut->activate(false); + shortcut->setPosition(0); + } } } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index abb5c7f18..6e47c8598 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -236,6 +236,7 @@ void CSMPrefs::State::declare() declareShortcut ("free-roll-left", "Free camera roll left", QKeySequence(Qt::Key_Q)); declareShortcut ("free-roll-right", "Free camera roll right", QKeySequence(Qt::Key_E)); declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); + declareSeparator (); declareShortcut ("orbit-up", "Orbit camera up", QKeySequence(Qt::Key_W)); declareShortcut ("orbit-down", "Orbit camera down", QKeySequence(Qt::Key_S)); @@ -245,6 +246,19 @@ void CSMPrefs::State::declare() declareShortcut ("orbit-roll-right", "Orbit camera roll right", QKeySequence(Qt::Key_E)); declareShortcut ("orbit-speed-mode", "Orbit camera speed mode toggle", QKeySequence(Qt::Key_F)); declareShortcut ("orbit-center-selection", "Centers the camera on the selected item", QKeySequence(Qt::Key_C)); + + declareSeparator (); + declareShortcut ("scene-navi-primary", "Camera rotation from mouse movement", QKeySequence(Qt::LeftButton)); + declareShortcut ("scene-navi-secondary", "Camera translation from mouse movement", + QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); + declareShortcut ("scene-edit-primary", "Scene primary edit button", QKeySequence(Qt::RightButton)); + declareShortcut ("scene-edit-secondary", "Scene secondary edit button", + QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); + declareShortcut ("scene-select-primary", "Scene primary select button", QKeySequence(Qt::MiddleButton)); + declareShortcut ("scene-select-secondary", "Scene secondary select button", + QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); + declareShortcut ("scene-edit-abort", "Scene editor abort key", QKeySequence(Qt::Key_Escape)); + declareShortcut ("scene-focus-toolbar", "Change focus in scene editor", QKeySequence(Qt::Key_T)); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 73d8aef52..88ded40d6 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -32,8 +32,9 @@ namespace CSVRender const osg::Vec3d CameraController::LocalLeft = osg::Vec3d(1, 0, 0); const osg::Vec3d CameraController::LocalForward = osg::Vec3d(0, 0, 1); - CameraController::CameraController() - : mActive(false) + CameraController::CameraController(QObject* parent) + : QObject(parent) + , mActive(false) , mInverted(false) , mCameraSensitivity(1/650.f) , mSecondaryMoveMult(50) @@ -163,8 +164,9 @@ namespace CSVRender Free Camera Controller */ - FreeCameraController::FreeCameraController(CSMPrefs::ShortcutEventHandler* handler) - : mLockUpright(false) + FreeCameraController::FreeCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent) + : CameraController(parent) + , mLockUpright(false) , mModified(false) , mFast(false) , mLeft(false) @@ -178,6 +180,16 @@ namespace CSVRender , mRotSpeed(osg::PI / 2) , mSpeedMult(8) { + CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", this); + naviPrimaryShortcut->enable(false); + handler->addShortcut(naviPrimaryShortcut); + connect(naviPrimaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviPrimary(bool))); + + CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", this); + naviSecondaryShortcut->enable(false); + handler->addShortcut(naviSecondaryShortcut); + connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool))); + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", this); forwardShortcut->enable(false); handler->addShortcut(forwardShortcut); @@ -211,7 +223,7 @@ namespace CSVRender CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", this); speedModeShortcut->enable(false); handler->addShortcut(speedModeShortcut); - connect(speedModeShortcut, SIGNAL(activated(bool)), this, SLOT(swapSpeedMode(bool))); + connect(speedModeShortcut, SIGNAL(activated()), this, SLOT(swapSpeedMode())); } double FreeCameraController::getLinearSpeed() const @@ -261,13 +273,13 @@ namespace CSVRender if (!isActive()) return false; - if (mode == "p-navi") + if (mNaviPrimary) { double scalar = getCameraSensitivity() * (getInverted() ? -1.0 : 1.0); yaw(x * scalar); pitch(y * scalar); } - else if (mode == "s-navi") + else if (mNaviSecondary) { osg::Vec3d movement; movement += LocalLeft * -x * getSecondaryMovementMultiplier(); @@ -384,54 +396,58 @@ namespace CSVRender getCamera()->setViewMatrixAsLookAt(eye, center, mUp); } + void FreeCameraController::naviPrimary(bool active) + { + mNaviPrimary = active; + } + + void FreeCameraController::naviSecondary(bool active) + { + mNaviSecondary = active; + } + void FreeCameraController::forward(bool active) { - if (isActive()) - mForward = active; + mForward = active; } void FreeCameraController::left(bool active) { - if (isActive()) - mLeft = active; + mLeft = active; } void FreeCameraController::backward(bool active) { - if (isActive()) - mBackward = active; + mBackward = active; } void FreeCameraController::right(bool active) { - if (isActive()) - mRight = active; + mRight = active; } void FreeCameraController::rollLeft(bool active) { - if (isActive()) - mRollLeft = active; + mRollLeft = active; } void FreeCameraController::rollRight(bool active) { - if (isActive()) - mRollRight = active; + mRollRight = active; } - void FreeCameraController::swapSpeedMode(bool active) + void FreeCameraController::swapSpeedMode() { - if (isActive() && active) - mFast = !mFast; + mFast = !mFast; } /* Orbit Camera Controller */ - OrbitCameraController::OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler) - : mInitialized(false) + OrbitCameraController::OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent) + : CameraController(parent) + , mInitialized(false) , mFast(false) , mLeft(false) , mRight(false) @@ -445,6 +461,16 @@ namespace CSVRender , mOrbitSpeed(osg::PI / 4) , mOrbitSpeedMult(4) { + CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", this); + naviPrimaryShortcut->enable(false); + handler->addShortcut(naviPrimaryShortcut); + connect(naviPrimaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviPrimary(bool))); + + CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", this); + naviSecondaryShortcut->enable(false); + handler->addShortcut(naviSecondaryShortcut); + connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool))); + CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", this); upShortcut->enable(false); handler->addShortcut(upShortcut); @@ -478,7 +504,7 @@ namespace CSVRender CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("orbit-speed-mode", this); speedModeShortcut->enable(false); handler->addShortcut(speedModeShortcut); - connect(speedModeShortcut, SIGNAL(activated(bool)), this, SLOT(swapSpeedMode(bool))); + connect(speedModeShortcut, SIGNAL(activated()), this, SLOT(swapSpeedMode())); } osg::Vec3d OrbitCameraController::getCenter() const @@ -537,13 +563,13 @@ namespace CSVRender if (!mInitialized) initialize(); - if (mode == "p-navi") + if (mNaviPrimary) { double scalar = getCameraSensitivity() * (getInverted() ? -1.0 : 1.0); rotateHorizontal(x * scalar); rotateVertical(-y * scalar); } - else if (mode == "s-navi") + else if (mNaviSecondary) { osg::Vec3d movement; movement += LocalLeft * x * getSecondaryMovementMultiplier(); @@ -696,28 +722,34 @@ namespace CSVRender getCamera()->setViewMatrixAsLookAt(mCenter + offset, mCenter, up); } + void OrbitCameraController::naviPrimary(bool active) + { + mNaviPrimary = active; + } + + void OrbitCameraController::naviSecondary(bool active) + { + mNaviSecondary = active; + } + void OrbitCameraController::up(bool active) { - if (isActive()) - mUp = active; + mUp = active; } void OrbitCameraController::left(bool active) { - if (isActive()) - mLeft = active; + mLeft = active; } void OrbitCameraController::down(bool active) { - if (isActive()) - mDown = active; + mDown = active; } void OrbitCameraController::right(bool active) { - if (isActive()) - mRight = active; + mRight = active; } void OrbitCameraController::rollLeft(bool active) @@ -728,13 +760,11 @@ namespace CSVRender void OrbitCameraController::rollRight(bool active) { - if (isActive()) - mRollRight = active; + mRollRight = active; } - void OrbitCameraController::swapSpeedMode(bool active) + void OrbitCameraController::swapSpeedMode() { - if (isActive() && active) - mFast = !mFast; + mFast = !mFast; } } diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index 297a58f58..6a2773298 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -37,7 +37,7 @@ namespace CSVRender static const osg::Vec3d LocalLeft; static const osg::Vec3d LocalForward; - CameraController(); + CameraController(QObject* parent); virtual ~CameraController(); bool isActive() const; @@ -83,7 +83,7 @@ namespace CSVRender public: - FreeCameraController(CSMPrefs::ShortcutEventHandler* handler); + FreeCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent=0); double getLinearSpeed() const; double getRotationalSpeed() const; @@ -112,6 +112,7 @@ namespace CSVRender void stabilize(); bool mLockUpright, mModified; + bool mNaviPrimary, mNaviSecondary; bool mFast, mLeft, mRight, mForward, mBackward, mRollLeft, mRollRight; osg::Vec3d mUp; @@ -121,13 +122,15 @@ namespace CSVRender private slots: + void naviPrimary(bool active); + void naviSecondary(bool active); void forward(bool active); void left(bool active); void backward(bool active); void right(bool active); void rollLeft(bool active); void rollRight(bool active); - void swapSpeedMode(bool active); + void swapSpeedMode(); }; class OrbitCameraController : public CameraController @@ -136,7 +139,7 @@ namespace CSVRender public: - OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler); + OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent=0); osg::Vec3d getCenter() const; double getOrbitSpeed() const; @@ -167,6 +170,7 @@ namespace CSVRender void zoom(double value); bool mInitialized; + bool mNaviPrimary, mNaviSecondary; bool mFast, mLeft, mRight, mUp, mDown, mRollLeft, mRollRight; unsigned int mPickingMask; osg::Vec3d mCenter; @@ -177,13 +181,15 @@ namespace CSVRender private slots: + void naviPrimary(bool active); + void naviSecondary(bool active); void up(bool active); void left(bool active); void down(bool active); void right(bool active); void rollLeft(bool active); void rollRight(bool active); - void swapSpeedMode(bool active); + void swapSpeedMode(); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index a01df4392..54e359fb3 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -142,15 +142,14 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } -void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, +void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift) { if (hit.tag && hit.tag->getMask()==Mask_CellArrow) { - if (button=="p-edit" || button=="s-edit") + if (type == InteractionType_PrimaryEdit || type == InteractionType_SecondaryEdit) { - if (CellArrowTag *cellArrowTag = - dynamic_cast (hit.tag.get())) + if (CellArrowTag *cellArrowTag = dynamic_cast (hit.tag.get())) { CellArrow *arrow = cellArrowTag->getCellArrow(); @@ -173,7 +172,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResu if (shift) { - if (button=="p-edit") + if (type == InteractionType_PrimaryEdit) addCellSelection (x, y); else moveCellSelection (x, y); @@ -191,7 +190,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResu modified = true; } - if (button=="s-edit") + if (type == InteractionType_SecondaryEdit) { if (mCells.find (coordinates)!=mCells.end()) { @@ -210,7 +209,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResu } } - WorldspaceWidget::handleMouseClick (hit, button, shift); + WorldspaceWidget::handleMouseClick (hit, type, shift); } void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 692000708..018d5dafb 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -138,7 +138,7 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, bool shift); + virtual void handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift); signals: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index bb1ca4008..8a1f1ad35 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -77,7 +77,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mView->setSceneData(mRootNode); - // Press S to reveal profiling stats + // Add ability to signal osg to show its statistics for debugging purposes mView->addEventHandler(new osgViewer::StatsHandler); mView->getCamera()->setCullMask(~(Mask_UpdateVisitor)); @@ -165,12 +165,11 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys mShortcutHandler = new CSMPrefs::ShortcutEventHandler(this); installEventFilter(mShortcutHandler); - mFreeCamControl.reset(new FreeCameraController(mShortcutHandler)); - mOrbitCamControl.reset(new OrbitCameraController(mShortcutHandler)); - mCurrentCamControl = mFreeCamControl.get(); + mFreeCamControl = new FreeCameraController(mShortcutHandler, this); + mOrbitCamControl = new OrbitCameraController(mShortcutHandler, this); + mCurrentCamControl = mFreeCamControl; mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); - selectNavigationMode("free"); // we handle lighting manually mView->setLightingMode(osgViewer::View::NO_LIGHT); @@ -183,9 +182,9 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); - /// \todo make shortcut configurable - //QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); - //connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); + mFocusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); + mShortcutHandler->addShortcut(mFocusToolbarShortcut); + connect(mFocusToolbarShortcut, SIGNAL(activated()), this, SIGNAL(focusToolbarRequest())); connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), this, SLOT (settingChanged (const CSMPrefs::Setting *))); @@ -279,32 +278,14 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); } -void SceneWidget::mousePressEvent (QMouseEvent *event) -{ - mMouseMode = mapButton(event); - - mPrevMouseX = event->x(); - mPrevMouseY = event->y(); -} - -void SceneWidget::mouseReleaseEvent (QMouseEvent *event) -{ - mMouseMode = ""; -} - void SceneWidget::mouseMoveEvent (QMouseEvent *event) { - mCurrentCamControl->handleMouseMoveEvent(mMouseMode, event->x() - mPrevMouseX, event->y() - mPrevMouseY); + mCurrentCamControl->handleMouseMoveEvent("TODO", event->x() - mPrevMouseX, event->y() - mPrevMouseY); mPrevMouseX = event->x(); mPrevMouseY = event->y(); } -void SceneWidget::focusOutEvent (QFocusEvent *event) -{ - mCurrentCamControl->resetInput(); -} - void SceneWidget::wheelEvent(QWheelEvent *event) { mCurrentCamControl->handleMouseMoveEvent("t-navi", event->delta(), 0); @@ -371,10 +352,6 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) { mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble()); } - else - { - storeMappingSetting(setting); - } } void SceneWidget::selectNavigationMode (const std::string& mode) @@ -382,73 +359,23 @@ void SceneWidget::selectNavigationMode (const std::string& mode) if (mode=="1st") { mCurrentCamControl->setCamera(NULL); - mCurrentCamControl = mFreeCamControl.get(); - mCurrentCamControl->setCamera(getCamera()); + mCurrentCamControl = mFreeCamControl; + mFreeCamControl->setCamera(getCamera()); mFreeCamControl->fixUpAxis(CameraController::WorldUp); } else if (mode=="free") { mCurrentCamControl->setCamera(NULL); - mCurrentCamControl = mFreeCamControl.get(); - mCurrentCamControl->setCamera(getCamera()); + mCurrentCamControl = mFreeCamControl; + mFreeCamControl->setCamera(getCamera()); mFreeCamControl->unfixUpAxis(); } else if (mode=="orbit") { mCurrentCamControl->setCamera(NULL); - mCurrentCamControl = mOrbitCamControl.get(); - mCurrentCamControl->setCamera(getCamera()); + mCurrentCamControl = mOrbitCamControl; + mOrbitCamControl->setCamera(getCamera()); } } -bool SceneWidget::storeMappingSetting (const CSMPrefs::Setting *setting) -{ - if (setting->getParent()->getKey()!="3D Scene Input") - return false; - - static const char * const sMappingSettings[] = - { - "p-navi", "s-navi", - 0 - }; - - for (int i=0; sMappingSettings[i]; ++i) - if (setting->getKey()==sMappingSettings[i]) - { - QString value = QString::fromUtf8 (setting->toString().c_str()); - - Qt::MouseButton button = Qt::NoButton; - - if (value.endsWith ("Left Mouse-Button")) - button = Qt::LeftButton; - else if (value.endsWith ("Right Mouse-Button")) - button = Qt::RightButton; - else if (value.endsWith ("Middle Mouse-Button")) - button = Qt::MiddleButton; - else - return false; - - bool ctrl = value.startsWith ("Ctrl-"); - - mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i]; - return true; - } - - return false; -} - -std::string SceneWidget::mapButton (QMouseEvent *event) -{ - std::pair phyiscal ( - event->button(), event->modifiers() & Qt::ControlModifier); - - std::map, std::string>::const_iterator iter = - mButtonMapping.find (phyiscal); - - if (iter!=mButtonMapping.end()) - return iter->second; - - return ""; -} - } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 07f5f03cf..07d1dce75 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -56,6 +56,7 @@ namespace CSVRender RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~RenderWidget(); + /// Initiates a request to redraw the view void flagAsModified(); void setVisibilityMask(int mask); @@ -65,19 +66,21 @@ namespace CSVRender protected: osg::ref_ptr mView; - - osg::Group* mRootNode; + osg::ref_ptr mRootNode; QTimer mTimer; }; - // Extension of RenderWidget to support lighting mode selection & toolbar + /// Extension of RenderWidget to support lighting mode selection & toolbar class SceneWidget : public RenderWidget { Q_OBJECT + public: + SceneWidget(boost::shared_ptr resourceSystem, QWidget* parent = 0, Qt::WindowFlags f = 0, bool retrieveInput = true); + virtual ~SceneWidget(); CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); @@ -88,21 +91,14 @@ namespace CSVRender ///< \note The actual ambient colour may differ based on lighting settings. protected: + void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. void setAmbient(const osg::Vec4f& ambient); - virtual void mousePressEvent (QMouseEvent *event); - virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseMoveEvent (QMouseEvent *event); virtual void wheelEvent (QWheelEvent *event); - virtual void focusOutEvent (QFocusEvent *event); - - /// \return Is \a key a button mapping setting? (ignored otherwise) - virtual bool storeMappingSetting (const CSMPrefs::Setting *setting); - - std::string mapButton (QMouseEvent *event); boost::shared_ptr mResourceSystem; @@ -115,13 +111,13 @@ namespace CSVRender LightingBright mLightingBright; int mPrevMouseX, mPrevMouseY; - std::string mMouseMode; - std::auto_ptr mFreeCamControl; - std::auto_ptr mOrbitCamControl; + + FreeCameraController* mFreeCamControl; + OrbitCameraController* mOrbitCamControl; CameraController* mCurrentCamControl; - std::map, std::string> mButtonMapping; CSMPrefs::ShortcutEventHandler *mShortcutHandler; + CSMPrefs::Shortcut* mFocusToolbarShortcut; private: bool mCamPositionSet; @@ -149,7 +145,9 @@ namespace CSVRender class CompositeViewer : public QObject, public osgViewer::CompositeViewer { Q_OBJECT + public: + CompositeViewer(); static CompositeViewer& get(); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index e1706ca77..df0550730 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -16,6 +16,8 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/prefs/shortcut.hpp" +#include "../../model/prefs/shortcuteventhandler.hpp" #include "../../model/prefs/state.hpp" #include "../render/orbitcameramode.hpp" @@ -31,10 +33,23 @@ #include "cameracontroller.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (document.getData().getResourceSystem(), parent, 0, false), mSceneElements(0), mRun(0), mDocument(document), - mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), mDragX(0), mDragY(0), mDragFactor(0), - mDragWheelFactor(0), mDragShiftFactor(0), - mToolTipPos (-1, -1), mShowToolTips(false), mToolTipDelay(0) + : SceneWidget (document.getData().getResourceSystem(), parent, 0, false) + , mSceneElements(0) + , mRun(0) + , mDocument(document) + , mInteractionMask (0) + , mEditMode (0) + , mLocked (false) + , mDragMode(InteractionType_None) + , mDragging (false) + , mDragX(0) + , mDragY(0) + , mDragFactor(0) + , mDragWheelFactor(0) + , mDragShiftFactor(0) + , mToolTipPos (-1, -1) + , mShowToolTips(false) + , mToolTipDelay(0) { setAcceptDrops(true); @@ -80,6 +95,27 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg CSMPrefs::get()["3D Scene Input"].update(); CSMPrefs::get()["Tooltips"].update(); + + // Shortcuts + mPrimaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", this); + mShortcutHandler->addShortcut(mPrimaryEditShortcut); + connect(mPrimaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool))); + + mSecondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this); + mShortcutHandler->addShortcut(mSecondaryEditShortcut); + connect(mSecondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool))); + + mPrimarySelectShortcut = new CSMPrefs::Shortcut("scene-select-primary", this); + mShortcutHandler->addShortcut(mPrimarySelectShortcut); + connect(mPrimarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(primarySelect(bool))); + + mSecondarySelectShortcut = new CSMPrefs::Shortcut("scene-select-secondary", this); + mShortcutHandler->addShortcut(mSecondarySelectShortcut); + connect(mSecondarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(secondarySelect(bool))); + + mAbortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this); + mShortcutHandler->addShortcut(mAbortShortcut); + connect(mSecondaryEditShortcut, SIGNAL(activated()), this, SLOT(abortDrag())); } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -409,7 +445,7 @@ void CSVRender::WorldspaceWidget::abortDrag() editMode.dragAborted(); mDragging = false; - mDragMode.clear(); + mDragMode = InteractionType_None; } } @@ -453,45 +489,6 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event) } } -bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *setting) -{ - static const char * const sMappingSettings[] = - { - "p-edit", "s-edit", - "p-select", "s-select", - 0 - }; - - if (setting->getParent()->getKey()=="3D Scene Input") - { - for (int i=0; sMappingSettings[i]; ++i) - { - if (setting->getKey()==sMappingSettings[i]) - { - QString value = QString::fromUtf8 (setting->toString().c_str()); - - Qt::MouseButton button = Qt::NoButton; - - if (value.endsWith ("Left Mouse-Button")) - button = Qt::LeftButton; - else if (value.endsWith ("Right Mouse-Button")) - button = Qt::RightButton; - else if (value.endsWith ("Middle Mouse-Button")) - button = Qt::MiddleButton; - else - return false; - - bool ctrl = value.startsWith ("Ctrl-"); - - mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i]; - return true; - } - } - } - - return SceneWidget::storeMappingSetting(setting); -} - void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); @@ -567,7 +564,7 @@ void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id) { dynamic_cast (*mEditMode->getCurrent()).setEditLock (mLocked); mDragging = false; - mDragMode.clear(); + mDragMode = InteractionType_None; } void CSVRender::WorldspaceWidget::showToolTip() @@ -615,17 +612,17 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) editMode.drag (event->pos(), diffX, diffY, factor); } - else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select") + else if (mDragMode != InteractionType_None) { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - if (mDragMode=="p-edit") + if (mDragMode == InteractionType_PrimaryEdit) mDragging = editMode.primaryEditStartDrag (event->pos()); - else if (mDragMode=="s-edit") + else if (mDragMode == InteractionType_SecondaryEdit) mDragging = editMode.secondaryEditStartDrag (event->pos()); - else if (mDragMode=="p-select") + else if (mDragMode == InteractionType_PrimarySelect) mDragging = editMode.primarySelectStartDrag (event->pos()); - else if (mDragMode=="s-select") + else if (mDragMode == InteractionType_SecondarySelect) mDragging = editMode.secondarySelectStartDrag (event->pos()); if (mDragging) @@ -656,46 +653,6 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) } } -void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) -{ - std::string button = mapButton (event); - - if (button=="p-edit" || button=="s-edit" || - button=="p-select" || button=="s-select") - { - if (!mDragging) - mDragMode = button; - } - else - SceneWidget::mousePressEvent(event); -} - -void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) -{ - std::string button = mapButton (event); - mDragMode.clear(); - - if (button=="p-edit" || button=="s-edit" || - button=="p-select" || button=="s-select") - { - if (mDragging) - { - EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - - editMode.dragCompleted(event->pos()); - mDragging = false; - } - else - { - WorldspaceHitResult hit = mousePick(event->pos(), getInteractionMask()); - - handleMouseClick (hit, button, event->modifiers() & Qt::ShiftModifier); - } - } - else - SceneWidget::mouseReleaseEvent(event); -} - void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { if (mDragging) @@ -713,27 +670,17 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) SceneWidget::wheelEvent(event); } -void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) -{ - if(event->key() == Qt::Key_Escape) - { - abortDrag(); - } - else - SceneWidget::keyPressEvent(event); -} - -void CSVRender::WorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, bool shift) +void CSVRender::WorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift) { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); - if (button=="p-edit") + if (type == InteractionType_PrimaryEdit) editMode.primaryEditPressed (hit); - else if (button=="s-edit") + else if (type == InteractionType_SecondaryEdit) editMode.secondaryEditPressed (hit); - else if (button=="p-select") + else if (type == InteractionType_PrimarySelect) editMode.primarySelectPressed (hit); - else if (button=="s-select") + else if (type == InteractionType_SecondarySelect) editMode.secondarySelectPressed (hit); } @@ -741,3 +688,48 @@ CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode() { return dynamic_cast (mEditMode->getCurrent()); } + +void CSVRender::WorldspaceWidget::primaryEdit(bool activate) +{ + handleInteraction(InteractionType_PrimaryEdit, activate); +} + +void CSVRender::WorldspaceWidget::secondaryEdit(bool activate) +{ + handleInteraction(InteractionType_SecondaryEdit, activate); +} + +void CSVRender::WorldspaceWidget::primarySelect(bool activate) +{ + handleInteraction(InteractionType_PrimarySelect, activate); +} + +void CSVRender::WorldspaceWidget::secondarySelect(bool activate) +{ + handleInteraction(InteractionType_SecondarySelect, activate); +} + +void CSVRender::WorldspaceWidget::handleInteraction(InteractionType type, bool activate) +{ + if (activate) + { + if (!mDragging) + mDragMode = type; + } + else + { + mDragMode = InteractionType_None; + + if (mDragging) + { + EditMode* editMode = getEditMode(); + editMode->dragCompleted(mapFromGlobal(QCursor::pos())); + mDragging = false; + } + else + { + WorldspaceHitResult hit = mousePick(mapFromGlobal(QCursor::pos()), getInteractionMask()); + handleMouseClick(hit, type, false); + } + } +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 92d31eb9e..36ee92773 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -15,6 +15,7 @@ namespace CSMPrefs { class Setting; + class Shortcut; } namespace CSMWorld @@ -55,7 +56,7 @@ namespace CSVRender unsigned int mInteractionMask; CSVWidget::SceneToolMode *mEditMode; bool mLocked; - std::string mDragMode; + int mDragMode; bool mDragging; int mDragX; int mDragY; @@ -67,6 +68,12 @@ namespace CSVRender bool mShowToolTips; int mToolTipDelay; + CSMPrefs::Shortcut* mPrimaryEditShortcut; + CSMPrefs::Shortcut* mSecondaryEditShortcut; + CSMPrefs::Shortcut* mPrimarySelectShortcut; + CSMPrefs::Shortcut* mSecondarySelectShortcut; + CSMPrefs::Shortcut* mAbortShortcut; + public: enum DropType @@ -85,6 +92,15 @@ namespace CSVRender ignored //either mixed cells, or not cells }; + enum InteractionType + { + InteractionType_PrimaryEdit, + InteractionType_PrimarySelect, + InteractionType_SecondaryEdit, + InteractionType_SecondarySelect, + InteractionType_None + }; + WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0); ~WorldspaceWidget (); @@ -171,12 +187,6 @@ namespace CSVRender /// Erase all overrides and restore the visual representation to its true state. virtual void reset (unsigned int elementMask) = 0; - /// \note Drags will be automatically aborted when the aborting is triggered - /// (either explicitly or implicitly) from within this class. This function only - /// needs to be called, when the drag abort is triggered externally (e.g. from - /// an edit mode). - void abortDrag(); - protected: /// Visual elements in a scene @@ -197,16 +207,9 @@ namespace CSVRender virtual void updateOverlay(); virtual void mouseMoveEvent (QMouseEvent *event); - virtual void mousePressEvent (QMouseEvent *event); - virtual void mouseReleaseEvent (QMouseEvent *event); virtual void wheelEvent (QWheelEvent *event); - virtual void keyPressEvent (QKeyEvent *event); - - virtual void handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, - bool shift); - /// \return Is \a key a button mapping setting? (ignored otherwise) - virtual bool storeMappingSetting (const CSMPrefs::Setting *setting); + virtual void handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift); virtual void settingChanged (const CSMPrefs::Setting *setting); @@ -222,6 +225,16 @@ namespace CSVRender virtual std::string getStartupInstruction() = 0; + void handleInteraction(InteractionType type, bool activate); + + public slots: + + /// \note Drags will be automatically aborted when the aborting is triggered + /// (either explicitly or implicitly) from within this class. This function only + /// needs to be called, when the drag abort is triggered externally (e.g. from + /// an edit mode). + void abortDrag(); + private slots: virtual void referenceableDataChanged (const QModelIndex& topLeft, @@ -255,6 +268,14 @@ namespace CSVRender void showToolTip(); + void primaryEdit(bool activate); + + void secondaryEdit(bool activate); + + void primarySelect(bool activate); + + void secondarySelect(bool activate); + protected slots: void elementSelectionChanged(); From d9d5a6561b0008272b958a84550581b660ca9b99 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Jul 2016 14:50:34 +0100 Subject: [PATCH 08/46] Adjust the code so that it should (maybe) work, changing the compilation error to a less straighforward one. --- components/fallback/validate.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 4f0933e6e..b89a71a5a 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -2,6 +2,8 @@ #define OPENMW_COMPONENTS_FALLBACK_VALIDATE_H #include +#include +#include #include #include @@ -80,7 +82,9 @@ namespace Files { filteredStream.push(unescape_hash_filter()); filteredStream.push(istream); - filteredStream >> escapePathContainer.mContainer; + boost::filesystem::path path; + filteredStream >> path; + escapePathContainer.mContainer.push_back(path); return istream; } From 59639e3988a59f01e38cd9834777dc495f93cbc8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Jul 2016 15:16:53 +0100 Subject: [PATCH 09/46] Make it build again (but remove the new functionality). --- apps/openmw/main.cpp | 2 +- components/fallback/validate.hpp | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 64b74276e..6cc3fbf4e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -193,7 +193,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // directory settings engine.enableFSStrict(variables["fs-strict"].as()); - Files::PathContainer dataDirs(variables["data"].as().mContainer); + Files::PathContainer dataDirs(Files::EscapePath::toPathContainer(variables["data"].as())); std::string local(variables["data-local"].as().toStdString()); if (!local.empty()) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index b89a71a5a..d0cad4672 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -70,21 +70,31 @@ namespace Files { eSV->mVector.push_back(EscapeHashString(*it)); } - struct EscapePathContainer { - PathContainer mContainer; + struct EscapePath { + boost::filesystem::path mPath; + + static PathContainer toPathContainer(const std::vector & escapePathContainer); }; - std::istream & operator>> (std::istream & istream, EscapePathContainer & escapePathContainer) + typedef std::vector EscapePathContainer; + + PathContainer EscapePath::toPathContainer(const EscapePathContainer & escapePathContainer) + { + PathContainer temp; + for (EscapePathContainer::const_iterator it = escapePathContainer.begin(); it != escapePathContainer.end(); ++it) + temp.push_back(it->mPath); + return temp; + } + + std::istream & operator>> (std::istream & istream, EscapePath & escapePath) { std::cout << "The new dodgy operator>> is being used" << std::endl; boost::iostreams::filtering_istream filteredStream; - filteredStream.push(unescape_hash_filter()); + //filteredStream.push(unescape_hash_filter()); filteredStream.push(istream); - boost::filesystem::path path; - filteredStream >> path; - escapePathContainer.mContainer.push_back(path); + filteredStream >> escapePath.mPath; return istream; } From 423919abb5db50a7dc889a5f26b7dcc326f85b01 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Jul 2016 15:19:34 +0100 Subject: [PATCH 10/46] Make it not build again (but theoretically enable the desired functionality). --- components/fallback/validate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index d0cad4672..cb3555d7f 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -91,7 +91,7 @@ namespace Files { std::cout << "The new dodgy operator>> is being used" << std::endl; boost::iostreams::filtering_istream filteredStream; - //filteredStream.push(unescape_hash_filter()); + filteredStream.push(unescape_hash_filter()); filteredStream.push(istream); filteredStream >> escapePath.mPath; From 1b5273f2b7b69a1f6ad7e46e7364e2d2292cc248 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 20 Jul 2016 15:00:00 -0400 Subject: [PATCH 11/46] Finally re-added rendering stats, refactored some functions to better fit new input structure, removed unneeded shortcut declarations in headers, and changed the cell marker interaction to use primary/secondary select instead of shift + primary/secondary edit. --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/view/render/cameracontroller.cpp | 62 ++++--------- apps/opencs/view/render/cameracontroller.hpp | 15 ++-- .../view/render/pagedworldspacewidget.cpp | 87 +++++++++---------- .../view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 26 ++++-- apps/opencs/view/render/scenewidget.hpp | 11 +-- apps/opencs/view/render/worldspacewidget.cpp | 34 ++++---- apps/opencs/view/render/worldspacewidget.hpp | 8 +- 9 files changed, 110 insertions(+), 136 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 6e47c8598..417209380 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -259,6 +259,7 @@ void CSMPrefs::State::declare() QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); declareShortcut ("scene-edit-abort", "Scene editor abort key", QKeySequence(Qt::Key_Escape)); declareShortcut ("scene-focus-toolbar", "Change focus in scene editor", QKeySequence(Qt::Key_T)); + declareShortcut ("scene-render-stats", "Displays debug rendering stats", QKeySequence(Qt::Key_F3)); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 88ded40d6..642991b36 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -268,10 +268,10 @@ namespace CSVRender mLockUpright = false; } - bool FreeCameraController::handleMouseMoveEvent(std::string mode, int x, int y) + void FreeCameraController::handleMouseMoveEvent(int x, int y) { if (!isActive()) - return false; + return; if (mNaviPrimary) { @@ -287,16 +287,14 @@ namespace CSVRender translate(movement); } - else if (mode == "t-navi") - { - translate(LocalForward * x * (mFast ? getWheelMovementMultiplier() : 1)); - } - else - { - return false; - } + } - return true; + void FreeCameraController::handleMouseScrollEvent(int x) + { + if (!isActive()) + return; + + translate(LocalForward * x * (mFast ? getWheelMovementMultiplier() : 1)); } void FreeCameraController::update(double dt) @@ -336,17 +334,6 @@ namespace CSVRender getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix()); } - void FreeCameraController::resetInput() - { - mFast = false; - mLeft = false; - mRight = false; - mForward = false; - mBackward = false; - mRollLeft = false; - mRollRight = false; - } - void FreeCameraController::yaw(double value) { getCamera()->getViewMatrix() *= osg::Matrixd::rotate(value, LocalUp); @@ -555,10 +542,10 @@ namespace CSVRender mPickingMask = value; } - bool OrbitCameraController::handleMouseMoveEvent(std::string mode, int x, int y) + void OrbitCameraController::handleMouseMoveEvent(int x, int y) { if (!isActive()) - return false; + return; if (!mInitialized) initialize(); @@ -577,16 +564,14 @@ namespace CSVRender translate(movement); } - else if (mode == "t-navi") - { - zoom(-x * (mFast ? getWheelMovementMultiplier() : 1)); - } - else - { - return false; - } + } - return true; + void OrbitCameraController::handleMouseScrollEvent(int x) + { + if (!isActive()) + return; + + zoom(-x * (mFast ? getWheelMovementMultiplier() : 1)); } void OrbitCameraController::update(double dt) @@ -620,17 +605,6 @@ namespace CSVRender getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix()); } - void OrbitCameraController::resetInput() - { - mFast = false; - mLeft = false; - mRight =false; - mUp = false; - mDown = false; - mRollLeft = false; - mRollRight = false; - } - void OrbitCameraController::onActivate() { mInitialized = false; diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index 6a2773298..7cca048d8 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -57,12 +57,11 @@ namespace CSVRender // moves the camera to an intelligent position void setup(osg::Group* root, unsigned int mask, const osg::Vec3d& up); - virtual bool handleMouseMoveEvent(std::string mode, int x, int y) = 0; + virtual void handleMouseMoveEvent(int x, int y) = 0; + virtual void handleMouseScrollEvent(int x) = 0; virtual void update(double dt) = 0; - virtual void resetInput() = 0; - protected: virtual void onActivate(){} @@ -96,12 +95,11 @@ namespace CSVRender void fixUpAxis(const osg::Vec3d& up); void unfixUpAxis(); - bool handleMouseMoveEvent(std::string mode, int x, int y); + void handleMouseMoveEvent(int x, int y); + void handleMouseScrollEvent(int x); void update(double dt); - void resetInput(); - private: void yaw(double value); @@ -151,12 +149,11 @@ namespace CSVRender void setOrbitSpeedMultiplier(double value); void setPickingMask(unsigned int value); - bool handleMouseMoveEvent(std::string mode, int x, int y); + void handleMouseMoveEvent(int x, int y); + void handleMouseScrollEvent(int x); void update(double dt); - void resetInput(); - private: void onActivate(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 54e359fb3..397b86f0d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -142,74 +142,71 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( "terrain-move"); } -void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, - bool shift) +void CSVRender::PagedWorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type) { if (hit.tag && hit.tag->getMask()==Mask_CellArrow) { - if (type == InteractionType_PrimaryEdit || type == InteractionType_SecondaryEdit) + if (CellArrowTag *cellArrowTag = dynamic_cast (hit.tag.get())) { - if (CellArrowTag *cellArrowTag = dynamic_cast (hit.tag.get())) - { - CellArrow *arrow = cellArrowTag->getCellArrow(); + CellArrow *arrow = cellArrowTag->getCellArrow(); - CSMWorld::CellCoordinates coordinates = arrow->getCoordinates(); + CSMWorld::CellCoordinates coordinates = arrow->getCoordinates(); - CellArrow::Direction direction = arrow->getDirection(); + CellArrow::Direction direction = arrow->getDirection(); - int x = 0; - int y = 0; + int x = 0; + int y = 0; - switch (direction) - { - case CellArrow::Direction_North: y = 1; break; - case CellArrow::Direction_West: x = -1; break; - case CellArrow::Direction_South: y = -1; break; - case CellArrow::Direction_East: x = 1; break; - } + switch (direction) + { + case CellArrow::Direction_North: y = 1; break; + case CellArrow::Direction_West: x = -1; break; + case CellArrow::Direction_South: y = -1; break; + case CellArrow::Direction_East: x = 1; break; + } - bool modified = false; + bool modified = false; - if (shift) - { - if (type == InteractionType_PrimaryEdit) - addCellSelection (x, y); - else - moveCellSelection (x, y); + if (type == InteractionType_PrimarySelect) + { + addCellSelection (x, y); + modified = true; + } + else if (type == InteractionType_SecondarySelect) + { + moveCellSelection (x, y); + modified = true; + } + else // Primary/SecondaryEdit + { + CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y); + if (mCells.find (newCoordinates)==mCells.end()) + { + addCellToScene (newCoordinates); + mSelection.add (newCoordinates); modified = true; } - else - { - CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y); - if (mCells.find (newCoordinates)==mCells.end()) + if (type == InteractionType_SecondaryEdit) + { + if (mCells.find (coordinates)!=mCells.end()) { - addCellToScene (newCoordinates); - mSelection.add (newCoordinates); + removeCellFromScene (coordinates); + mSelection.remove (coordinates); modified = true; } - - if (type == InteractionType_SecondaryEdit) - { - if (mCells.find (coordinates)!=mCells.end()) - { - removeCellFromScene (coordinates); - mSelection.remove (coordinates); - modified = true; - } - } } + } - if (modified) - adjustCells(); + if (modified) + adjustCells(); - return; - } + return; } } - WorldspaceWidget::handleMouseClick (hit, type, shift); + WorldspaceWidget::handleInteractionPress (hit, type); } void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 018d5dafb..462580d49 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -138,7 +138,7 @@ namespace CSVRender virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); - virtual void handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift); + virtual void handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type); signals: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 8a1f1ad35..c32427863 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -107,6 +107,15 @@ osg::Camera *RenderWidget::getCamera() return mView->getCamera(); } +void RenderWidget::toggleRenderStats() +{ + osgViewer::GraphicsWindow* window = + static_cast(mView->getCamera()->getGraphicsContext()); + + window->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_S); + window->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_S); +} + // -------------------------------------------------- @@ -182,10 +191,6 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); - mFocusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); - mShortcutHandler->addShortcut(mFocusToolbarShortcut); - connect(mFocusToolbarShortcut, SIGNAL(activated()), this, SIGNAL(focusToolbarRequest())); - connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), this, SLOT (settingChanged (const CSMPrefs::Setting *))); @@ -197,6 +202,15 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys } connect (&CompositeViewer::get(), SIGNAL (simulationUpdated(double)), this, SLOT (update(double))); + + // Shortcuts + CSMPrefs::Shortcut* focusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); + mShortcutHandler->addShortcut(focusToolbarShortcut); + connect(focusToolbarShortcut, SIGNAL(activated()), this, SIGNAL(focusToolbarRequest())); + + CSMPrefs::Shortcut* renderStatsShortcut = new CSMPrefs::Shortcut("scene-render-stats", this); + mShortcutHandler->addShortcut(renderStatsShortcut); + connect(renderStatsShortcut, SIGNAL(activated()), this, SLOT(toggleRenderStats())); } SceneWidget::~SceneWidget() @@ -280,7 +294,7 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) void SceneWidget::mouseMoveEvent (QMouseEvent *event) { - mCurrentCamControl->handleMouseMoveEvent("TODO", event->x() - mPrevMouseX, event->y() - mPrevMouseY); + mCurrentCamControl->handleMouseMoveEvent(event->x() - mPrevMouseX, event->y() - mPrevMouseY); mPrevMouseX = event->x(); mPrevMouseY = event->y(); @@ -288,7 +302,7 @@ void SceneWidget::mouseMoveEvent (QMouseEvent *event) void SceneWidget::wheelEvent(QWheelEvent *event) { - mCurrentCamControl->handleMouseMoveEvent("t-navi", event->delta(), 0); + mCurrentCamControl->handleMouseScrollEvent(event->delta()); } void SceneWidget::update(double dt) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 07d1dce75..fbe5bc13e 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -69,18 +69,19 @@ namespace CSVRender osg::ref_ptr mRootNode; QTimer mTimer; + + protected slots: + + void toggleRenderStats(); }; /// Extension of RenderWidget to support lighting mode selection & toolbar class SceneWidget : public RenderWidget { Q_OBJECT - public: - SceneWidget(boost::shared_ptr resourceSystem, QWidget* parent = 0, Qt::WindowFlags f = 0, bool retrieveInput = true); - virtual ~SceneWidget(); CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); @@ -91,7 +92,6 @@ namespace CSVRender ///< \note The actual ambient colour may differ based on lighting settings. protected: - void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. @@ -117,7 +117,6 @@ namespace CSVRender CameraController* mCurrentCamControl; CSMPrefs::ShortcutEventHandler *mShortcutHandler; - CSMPrefs::Shortcut* mFocusToolbarShortcut; private: bool mCamPositionSet; @@ -145,9 +144,7 @@ namespace CSVRender class CompositeViewer : public QObject, public osgViewer::CompositeViewer { Q_OBJECT - public: - CompositeViewer(); static CompositeViewer& get(); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index df0550730..ab6a525d9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -97,25 +97,25 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg CSMPrefs::get()["Tooltips"].update(); // Shortcuts - mPrimaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", this); - mShortcutHandler->addShortcut(mPrimaryEditShortcut); - connect(mPrimaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool))); + CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", this); + mShortcutHandler->addShortcut(primaryEditShortcut); + connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool))); - mSecondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this); - mShortcutHandler->addShortcut(mSecondaryEditShortcut); - connect(mSecondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool))); + CSMPrefs::Shortcut* secondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this); + mShortcutHandler->addShortcut(secondaryEditShortcut); + connect(secondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool))); - mPrimarySelectShortcut = new CSMPrefs::Shortcut("scene-select-primary", this); - mShortcutHandler->addShortcut(mPrimarySelectShortcut); - connect(mPrimarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(primarySelect(bool))); + CSMPrefs::Shortcut* primarySelectShortcut = new CSMPrefs::Shortcut("scene-select-primary", this); + mShortcutHandler->addShortcut(primarySelectShortcut); + connect(primarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(primarySelect(bool))); - mSecondarySelectShortcut = new CSMPrefs::Shortcut("scene-select-secondary", this); - mShortcutHandler->addShortcut(mSecondarySelectShortcut); - connect(mSecondarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(secondarySelect(bool))); + CSMPrefs::Shortcut* secondarySelectShortcut = new CSMPrefs::Shortcut("scene-select-secondary", this); + mShortcutHandler->addShortcut(secondarySelectShortcut); + connect(secondarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(secondarySelect(bool))); - mAbortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this); - mShortcutHandler->addShortcut(mAbortShortcut); - connect(mSecondaryEditShortcut, SIGNAL(activated()), this, SLOT(abortDrag())); + CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this); + mShortcutHandler->addShortcut(abortShortcut); + connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag())); } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -670,7 +670,7 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) SceneWidget::wheelEvent(event); } -void CSVRender::WorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift) +void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type) { EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -729,7 +729,7 @@ void CSVRender::WorldspaceWidget::handleInteraction(InteractionType type, bool a else { WorldspaceHitResult hit = mousePick(mapFromGlobal(QCursor::pos()), getInteractionMask()); - handleMouseClick(hit, type, false); + handleInteractionPress(hit, type); } } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 36ee92773..8a8ce1c6f 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -68,12 +68,6 @@ namespace CSVRender bool mShowToolTips; int mToolTipDelay; - CSMPrefs::Shortcut* mPrimaryEditShortcut; - CSMPrefs::Shortcut* mSecondaryEditShortcut; - CSMPrefs::Shortcut* mPrimarySelectShortcut; - CSMPrefs::Shortcut* mSecondarySelectShortcut; - CSMPrefs::Shortcut* mAbortShortcut; - public: enum DropType @@ -209,7 +203,7 @@ namespace CSVRender virtual void mouseMoveEvent (QMouseEvent *event); virtual void wheelEvent (QWheelEvent *event); - virtual void handleMouseClick (const WorldspaceHitResult& hit, InteractionType type, bool shift); + virtual void handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type); virtual void settingChanged (const CSMPrefs::Setting *setting); From 32f0ded8f63f3245aa347a81d2f0c262e46288e8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Jul 2016 23:15:44 +0100 Subject: [PATCH 12/46] Fix bug in unescape filter, but still manage not to fix build issue. --- components/files/configurationmanager.cpp | 29 +++++++++++++++++++---- components/files/configurationmanager.hpp | 6 +++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index bbac62731..e1b82703f 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -237,25 +237,46 @@ int escape_hash_filter::get(Source & src) return retval; } +unescape_hash_filter::unescape_hash_filter() : expectingIdentifier(false) +{ +} + +unescape_hash_filter::~unescape_hash_filter() +{ +} + template int unescape_hash_filter::get(Source & src) { - int character = boost::iostreams::get(src); + int character; + if (!expectingIdentifier) + character = boost::iostreams::get(src); + else + { + character = escape_hash_filter::sEscape; + expectingIdentifier = false; + } if (character == escape_hash_filter::sEscape) { int nextChar = boost::iostreams::get(src); + int intended; switch (nextChar) { case escape_hash_filter::sEscapeIdentifier: - return escape_hash_filter::sEscape; + intended = escape_hash_filter::sEscape; break; case escape_hash_filter::sHashIdentifier: - return '#'; + intended = '#'; + break; + case boost::iostreams::WOULD_BLOCK: + expectingIdentifier = true; + intended = nextChar; break; default: - return '?'; + intended = '?'; break; } + return intended; } else return character; diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index d31ac1ecd..154445be6 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -90,7 +90,13 @@ struct escape_hash_filter : public boost::iostreams::input_filter struct unescape_hash_filter : public boost::iostreams::input_filter { + unescape_hash_filter(); + virtual ~unescape_hash_filter(); + template int get(Source & src); + + private: + bool expectingIdentifier; }; /** From 519fbab864eb987b0f72a3314de3accf1030678d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 20 Jul 2016 23:18:09 +0100 Subject: [PATCH 13/46] Remove useless print --- components/fallback/validate.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index cb3555d7f..43d51dd5e 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -88,8 +88,6 @@ namespace Files { std::istream & operator>> (std::istream & istream, EscapePath & escapePath) { - std::cout << "The new dodgy operator>> is being used" << std::endl; - boost::iostreams::filtering_istream filteredStream; filteredStream.push(unescape_hash_filter()); filteredStream.push(istream); From becc05355512753c301210674820e04453ba26bd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 21 Jul 2016 00:16:00 +0100 Subject: [PATCH 14/46] Trick the software into building by using what I assume is a really dirty hack. --- components/files/configurationmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index e1b82703f..ca2c22ecd 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -145,6 +145,9 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, boost::iostreams::filtering_istream configFileStream; configFileStream.push(escape_hash_filter()); configFileStream.push(configFileStreamUnfiltered); + + boost::iostreams::filtering_istream dummyStreamThatShouldMakeOtherCodeCompile; + dummyStreamThatShouldMakeOtherCodeCompile.push(unescape_hash_filter()); if (configFileStreamUnfiltered.is_open()) { boost::program_options::store(boost::program_options::parse_config_file( From 2b829f7f7b2f5083f6ab2587fbf96042aba58406 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 21 Jul 2016 01:07:25 +0100 Subject: [PATCH 15/46] Move some stuff to a header, removing the need for a dodgy hack. --- components/files/configurationmanager.cpp | 44 ----------------------- components/files/configurationmanager.hpp | 43 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index ca2c22ecd..127daac65 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -145,9 +145,6 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, boost::iostreams::filtering_istream configFileStream; configFileStream.push(escape_hash_filter()); configFileStream.push(configFileStreamUnfiltered); - - boost::iostreams::filtering_istream dummyStreamThatShouldMakeOtherCodeCompile; - dummyStreamThatShouldMakeOtherCodeCompile.push(unescape_hash_filter()); if (configFileStreamUnfiltered.is_open()) { boost::program_options::store(boost::program_options::parse_config_file( @@ -167,10 +164,6 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } -const int escape_hash_filter::sEscape = '@'; -const int escape_hash_filter::sEscapeIdentifier = 'a'; -const int escape_hash_filter::sHashIdentifier = 'h'; - escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false) { } @@ -248,43 +241,6 @@ unescape_hash_filter::~unescape_hash_filter() { } -template -int unescape_hash_filter::get(Source & src) -{ - int character; - if (!expectingIdentifier) - character = boost::iostreams::get(src); - else - { - character = escape_hash_filter::sEscape; - expectingIdentifier = false; - } - if (character == escape_hash_filter::sEscape) - { - int nextChar = boost::iostreams::get(src); - int intended; - switch (nextChar) - { - case escape_hash_filter::sEscapeIdentifier: - intended = escape_hash_filter::sEscape; - break; - case escape_hash_filter::sHashIdentifier: - intended = '#'; - break; - case boost::iostreams::WOULD_BLOCK: - expectingIdentifier = true; - intended = nextChar; - break; - default: - intended = '?'; - break; - } - return intended; - } - else - return character; -} - std::string EscapeHashString::processString(const std::string & str) { std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 154445be6..1d2d2c419 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -71,9 +71,9 @@ struct ConfigurationManager */ struct escape_hash_filter : public boost::iostreams::input_filter { - static const int sEscape; - static const int sHashIdentifier; - static const int sEscapeIdentifier; + static const int sEscape = '@'; + static const int sHashIdentifier = 'h'; + static const int sEscapeIdentifier = 'a'; escape_hash_filter(); virtual ~escape_hash_filter(); @@ -99,6 +99,43 @@ struct unescape_hash_filter : public boost::iostreams::input_filter bool expectingIdentifier; }; +template +int unescape_hash_filter::get(Source & src) +{ + int character; + if (!expectingIdentifier) + character = boost::iostreams::get(src); + else + { + character = escape_hash_filter::sEscape; + expectingIdentifier = false; + } + if (character == escape_hash_filter::sEscape) + { + int nextChar = boost::iostreams::get(src); + int intended; + switch (nextChar) + { + case escape_hash_filter::sEscapeIdentifier: + intended = escape_hash_filter::sEscape; + break; + case escape_hash_filter::sHashIdentifier: + intended = '#'; + break; + case boost::iostreams::WOULD_BLOCK: + expectingIdentifier = true; + intended = nextChar; + break; + default: + intended = '?'; + break; + } + return intended; + } + else + return character; +} + /** * \class EscapeHashString */ From 7243583963a067610aa98ee9c1fba9be28d5957c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 21 Jul 2016 01:36:14 +0100 Subject: [PATCH 16/46] Change a switch to a series of if/else if/.../else, hopefully resolving compilation issues on OSX and Linux. --- components/files/configurationmanager.cpp | 4 ++++ components/files/configurationmanager.hpp | 23 +++++++++-------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 127daac65..e5313bfee 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -164,6 +164,10 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } +const int escape_hash_filter::sEscape = '@'; +const int escape_hash_filter::sEscapeIdentifier = 'a'; +const int escape_hash_filter::sHashIdentifier = 'h'; + escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false) { } diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 1d2d2c419..494dfdd0c 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -71,9 +71,9 @@ struct ConfigurationManager */ struct escape_hash_filter : public boost::iostreams::input_filter { - static const int sEscape = '@'; - static const int sHashIdentifier = 'h'; - static const int sEscapeIdentifier = 'a'; + static const int sEscape; + static const int sHashIdentifier; + static const int sEscapeIdentifier; escape_hash_filter(); virtual ~escape_hash_filter(); @@ -114,22 +114,17 @@ int unescape_hash_filter::get(Source & src) { int nextChar = boost::iostreams::get(src); int intended; - switch (nextChar) - { - case escape_hash_filter::sEscapeIdentifier: + if (nextChar == escape_hash_filter::sEscapeIdentifier) intended = escape_hash_filter::sEscape; - break; - case escape_hash_filter::sHashIdentifier: + else if (nextChar == escape_hash_filter::sHashIdentifier) intended = '#'; - break; - case boost::iostreams::WOULD_BLOCK: + else if (nextChar == boost::iostreams::WOULD_BLOCK) + { expectingIdentifier = true; intended = nextChar; - break; - default: - intended = '?'; - break; } + else + intended = '?'; return intended; } else From d7907473891b02b7bd6577336a4422bd0e5ecbd7 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 22 Jul 2016 01:59:02 +0200 Subject: [PATCH 17/46] Implement deletion of moved references (Bug #3471) --- apps/openmw/mwworld/cellstore.cpp | 11 +++++++---- apps/openmw/mwworld/store.cpp | 25 +++++++++++-------------- components/esm/loadcell.hpp | 10 +++++++++- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1ca452efe..31b8a1515 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -497,9 +497,11 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - const ESM::CellRef &ref = *it; + const ESM::CellRef &ref = it->first; + bool deleted = it->second; - mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); + if (!deleted) + mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } std::sort (mIds.begin(), mIds.end()); @@ -549,9 +551,10 @@ namespace MWWorld // Load moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + ESM::CellRef &ref = const_cast(it->first); + bool deleted = it->second; - loadRef (ref, false); + loadRef (ref, deleted); } updateMergedRefs(); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 4cddbcdfb..fbe94b7d0 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -513,19 +513,16 @@ namespace MWWorld bool deleted = false; cell->getNextRef(esm, ref, deleted); - if (!deleted) - { - // Add data required to make reference appear in the correct cell. - // We should not need to test for duplicates, as this part of the code is pre-cell merge. - cell->mMovedRefs.push_back(cMRef); - - // But there may be duplicates here! - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); - if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(ref); - else - *iter = ref; - } + // Add data required to make reference appear in the correct cell. + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + cell->mMovedRefs.push_back(cMRef); + + // But there may be duplicates here! + ESM::CellRefTracker::iterator iter = std::find_if(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(ref.mRefNum)); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(std::make_pair(ref, deleted)); + else + *iter = std::make_pair(ref, deleted); } } const ESM::Cell *Store::search(const std::string &id) const @@ -681,7 +678,7 @@ namespace MWWorld if (itold != oldcell->mMovedRefs.end()) { ESM::MovedCellRef target0 = *itold; ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); + ESM::CellRefTracker::iterator it_lease = std::find_if(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(it->mRefNum)); if (it_lease != wipecell->mLeasedRefs.end()) wipecell->mLeasedRefs.erase(it_lease); else diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 549ed7309..249d812b1 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -43,7 +43,15 @@ bool operator==(const MovedCellRef& ref, const RefNum& refNum); bool operator==(const CellRef& ref, const RefNum& refNum); typedef std::list MovedCellRefTracker; -typedef std::list CellRefTracker; +typedef std::list > CellRefTracker; + +struct CellRefTrackerPredicate +{ + RefNum mRefNum; + + CellRefTrackerPredicate(const RefNum& refNum) : mRefNum(refNum) {} + bool operator() (const std::pair& refdelPair) { return refdelPair.first == mRefNum; } +}; /* Cells hold data about objects, creatures, statics (rocks, walls, buildings) and landscape (for exterior cells). Cells frequently From dafe184220dc2790435c212e7bbe43fe9ccc1ebb Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 22 Jul 2016 02:12:03 +0200 Subject: [PATCH 18/46] Fix moved references disappearing when modified by a plugin --- apps/openmw/mwworld/store.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index fbe94b7d0..c13f10d9a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -675,14 +675,17 @@ namespace MWWorld for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { // remove reference from current leased ref tracker and add it to new cell ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); - if (itold != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = *itold; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - ESM::CellRefTracker::iterator it_lease = std::find_if(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(it->mRefNum)); - if (it_lease != wipecell->mLeasedRefs.end()) - wipecell->mLeasedRefs.erase(it_lease); - else - std::cerr << "can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs " << std::endl; + if (itold != oldcell->mMovedRefs.end()) + { + if (it->mTarget[0] != itold->mTarget[0] || it->mTarget[1] != itold->mTarget[1]) + { + ESM::Cell *wipecell = const_cast(search(itold->mTarget[0], itold->mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find_if(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(it->mRefNum)); + if (it_lease != wipecell->mLeasedRefs.end()) + wipecell->mLeasedRefs.erase(it_lease); + else + std::cerr << "can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs " << std::endl; + } *itold = *it; } else From 4a3529488b45e0020d1ae35400f49210bbb18760 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 22 Jul 2016 03:58:23 +0200 Subject: [PATCH 19/46] Fix possible reference duplication when the refID is modified by a plugin (Bug #3471) --- apps/openmw/mwworld/cellreflist.hpp | 12 ++++++++ apps/openmw/mwworld/cellstore.cpp | 48 ++++++++++++++++++++++++++--- apps/openmw/mwworld/cellstore.hpp | 2 +- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 4d503dcc8..30be4a661 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -29,6 +29,18 @@ namespace MWWorld mList.push_back(item); return mList.back(); } + + /// Remove all references with the given refNum from this list. + void remove (const ESM::RefNum &refNum) + { + for (typename List::iterator it = mList.begin(); it != mList.end();) + { + if (*it == refNum) + mList.erase(it++); + else + ++it; + } + } }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 31b8a1515..db3707441 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -516,6 +516,8 @@ namespace MWWorld if (mCell->mContextList.empty()) return; // this is a dynamically generated cell -> skipping. + std::map refNumToID; // used to detect refID modifications + // Load references from all plugins that do something with this cell. for (size_t i = 0; i < mCell->mContextList.size(); i++) { @@ -539,7 +541,7 @@ namespace MWWorld continue; } - loadRef (ref, deleted); + loadRef (ref, deleted, refNumToID); } } catch (std::exception& e) @@ -554,7 +556,7 @@ namespace MWWorld ESM::CellRef &ref = const_cast(it->first); bool deleted = it->second; - loadRef (ref, deleted); + loadRef (ref, deleted, refNumToID); } updateMergedRefs(); @@ -585,12 +587,47 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, bool deleted) + void CellStore::loadRef (ESM::CellRef& ref, bool deleted, std::map& refNumToID) { Misc::StringUtils::lowerCaseInPlace (ref.mRefID); const MWWorld::ESMStore& store = mStore; + std::map::iterator it = refNumToID.find(ref.mRefNum); + if (it != refNumToID.end()) + { + if (it->second != ref.mRefID) + { + // refID was modified, make sure we don't end up with duplicated refs + switch (store.find(it->second)) + { + case ESM::REC_ACTI: mActivators.remove(ref.mRefNum); break; + case ESM::REC_ALCH: mPotions.remove(ref.mRefNum); break; + case ESM::REC_APPA: mAppas.remove(ref.mRefNum); break; + case ESM::REC_ARMO: mArmors.remove(ref.mRefNum); break; + case ESM::REC_BOOK: mBooks.remove(ref.mRefNum); break; + case ESM::REC_CLOT: mClothes.remove(ref.mRefNum); break; + case ESM::REC_CONT: mContainers.remove(ref.mRefNum); break; + case ESM::REC_CREA: mCreatures.remove(ref.mRefNum); break; + case ESM::REC_DOOR: mDoors.remove(ref.mRefNum); break; + case ESM::REC_INGR: mIngreds.remove(ref.mRefNum); break; + case ESM::REC_LEVC: mCreatureLists.remove(ref.mRefNum); break; + case ESM::REC_LEVI: mItemLists.remove(ref.mRefNum); break; + case ESM::REC_LIGH: mLights.remove(ref.mRefNum); break; + case ESM::REC_LOCK: mLockpicks.remove(ref.mRefNum); break; + case ESM::REC_MISC: mMiscItems.remove(ref.mRefNum); break; + case ESM::REC_NPC_: mNpcs.remove(ref.mRefNum); break; + case ESM::REC_PROB: mProbes.remove(ref.mRefNum); break; + case ESM::REC_REPA: mRepairs.remove(ref.mRefNum); break; + case ESM::REC_STAT: mStatics.remove(ref.mRefNum); break; + case ESM::REC_WEAP: mWeapons.remove(ref.mRefNum); break; + case ESM::REC_BODY: mBodyParts.remove(ref.mRefNum); break; + default: + break; + } + } + } + switch (store.find (ref.mRefID)) { case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; @@ -615,12 +652,15 @@ namespace MWWorld case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; case ESM::REC_BODY: mBodyParts.load(ref, deleted, store); break; - case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; break; + case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; return; default: std::cerr << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + return; } + + refNumToID[ref.mRefNum] = ref.mRefID; } void CellStore::loadState (const ESM::CellState& state) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 36cc7f5eb..1aee13132 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -385,7 +385,7 @@ namespace MWWorld void loadRefs(); - void loadRef (ESM::CellRef& ref, bool deleted); + void loadRef (ESM::CellRef& ref, bool deleted, std::map& refNumToID); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. From 455d227f3c6eeb727b9aa805b7307ef01162c81a Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 22 Jul 2016 01:58:17 -0400 Subject: [PATCH 20/46] Changed shortcut design to allow a configurable second output. Also re-added shift for temporarily changing camera speed. --- apps/opencs/model/prefs/shortcut.cpp | 77 ++++++++++--- apps/opencs/model/prefs/shortcut.hpp | 52 +++++++-- .../model/prefs/shortcuteventhandler.cpp | 105 +++++++++++++++--- .../model/prefs/shortcuteventhandler.hpp | 4 +- apps/opencs/model/prefs/shortcutmanager.cpp | 100 +++++++++++++---- apps/opencs/model/prefs/shortcutmanager.hpp | 13 ++- apps/opencs/model/prefs/shortcutsetting.cpp | 6 +- apps/opencs/model/prefs/shortcutsetting.hpp | 10 +- apps/opencs/model/prefs/state.cpp | 12 +- apps/opencs/model/prefs/state.hpp | 3 +- apps/opencs/view/render/cameracontroller.cpp | 27 ++++- apps/opencs/view/render/cameracontroller.hpp | 8 +- 12 files changed, 332 insertions(+), 85 deletions(-) diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index b8820ae8b..4aa6f0d84 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -11,24 +11,41 @@ namespace CSMPrefs { Shortcut::Shortcut(const std::string& name, QObject* parent) : QObject(parent) + , mEnabled(true) , mName(name) + , mSecondaryMode(SM_Ignore) + , mModifier(0) , mCurrentPos(0) , mLastPos(0) - , mActive(false) - , mEnabled(true) + , mActivationStatus(AS_Inactive) + , mModifierStatus(false) { State::get().getShortcutManager().addShortcut(this); - setSequence(State::get().getShortcutManager().getSequence(name)); + ShortcutManager::SequenceData data = State::get().getShortcutManager().getSequence(name); + setSequence(data.first); + setModifier(data.second); } - Shortcut::~Shortcut() + Shortcut::Shortcut(const std::string& name, SecondaryMode secMode, QObject* parent) + : QObject(parent) + , mEnabled(true) + , mName(name) + , mSecondaryMode(secMode) + , mModifier(0) + , mCurrentPos(0) + , mLastPos(0) + , mActivationStatus(AS_Inactive) + , mModifierStatus(false) { - State::get().getShortcutManager().removeShortcut(this); + State::get().getShortcutManager().addShortcut(this); + ShortcutManager::SequenceData data = State::get().getShortcutManager().getSequence(name); + setSequence(data.first); + setModifier(data.second); } - bool Shortcut::isActive() const + Shortcut::~Shortcut() { - return mActive; + State::get().getShortcutManager().removeShortcut(this); } bool Shortcut::isEnabled() const @@ -41,11 +58,21 @@ namespace CSMPrefs return mName; } + Shortcut::SecondaryMode Shortcut::getSecondaryMode() const + { + return mSecondaryMode; + } + const QKeySequence& Shortcut::getSequence() const { return mSequence; } + int Shortcut::getModifier() const + { + return mModifier; + } + int Shortcut::getPosition() const { return mCurrentPos; @@ -56,9 +83,19 @@ namespace CSMPrefs return mLastPos; } - void Shortcut::setPosition(int pos) + Shortcut::ActivationStatus Shortcut::getActivationStatus() const { - mCurrentPos = pos; + return mActivationStatus; + } + + bool Shortcut::getModifierStatus() const + { + return mModifierStatus; + } + + void Shortcut::enable(bool state) + { + mEnabled = state; } void Shortcut::setSequence(const QKeySequence& sequence) @@ -68,22 +105,28 @@ namespace CSMPrefs mLastPos = sequence.count() - 1; } - void Shortcut::activate(bool state) + void Shortcut::setModifier(int modifier) { - mActive = state; - emit activated(state); + mModifier = modifier; + } - if (state) - emit activated(); + void Shortcut::setPosition(int pos) + { + mCurrentPos = pos; } - void Shortcut::enable(bool state) + void Shortcut::setActivationStatus(ActivationStatus status) { - mEnabled = state; + mActivationStatus = status; + } + + void Shortcut::setModifierStatus(bool status) + { + mModifierStatus = status; } QString Shortcut::toString() const { - return QString(State::get().getShortcutManager().sequenceToString(mSequence).data()); + return QString(State::get().getShortcutManager().sequenceToString(std::make_pair(mSequence, mModifier)).data()); } } diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index 25bb13556..491cd7667 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -20,45 +20,83 @@ namespace CSMPrefs public: + enum ActivationStatus + { + AS_Regular, + AS_Secondary, + AS_Inactive + }; + + enum SecondaryMode + { + SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active + SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active + SM_Ignore ///< The secondary signal will not ever be emitted + }; + Shortcut(const std::string& name, QObject* parent); + Shortcut(const std::string& name, SecondaryMode secMode, QObject* parent); + ~Shortcut(); - bool isActive() const; bool isEnabled() const; const std::string& getName() const; + SecondaryMode getSecondaryMode() const; + const QKeySequence& getSequence() const; + int getModifier() const; + /// The position in the sequence int getPosition() const; /// The position in the sequence int getLastPosition() const; + ActivationStatus getActivationStatus() const; + bool getModifierStatus() const; + + void enable(bool state); + void setSequence(const QKeySequence& sequence); + void setModifier(int modifier); + /// The position in the sequence void setPosition(int pos); - void activate(bool state); - void enable(bool state); + void setActivationStatus(ActivationStatus status); + void setModifierStatus(bool status); QString toString() const; private: + bool mEnabled; + std::string mName; + SecondaryMode mSecondaryMode; QKeySequence mSequence; + int mModifier; + int mCurrentPos; int mLastPos; - bool mActive; - bool mEnabled; + ActivationStatus mActivationStatus; + bool mModifierStatus; + signals: - /// Triggered when the shortcut is activated or deactived; can be determined from \p state + /// Triggered when the shortcut is activated or deactivated; can be determined from \p state void activated(bool state); - /// Trigger when activated; convenience signal. + /// Convenience signal. void activated(); + + /// Triggered depending on SecondaryMode + void secondary(bool state); + + /// Convenience signal. + void secondary(); }; } diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index 3119623ae..0537c53a2 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -41,10 +41,11 @@ namespace CSMPrefs else if (event->type() == QEvent::KeyRelease) { QKeyEvent* keyEvent = static_cast(event); + unsigned int mod = (unsigned int) keyEvent->modifiers(); unsigned int key = (unsigned int) keyEvent->key(); if (!keyEvent->isAutoRepeat()) - return deactivate(key); + return deactivate(mod, key); } else if (event->type() == QEvent::MouseButtonPress) { @@ -57,9 +58,10 @@ namespace CSMPrefs else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent* mouseEvent = static_cast(event); + unsigned int mod = (unsigned int) mouseEvent->modifiers(); unsigned int button = (unsigned int) mouseEvent->button(); - return deactivate(button); + return deactivate(mod, button); } else if (event->type() == QEvent::FocusOut) { @@ -68,10 +70,18 @@ namespace CSMPrefs { Shortcut* shortcut = *it; - if (shortcut->isActive()) + shortcut->setPosition(0); + shortcut->setModifierStatus(false); + + if (shortcut->getActivationStatus() == Shortcut::AS_Regular) { - shortcut->activate(false); - shortcut->setPosition(0); + shortcut->setActivationStatus(Shortcut::AS_Inactive); + emit shortcut->activated(false); + } + else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) + { + shortcut->setActivationStatus(Shortcut::AS_Inactive); + emit shortcut->secondary(false); } } } @@ -88,39 +98,56 @@ namespace CSMPrefs for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) { Shortcut* shortcut = *it; - int pos = shortcut->getPosition(); - int lastPos = shortcut->getLastPosition(); - MatchResult result = match(mod, button, shortcut->getSequence()[pos]); if (!shortcut->isEnabled()) continue; + int pos = shortcut->getPosition(); + int lastPos = shortcut->getLastPosition(); + MatchResult result = match(mod, button, shortcut->getSequence()[pos]); + if (result == Matches_WithMod || result == Matches_NoMod) { if (pos < lastPos && (result == Matches_WithMod || pos > 0)) { shortcut->setPosition(pos+1); - used = true; } else if (pos == lastPos) { potentials.push_back(std::make_pair(result, shortcut)); } } + + if (checkModifier(mod, button, shortcut, true)) + used = true; } // Only activate the best match; in exact conflicts, this will favor the first shortcut added. if (!potentials.empty()) { std::sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort); - potentials.front().second->activate(true); + Shortcut* shortcut = potentials.front().second; + + if (shortcut->getModifierStatus() && shortcut->getSecondaryMode() == Shortcut::SM_Replace) + { + shortcut->setActivationStatus(Shortcut::AS_Secondary); + emit shortcut->secondary(true); + emit shortcut->secondary(); + } + else + { + shortcut->setActivationStatus(Shortcut::AS_Regular); + emit shortcut->activated(true); + emit shortcut->activated(); + } + used = true; } return used; } - bool ShortcutEventHandler::deactivate(unsigned int button) + bool ShortcutEventHandler::deactivate(unsigned int mod, unsigned int button) { const int KeyMask = 0x01FFFFFF; @@ -129,16 +156,66 @@ namespace CSMPrefs for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) { Shortcut* shortcut = *it; + + if (checkModifier(mod, button, shortcut, false)) + used = true; + int pos = shortcut->getPosition(); MatchResult result = match(0, button, shortcut->getSequence()[pos] & KeyMask); if (result != Matches_Not) { - if (shortcut->isActive()) - shortcut->activate(false); - shortcut->setPosition(0); + if (shortcut->getActivationStatus() == Shortcut::AS_Regular) + { + shortcut->setActivationStatus(Shortcut::AS_Inactive); + emit shortcut->activated(false); + used = true; + } + else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) + { + shortcut->setActivationStatus(Shortcut::AS_Inactive); + emit shortcut->secondary(false); + used = true; + } + } + } + + return used; + } + + bool ShortcutEventHandler::checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate) + { + if (!shortcut->isEnabled() || !shortcut->getModifier() || shortcut->getSecondaryMode() == Shortcut::SM_Ignore) + return false; + + MatchResult result = match(mod, button, shortcut->getModifier()); + bool used = false; + + if (result != Matches_Not) + { + shortcut->setModifierStatus(activate); + + if (shortcut->getSecondaryMode() == Shortcut::SM_Detach) + { + if (activate) + { + emit shortcut->secondary(true); + emit shortcut->secondary(); + } + else + { + emit shortcut->secondary(false); + } + + used = true; + } + else if (!activate && shortcut->getActivationStatus() == Shortcut::AS_Secondary) + { + shortcut->setActivationStatus(Shortcut::AS_Inactive); + shortcut->setPosition(0); + emit shortcut->secondary(false); used = true; } } diff --git a/apps/opencs/model/prefs/shortcuteventhandler.hpp b/apps/opencs/model/prefs/shortcuteventhandler.hpp index c1ce48f7e..d6a0d16ec 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.hpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.hpp @@ -39,7 +39,9 @@ namespace CSMPrefs bool activate(unsigned int mod, unsigned int button); - bool deactivate(unsigned int button); + bool deactivate(unsigned int mod, unsigned int button); + + bool checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate); MatchResult match(unsigned int mod, unsigned int button, unsigned int value); diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index a4b9b1818..198804b3d 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -33,31 +33,31 @@ namespace CSMPrefs } } - QKeySequence ShortcutManager::getSequence(const std::string& name) const + ShortcutManager::SequenceData ShortcutManager::getSequence(const std::string& name) const { - QKeySequence sequence; + SequenceData data; SequenceMap::const_iterator item = mSequences.find(name); if (item != mSequences.end()) { - sequence = item->second; + data = item->second; } - return sequence; + return data; } - void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence) + void ShortcutManager::setSequence(const std::string& name, const SequenceData& data) { // Add to map/modify SequenceMap::iterator item = mSequences.find(name); if (item != mSequences.end()) { - item->second = sequence; + item->second = data; } else { - mSequences.insert(std::make_pair(name, sequence)); + mSequences.insert(std::make_pair(name, data)); } // Change active shortcuts @@ -65,11 +65,12 @@ namespace CSMPrefs for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) { - it->second->setSequence(sequence); + it->second->setSequence(data.first); + it->second->setModifier(data.second); } } - std::string ShortcutManager::sequenceToString(const QKeySequence& seq) + std::string ShortcutManager::sequenceToString(const SequenceData& data) { const int MouseMask = 0x0000001F; // Conflicts with key const int KeyMask = 0x01FFFFFF; @@ -80,27 +81,28 @@ namespace CSMPrefs std::string output; - for (int i = 0; i < seq.count(); ++i) + // KeySequence + for (unsigned int i = 0; i < data.first.count(); ++i) { - if (seq[i] & ModMask) + if (data.first[i] & ModMask) { // TODO separate out modifiers to allow more than 1 - output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(seq[i] & ModMask)); + output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(data.first[i] & ModMask)); output.append("+"); } - if (seq[i] & KeyMask & ~MouseMask) + if (data.first[i] & KeyMask & ~MouseMask) { // Is a key - output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(seq[i] & KeyMask)); + output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(data.first[i] & KeyMask)); output.append(","); } - else if (seq[i] & MouseMask) + else if (data.first[i] & MouseMask) { std::stringstream ss; std::string num; - unsigned int value = (unsigned int)(seq[i] & MouseMask); + unsigned int value = (unsigned int)(data.first[i] & MouseMask); // value will never be 0 int exponent = 1; // Offset by 1 @@ -123,18 +125,56 @@ namespace CSMPrefs output.resize(output.size() - 1); } + // Add modifier if needed + if (data.second & ModMask) + { + output.append(";"); + output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(data.second & ModMask)); + } + else if (data.second & KeyMask & ~MouseMask) + { + output.append(";"); + output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(data.second & KeyMask)); + } + else if (data.second & MouseMask) + { + std::stringstream ss; + std::string num; + + unsigned int value = (unsigned int)(data.second & MouseMask); + + // value will never be 0 + int exponent = 1; // Offset by 1 + while (value >>= 1) + ++exponent; + + ss << exponent; + ss >> num; + + // Is a mouse button + output.append(";Mouse"); + output.append(num); + } + return output; } - QKeySequence ShortcutManager::stringToSequence(const std::string& input) + ShortcutManager::SequenceData ShortcutManager::stringToSequence(const std::string& input) { + // TODO clean and standardize + const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); int keys[4] = { 0, 0, 0, 0 }; + int modifier = 0; + + size_t middle = input.find(';'); + std::string sequenceStr = input.substr(0, middle); + std::string modifierStr = input.substr((middle < input.size())? middle + 1 : input.size()); QRegExp splitRX("[, ]"); - QStringList keyStrs = QString(input.c_str()).split(splitRX, QString::SkipEmptyParts); + QStringList keyStrs = QString(sequenceStr.c_str()).split(splitRX, QString::SkipEmptyParts); for (int i = 0; i < keyStrs.size(); ++i) { @@ -162,9 +202,29 @@ namespace CSMPrefs } } + if (!modifierStr.empty()) + { + if (modifierStr.find("Mouse") != std::string::npos) + { + QString num = QString::fromUtf8(modifierStr.substr(5).data()); + if (num > 0) + { + modifier = 1 << (num.toInt() - 1); // offset by 1 + } + } + else if (staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(modifierStr.data()) != -1) + { + modifier = staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(modifierStr.data()); + } + else if (staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(modifierStr.data()) != -1) + { + modifier = staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(modifierStr.data()); + } + } + // TODO remove - std::cout << input << '.' << keys[0] << '.'<< keys[1] << '.'<< keys[2] << '.'<< keys[3] << std::endl; + std::cout << input << '.' << keys[0] << '.'<< keys[1] << '.'<< keys[2] << '.'<< keys[3] << '.' << modifier << std::endl; - return QKeySequence(keys[0], keys[1], keys[2], keys[3]); + return std::make_pair(QKeySequence(keys[0], keys[1], keys[2], keys[3]), modifier); } } diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index 2510ec77e..60cdefe36 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -17,23 +17,26 @@ namespace CSMPrefs public: + /// Key Sequence, Modifier (for secondary signal) + typedef std::pair SequenceData; + /// The shortcut class will do this automatically void addShortcut(Shortcut* shortcut); /// The shortcut class will do this automatically void removeShortcut(Shortcut* shortcut); - QKeySequence getSequence(const std::string& name) const; - void setSequence(const std::string& name, const QKeySequence& sequence); + SequenceData getSequence(const std::string& name) const; + void setSequence(const std::string& name, const SequenceData& sequence); - std::string sequenceToString(const QKeySequence& sequence); - QKeySequence stringToSequence(const std::string& str); + std::string sequenceToString(const SequenceData& sequence); + SequenceData stringToSequence(const std::string& str); private: // Need a multimap in case multiple shortcuts share the same name typedef std::multimap ShortcutMap; - typedef std::map SequenceMap; + typedef std::map SequenceMap; ShortcutMap mShortcuts; SequenceMap mSequences; diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 5b2008241..fa2628e32 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -10,7 +10,7 @@ namespace CSMPrefs { ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, - const std::string& label, const QKeySequence& default_) + const std::string& label, const SequenceData& default_) : Setting(parent, values, mutex, key, label) , mDefault(default_) { @@ -33,9 +33,9 @@ namespace CSMPrefs QMutexLocker lock(getMutex()); getValues().setString(getKey(), getParent()->getKey(), text.toUtf8().data()); - QKeySequence sequence = State::get().getShortcutManager().stringToSequence(text.toUtf8().data()); + SequenceData data = State::get().getShortcutManager().stringToSequence(text.toUtf8().data()); - State::get().getShortcutManager().setSequence(getKey(), sequence); + State::get().getShortcutManager().setSequence(getKey(), data); } getParent()->getState()->update(*this); diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp index 893b01f93..e1979c800 100644 --- a/apps/opencs/model/prefs/shortcutsetting.hpp +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -11,16 +11,20 @@ namespace CSMPrefs { Q_OBJECT - QKeySequence mDefault; - public: + typedef std::pair SequenceData; + ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, - const std::string& label, const QKeySequence& default_); + const std::string& label, const SequenceData& default_); // TODO replace with custom page virtual std::pair makeWidgets(QWidget* parent); + private: + + SequenceData mDefault; + private slots: void valueChanged(const QString& text); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 417209380..cfb06f21a 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -229,7 +229,7 @@ void CSMPrefs::State::declare() addValues (insertOutsideVisibleCell); declareCategory ("Key Bindings"); - declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W)); + declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); declareShortcut ("free-left", "Free camera left", QKeySequence(Qt::Key_A)); declareShortcut ("free-right", "Free camera right", QKeySequence(Qt::Key_D)); @@ -238,7 +238,7 @@ void CSMPrefs::State::declare() declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); declareSeparator (); - declareShortcut ("orbit-up", "Orbit camera up", QKeySequence(Qt::Key_W)); + declareShortcut ("orbit-up", "Orbit camera up", QKeySequence(Qt::Key_W), Qt::Key_Shift); declareShortcut ("orbit-down", "Orbit camera down", QKeySequence(Qt::Key_S)); declareShortcut ("orbit-left", "Orbit camera left", QKeySequence(Qt::Key_A)); declareShortcut ("orbit-right", "Orbit camera right", QKeySequence(Qt::Key_D)); @@ -377,19 +377,19 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, } CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_) + const QKeySequence& default_, int modifier) { if (mCurrentCategory==mCategories.end()) throw std::logic_error ("no category for setting"); - std::string seqStr = getShortcutManager().sequenceToString(default_); + std::string seqStr = getShortcutManager().sequenceToString(std::make_pair(default_, modifier)); setDefault (key, seqStr); - QKeySequence seq = getShortcutManager().stringToSequence(mSettings.getString(key, + ShortcutManager::SequenceData data = getShortcutManager().stringToSequence(mSettings.getString(key, mCurrentCategory->second.getKey())); CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, - key, label, seq); + key, label, data); mCurrentCategory->second.addSetting (setting); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 15f6e6d1b..4ab713167 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -74,7 +74,8 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); - ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, const QKeySequence& default_); + ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, + const QKeySequence& default_, int modifier=0); void declareSeparator(); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 642991b36..df71a9b88 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -169,6 +169,7 @@ namespace CSVRender , mLockUpright(false) , mModified(false) , mFast(false) + , mFastAlternate(false) , mLeft(false) , mRight(false) , mForward(false) @@ -190,10 +191,12 @@ namespace CSVRender handler->addShortcut(naviSecondaryShortcut); connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool))); - CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", this); + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", CSMPrefs::Shortcut::SM_Detach, + this); forwardShortcut->enable(false); handler->addShortcut(forwardShortcut); connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); + connect(forwardShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", this); leftShortcut->enable(false); @@ -294,7 +297,7 @@ namespace CSVRender if (!isActive()) return; - translate(LocalForward * x * (mFast ? getWheelMovementMultiplier() : 1)); + translate(LocalForward * x * ((mFast ^ mFastAlternate) ? getWheelMovementMultiplier() : 1)); } void FreeCameraController::update(double dt) @@ -305,7 +308,7 @@ namespace CSVRender double linDist = mLinSpeed * dt; double rotDist = mRotSpeed * dt; - if (mFast) + if (mFast ^ mFastAlternate) linDist *= mSpeedMult; if (mLeft) @@ -423,6 +426,11 @@ namespace CSVRender mRollRight = active; } + void FreeCameraController::alternateFast(bool active) + { + mFastAlternate = active; + } + void FreeCameraController::swapSpeedMode() { mFast = !mFast; @@ -436,6 +444,7 @@ namespace CSVRender : CameraController(parent) , mInitialized(false) , mFast(false) + , mFastAlternate(false) , mLeft(false) , mRight(false) , mUp(false) @@ -458,10 +467,11 @@ namespace CSVRender handler->addShortcut(naviSecondaryShortcut); connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool))); - CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", this); + CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", CSMPrefs::Shortcut::SM_Detach, this); upShortcut->enable(false); handler->addShortcut(upShortcut); connect(upShortcut, SIGNAL(activated(bool)), this, SLOT(up(bool))); + connect(upShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("orbit-left", this); leftShortcut->enable(false); @@ -571,7 +581,7 @@ namespace CSVRender if (!isActive()) return; - zoom(-x * (mFast ? getWheelMovementMultiplier() : 1)); + zoom(-x * ((mFast ^ mFastAlternate) ? getWheelMovementMultiplier() : 1)); } void OrbitCameraController::update(double dt) @@ -584,7 +594,7 @@ namespace CSVRender double rotDist = mOrbitSpeed * dt; - if (mFast) + if (mFast ^ mFastAlternate) rotDist *= mOrbitSpeedMult; if (mLeft) @@ -737,6 +747,11 @@ namespace CSVRender mRollRight = active; } + void OrbitCameraController::alternateFast(bool active) + { + mFastAlternate = active; + } + void OrbitCameraController::swapSpeedMode() { mFast = !mFast; diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index 7cca048d8..45ccfc14e 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -111,7 +111,8 @@ namespace CSVRender bool mLockUpright, mModified; bool mNaviPrimary, mNaviSecondary; - bool mFast, mLeft, mRight, mForward, mBackward, mRollLeft, mRollRight; + bool mFast, mFastAlternate; + bool mLeft, mRight, mForward, mBackward, mRollLeft, mRollRight; osg::Vec3d mUp; double mLinSpeed; @@ -128,6 +129,7 @@ namespace CSVRender void right(bool active); void rollLeft(bool active); void rollRight(bool active); + void alternateFast(bool active); void swapSpeedMode(); }; @@ -168,7 +170,8 @@ namespace CSVRender bool mInitialized; bool mNaviPrimary, mNaviSecondary; - bool mFast, mLeft, mRight, mUp, mDown, mRollLeft, mRollRight; + bool mFast, mFastAlternate; + bool mLeft, mRight, mUp, mDown, mRollLeft, mRollRight; unsigned int mPickingMask; osg::Vec3d mCenter; double mDistance; @@ -186,6 +189,7 @@ namespace CSVRender void right(bool active); void rollLeft(bool active); void rollRight(bool active); + void alternateFast(bool active); void swapSpeedMode(); }; } From acdb6369359eb2bf29fd50d7d24d894d6c8636ff Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 22 Jul 2016 02:41:00 -0400 Subject: [PATCH 21/46] Qt4 protected signal workaround and signed/unsigned mismatch. --- apps/opencs/model/prefs/shortcut.cpp | 19 +++++++++++++++ apps/opencs/model/prefs/shortcut.hpp | 8 ++++++- .../model/prefs/shortcuteventhandler.cpp | 24 +++++++++---------- apps/opencs/model/prefs/shortcutmanager.cpp | 2 +- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index 4aa6f0d84..247dadf99 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -125,6 +125,25 @@ namespace CSMPrefs mModifierStatus = status; } + void Shortcut::signalActivated(bool state) + { + emit activated(state); + } + + void Shortcut::signalActivated() + { + emit activated(); + } + + void Shortcut::signalSecondary(bool state) + { + emit secondary(state); + } + void Shortcut::signalSecondary() + { + emit secondary(); + } + QString Shortcut::toString() const { return QString(State::get().getShortcutManager().sequenceToString(std::make_pair(mSequence, mModifier)).data()); diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index 491cd7667..af3a20c06 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -66,6 +66,13 @@ namespace CSMPrefs void setActivationStatus(ActivationStatus status); void setModifierStatus(bool status); + // Workaround for Qt4 signals being "protected" + void signalActivated(bool state); + void signalActivated(); + + void signalSecondary(bool state); + void signalSecondary(); + QString toString() const; private: @@ -83,7 +90,6 @@ namespace CSMPrefs ActivationStatus mActivationStatus; bool mModifierStatus; - signals: /// Triggered when the shortcut is activated or deactivated; can be determined from \p state diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index 0537c53a2..c04f9e310 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -76,12 +76,12 @@ namespace CSMPrefs if (shortcut->getActivationStatus() == Shortcut::AS_Regular) { shortcut->setActivationStatus(Shortcut::AS_Inactive); - emit shortcut->activated(false); + shortcut->signalActivated(false); } else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) { shortcut->setActivationStatus(Shortcut::AS_Inactive); - emit shortcut->secondary(false); + shortcut->signalSecondary(false); } } } @@ -131,14 +131,14 @@ namespace CSMPrefs if (shortcut->getModifierStatus() && shortcut->getSecondaryMode() == Shortcut::SM_Replace) { shortcut->setActivationStatus(Shortcut::AS_Secondary); - emit shortcut->secondary(true); - emit shortcut->secondary(); + shortcut->signalSecondary(true); + shortcut->signalSecondary(); } else { shortcut->setActivationStatus(Shortcut::AS_Regular); - emit shortcut->activated(true); - emit shortcut->activated(); + shortcut->signalActivated(true); + shortcut->signalActivated(); } used = true; @@ -170,13 +170,13 @@ namespace CSMPrefs if (shortcut->getActivationStatus() == Shortcut::AS_Regular) { shortcut->setActivationStatus(Shortcut::AS_Inactive); - emit shortcut->activated(false); + shortcut->signalActivated(false); used = true; } else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) { shortcut->setActivationStatus(Shortcut::AS_Inactive); - emit shortcut->secondary(false); + shortcut->signalSecondary(false); used = true; } } @@ -201,12 +201,12 @@ namespace CSMPrefs { if (activate) { - emit shortcut->secondary(true); - emit shortcut->secondary(); + shortcut->signalSecondary(true); + shortcut->signalSecondary(); } else { - emit shortcut->secondary(false); + shortcut->signalSecondary(false); } used = true; @@ -215,7 +215,7 @@ namespace CSMPrefs { shortcut->setActivationStatus(Shortcut::AS_Inactive); shortcut->setPosition(0); - emit shortcut->secondary(false); + shortcut->signalSecondary(false); used = true; } } diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 198804b3d..f8e9ccb8a 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -82,7 +82,7 @@ namespace CSMPrefs std::string output; // KeySequence - for (unsigned int i = 0; i < data.first.count(); ++i) + for (int i = 0; i < data.first.count(); ++i) { if (data.first[i] & ModMask) { From f251c3867dc58a3f7a8abaaf2c12b6a963e8b38b Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sat, 23 Jul 2016 21:23:02 -0400 Subject: [PATCH 22/46] Redesigned shortcut handler to be capable of dealing with child and parent widgets. This should be the final design change. Also, some various bug fixes. --- apps/opencs/model/prefs/shortcut.cpp | 14 +- apps/opencs/model/prefs/shortcut.hpp | 8 +- .../model/prefs/shortcuteventhandler.cpp | 188 +++++++++++++----- .../model/prefs/shortcuteventhandler.hpp | 21 +- apps/opencs/model/prefs/shortcutmanager.cpp | 10 + apps/opencs/model/prefs/shortcutmanager.hpp | 6 + apps/opencs/model/prefs/state.cpp | 4 + apps/opencs/view/doc/view.cpp | 4 + apps/opencs/view/render/cameracontroller.cpp | 132 ++++++------ apps/opencs/view/render/cameracontroller.hpp | 13 +- apps/opencs/view/render/orbitcameramode.cpp | 11 +- apps/opencs/view/render/orbitcameramode.hpp | 10 +- apps/opencs/view/render/scenewidget.cpp | 11 +- apps/opencs/view/render/scenewidget.hpp | 4 - apps/opencs/view/render/worldspacewidget.cpp | 7 +- apps/opencs/view/render/worldspacewidget.hpp | 1 - 16 files changed, 284 insertions(+), 160 deletions(-) diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index 247dadf99..c0682fed3 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -1,15 +1,15 @@ #include "shortcut.hpp" -#include -#include -#include +#include + +#include #include "state.hpp" #include "shortcutmanager.hpp" namespace CSMPrefs { - Shortcut::Shortcut(const std::string& name, QObject* parent) + Shortcut::Shortcut(const std::string& name, QWidget* parent) : QObject(parent) , mEnabled(true) , mName(name) @@ -20,13 +20,15 @@ namespace CSMPrefs , mActivationStatus(AS_Inactive) , mModifierStatus(false) { + assert (parent); + State::get().getShortcutManager().addShortcut(this); ShortcutManager::SequenceData data = State::get().getShortcutManager().getSequence(name); setSequence(data.first); setModifier(data.second); } - Shortcut::Shortcut(const std::string& name, SecondaryMode secMode, QObject* parent) + Shortcut::Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent) : QObject(parent) , mEnabled(true) , mName(name) @@ -37,6 +39,8 @@ namespace CSMPrefs , mActivationStatus(AS_Inactive) , mModifierStatus(false) { + assert (parent); + State::get().getShortcutManager().addShortcut(this); ShortcutManager::SequenceData data = State::get().getShortcutManager().getSequence(name); setSequence(data.first); diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index af3a20c06..2df47f382 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -7,9 +7,7 @@ #include #include -class QKeyEvent; -class QMouseEvent; -class QShortcut; +class QWidget; namespace CSMPrefs { @@ -34,8 +32,8 @@ namespace CSMPrefs SM_Ignore ///< The secondary signal will not ever be emitted }; - Shortcut(const std::string& name, QObject* parent); - Shortcut(const std::string& name, SecondaryMode secMode, QObject* parent); + Shortcut(const std::string& name, QWidget* parent); + Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent); ~Shortcut(); diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index c04f9e310..341881367 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -1,7 +1,7 @@ #include "shortcuteventhandler.hpp" #include -#include +#include #include #include @@ -19,54 +19,88 @@ namespace CSMPrefs void ShortcutEventHandler::addShortcut(Shortcut* shortcut) { - mShortcuts.push_back(shortcut); + // Enforced by shortcut class + QWidget* widget = static_cast(shortcut->parent()); + + // Check if widget setup is needed + ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); + if (shortcutListIt == mWidgetShortcuts.end()) + { + // Create list + shortcutListIt = mWidgetShortcuts.insert(std::make_pair(widget, ShortcutList())).first; + + // Check if widget has a parent with shortcuts, unfortunately it is not typically set yet + updateParent(widget); + + // Intercept widget events + widget->installEventFilter(this); + connect(widget, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); + } + + // Add to list + shortcutListIt->second.push_back(shortcut); } void ShortcutEventHandler::removeShortcut(Shortcut* shortcut) { - std::remove(mShortcuts.begin(), mShortcuts.end(), shortcut); + // Enforced by shortcut class + QWidget* widget = static_cast(shortcut->parent()); + + ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); + if (shortcutListIt != mWidgetShortcuts.end()) + { + std::remove(shortcutListIt->second.begin(), shortcutListIt->second.end(), shortcut); + } } bool ShortcutEventHandler::eventFilter(QObject* watched, QEvent* event) { + // Process event if (event->type() == QEvent::KeyPress) { + QWidget* widget = static_cast(watched); QKeyEvent* keyEvent = static_cast(event); unsigned int mod = (unsigned int) keyEvent->modifiers(); unsigned int key = (unsigned int) keyEvent->key(); if (!keyEvent->isAutoRepeat()) - return activate(mod, key); + return activate(widget, mod, key); } else if (event->type() == QEvent::KeyRelease) { + QWidget* widget = static_cast(watched); QKeyEvent* keyEvent = static_cast(event); unsigned int mod = (unsigned int) keyEvent->modifiers(); unsigned int key = (unsigned int) keyEvent->key(); if (!keyEvent->isAutoRepeat()) - return deactivate(mod, key); + return deactivate(widget, mod, key); } else if (event->type() == QEvent::MouseButtonPress) { + QWidget* widget = static_cast(watched); QMouseEvent* mouseEvent = static_cast(event); unsigned int mod = (unsigned int) mouseEvent->modifiers(); unsigned int button = (unsigned int) mouseEvent->button(); - return activate(mod, button); + return activate(widget, mod, button); } else if (event->type() == QEvent::MouseButtonRelease) { + QWidget* widget = static_cast(watched); QMouseEvent* mouseEvent = static_cast(event); unsigned int mod = (unsigned int) mouseEvent->modifiers(); unsigned int button = (unsigned int) mouseEvent->button(); - return deactivate(mod, button); + return deactivate(widget, mod, button); } else if (event->type() == QEvent::FocusOut) { + QWidget* widget = static_cast(watched); + ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); + // Deactivate in case events are missed - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it) { Shortcut* shortcut = *it; @@ -85,41 +119,76 @@ namespace CSMPrefs } } } + else if (event->type() == QEvent::FocusIn) + { + QWidget* widget = static_cast(watched); + updateParent(widget); + } return false; } - bool ShortcutEventHandler::activate(unsigned int mod, unsigned int button) + void ShortcutEventHandler::updateParent(QWidget* widget) + { + QWidget* parent = widget->parentWidget(); + while (parent) + { + ShortcutMap::iterator parentIt = mWidgetShortcuts.find(parent); + if (parentIt != mWidgetShortcuts.end()) + { + mChildParentRelations.insert(std::make_pair(widget, parent)); + break; + } + + // Check next + parent = parent->parentWidget(); + } + } + + bool ShortcutEventHandler::activate(QWidget* widget, unsigned int mod, unsigned int button) { std::vector > potentials; bool used = false; - // Find potential activations - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + while (widget) { - Shortcut* shortcut = *it; + ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); + assert(shortcutListIt != mWidgetShortcuts.end()); - if (!shortcut->isEnabled()) - continue; + // Find potential activations + for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it) + { + Shortcut* shortcut = *it; - int pos = shortcut->getPosition(); - int lastPos = shortcut->getLastPosition(); - MatchResult result = match(mod, button, shortcut->getSequence()[pos]); + if (!shortcut->isEnabled()) + continue; - if (result == Matches_WithMod || result == Matches_NoMod) - { - if (pos < lastPos && (result == Matches_WithMod || pos > 0)) - { - shortcut->setPosition(pos+1); - } - else if (pos == lastPos) + if (checkModifier(mod, button, shortcut, true)) + used = true; + + if (shortcut->getActivationStatus() != Shortcut::AS_Inactive) + continue; + + int pos = shortcut->getPosition(); + int lastPos = shortcut->getLastPosition(); + MatchResult result = match(mod, button, shortcut->getSequence()[pos]); + + if (result == Matches_WithMod || result == Matches_NoMod) { - potentials.push_back(std::make_pair(result, shortcut)); + if (pos < lastPos && (result == Matches_WithMod || pos > 0)) + { + shortcut->setPosition(pos+1); + } + else if (pos == lastPos) + { + potentials.push_back(std::make_pair(result, shortcut)); + } } } - if (checkModifier(mod, button, shortcut, true)) - used = true; + // Move on to parent + WidgetMap::iterator widgetIt = mChildParentRelations.find(widget); + widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0; } // Only activate the best match; in exact conflicts, this will favor the first shortcut added. @@ -147,39 +216,49 @@ namespace CSMPrefs return used; } - bool ShortcutEventHandler::deactivate(unsigned int mod, unsigned int button) + bool ShortcutEventHandler::deactivate(QWidget* widget, unsigned int mod, unsigned int button) { const int KeyMask = 0x01FFFFFF; bool used = false; - for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + while (widget) { - Shortcut* shortcut = *it; + ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); + assert(shortcutListIt != mWidgetShortcuts.end()); - if (checkModifier(mod, button, shortcut, false)) - used = true; - - int pos = shortcut->getPosition(); - MatchResult result = match(0, button, shortcut->getSequence()[pos] & KeyMask); - - if (result != Matches_Not) + for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it) { - shortcut->setPosition(0); + Shortcut* shortcut = *it; - if (shortcut->getActivationStatus() == Shortcut::AS_Regular) - { - shortcut->setActivationStatus(Shortcut::AS_Inactive); - shortcut->signalActivated(false); + if (checkModifier(mod, button, shortcut, false)) used = true; - } - else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) + + int pos = shortcut->getPosition(); + MatchResult result = match(0, button, shortcut->getSequence()[pos] & KeyMask); + + if (result != Matches_Not) { - shortcut->setActivationStatus(Shortcut::AS_Inactive); - shortcut->signalSecondary(false); - used = true; + shortcut->setPosition(0); + + if (shortcut->getActivationStatus() == Shortcut::AS_Regular) + { + shortcut->setActivationStatus(Shortcut::AS_Inactive); + shortcut->signalActivated(false); + used = true; + } + else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) + { + shortcut->setActivationStatus(Shortcut::AS_Inactive); + shortcut->signalSecondary(false); + used = true; + } } } + + // Move on to parent + WidgetMap::iterator widgetIt = mChildParentRelations.find(widget); + widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0; } return used; @@ -187,7 +266,8 @@ namespace CSMPrefs bool ShortcutEventHandler::checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate) { - if (!shortcut->isEnabled() || !shortcut->getModifier() || shortcut->getSecondaryMode() == Shortcut::SM_Ignore) + if (!shortcut->isEnabled() || !shortcut->getModifier() || shortcut->getSecondaryMode() == Shortcut::SM_Ignore || + shortcut->getModifierStatus() == activate) return false; MatchResult result = match(mod, button, shortcut->getModifier()); @@ -208,8 +288,6 @@ namespace CSMPrefs { shortcut->signalSecondary(false); } - - used = true; } else if (!activate && shortcut->getActivationStatus() == Shortcut::AS_Secondary) { @@ -243,9 +321,17 @@ namespace CSMPrefs bool ShortcutEventHandler::sort(const std::pair& left, const std::pair& right) { - if (left.first == Matches_WithMod && left.first != right.first) + if (left.first == Matches_WithMod && right.first == Matches_NoMod) return true; else return left.second->getPosition() >= right.second->getPosition(); } + + void ShortcutEventHandler::widgetDestroyed() + { + QWidget* widget = static_cast(sender()); + + mWidgetShortcuts.erase(widget); + mChildParentRelations.erase(widget); + } } diff --git a/apps/opencs/model/prefs/shortcuteventhandler.hpp b/apps/opencs/model/prefs/shortcuteventhandler.hpp index d6a0d16ec..6a7ba2522 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.hpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.hpp @@ -1,6 +1,7 @@ #ifndef CSM_PREFS_SHORTCUT_EVENT_HANDLER_H #define CSM_PREFS_SHORTCUT_EVENT_HANDLER_H +#include #include #include @@ -19,7 +20,7 @@ namespace CSMPrefs public: - ShortcutEventHandler(QObject* parent=0); + ShortcutEventHandler(QObject* parent); void addShortcut(Shortcut* shortcut); void removeShortcut(Shortcut* shortcut); @@ -30,6 +31,11 @@ namespace CSMPrefs private: + typedef std::vector ShortcutList; + // Child, Parent + typedef std::map WidgetMap; + typedef std::map ShortcutMap; + enum MatchResult { Matches_WithMod, @@ -37,9 +43,11 @@ namespace CSMPrefs Matches_Not }; - bool activate(unsigned int mod, unsigned int button); + void updateParent(QWidget* widget); + + bool activate(QWidget* widget, unsigned int mod, unsigned int button); - bool deactivate(unsigned int mod, unsigned int button); + bool deactivate(QWidget* widget, unsigned int mod, unsigned int button); bool checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate); @@ -49,7 +57,12 @@ namespace CSMPrefs static bool sort(const std::pair& left, const std::pair& right); - std::vector mShortcuts; + WidgetMap mChildParentRelations; + ShortcutMap mWidgetShortcuts; + + private slots: + + void widgetDestroyed(); }; } diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index f8e9ccb8a..300c2b61a 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -3,17 +3,25 @@ #include #include +#include #include #include #include #include "shortcut.hpp" +#include "shortcuteventhandler.hpp" namespace CSMPrefs { + ShortcutManager::ShortcutManager() + { + mEventHandler = new ShortcutEventHandler(this); + } + void ShortcutManager::addShortcut(Shortcut* shortcut) { mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut)); + mEventHandler->addShortcut(shortcut); } void ShortcutManager::removeShortcut(Shortcut* shortcut) @@ -31,6 +39,8 @@ namespace CSMPrefs ++it; } } + + mEventHandler->removeShortcut(shortcut); } ShortcutManager::SequenceData ShortcutManager::getSequence(const std::string& name) const diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index 60cdefe36..fe813341c 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -9,6 +9,7 @@ namespace CSMPrefs { class Shortcut; + class ShortcutEventHandler; /// Class used to track and update shortcuts/sequences class ShortcutManager : public QObject @@ -20,6 +21,9 @@ namespace CSMPrefs /// Key Sequence, Modifier (for secondary signal) typedef std::pair SequenceData; + + ShortcutManager(); + /// The shortcut class will do this automatically void addShortcut(Shortcut* shortcut); @@ -40,6 +44,8 @@ namespace CSMPrefs ShortcutMap mShortcuts; SequenceMap mSequences; + + ShortcutEventHandler* mEventHandler; }; } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index cfb06f21a..75e15c08c 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -229,6 +229,10 @@ void CSMPrefs::State::declare() addValues (insertOutsideVisibleCell); declareCategory ("Key Bindings"); + + declareShortcut ("document-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); + + declareSeparator (); declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); declareShortcut ("free-left", "Free camera left", QKeySequence(Qt::Key_A)); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6f14e5a4d..bc4230dfd 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,6 +16,7 @@ #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcut.hpp" #include "../../model/world/idtable.hpp" @@ -62,6 +63,9 @@ void CSVDoc::View::setupFileMenu() connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + CSMPrefs::Shortcut* saveShortcut = new CSMPrefs::Shortcut("document-save", this); + connect (saveShortcut, SIGNAL(activated()), this, SLOT(save())); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); file->addAction (mVerify); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index df71a9b88..6df7c0478 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -15,7 +15,6 @@ #include #include "../../model/prefs/shortcut.hpp" -#include "../../model/prefs/shortcuteventhandler.hpp" #include "scenewidget.hpp" @@ -79,27 +78,17 @@ namespace CSVRender void CameraController::setCamera(osg::Camera* camera) { + bool wasActive = mActive; + mCamera = camera; mActive = (mCamera != NULL); - if (mActive) + if (mActive != wasActive) { - onActivate(); - - QList shortcuts = findChildren(); - - for (QList::iterator it = shortcuts.begin(); it != shortcuts.end(); ++it) + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) { - (*it)->enable(true); - } - } - else - { - QList shortcuts = findChildren(); - - for (QList::iterator it = shortcuts.begin(); it != shortcuts.end(); ++it) - { - (*it)->enable(false); + CSMPrefs::Shortcut* shortcut = *it; + shortcut->enable(mActive); } } } @@ -160,14 +149,21 @@ namespace CSVRender getCamera()->setViewMatrixAsLookAt(eye, center, up); } + void CameraController::addShortcut(CSMPrefs::Shortcut* shortcut) + { + mShortcuts.push_back(shortcut); + } + /* Free Camera Controller */ - FreeCameraController::FreeCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent) - : CameraController(parent) + FreeCameraController::FreeCameraController(QWidget* widget) + : CameraController(widget) , mLockUpright(false) , mModified(false) + , mNaviPrimary(false) + , mNaviSecondary(false) , mFast(false) , mFastAlternate(false) , mLeft(false) @@ -181,52 +177,61 @@ namespace CSVRender , mRotSpeed(osg::PI / 2) , mSpeedMult(8) { - CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", this); + CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", widget); naviPrimaryShortcut->enable(false); - handler->addShortcut(naviPrimaryShortcut); connect(naviPrimaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviPrimary(bool))); - CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", this); + addShortcut(naviPrimaryShortcut); + + CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", widget); naviSecondaryShortcut->enable(false); - handler->addShortcut(naviSecondaryShortcut); connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool))); + addShortcut(naviSecondaryShortcut); + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", CSMPrefs::Shortcut::SM_Detach, - this); + widget); forwardShortcut->enable(false); - handler->addShortcut(forwardShortcut); connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); connect(forwardShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); - CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", this); + addShortcut(forwardShortcut); + + CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", widget); leftShortcut->enable(false); - handler->addShortcut(leftShortcut); connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool))); - CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", this); + addShortcut(leftShortcut); + + CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", widget); backShortcut->enable(false); - handler->addShortcut(backShortcut); connect(backShortcut, SIGNAL(activated(bool)), this, SLOT(backward(bool))); - CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", this); + addShortcut(backShortcut); + + CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", widget); rightShortcut->enable(false); - handler->addShortcut(rightShortcut); connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool))); - CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", this); + addShortcut(rightShortcut); + + CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", widget); rollLeftShortcut->enable(false); - handler->addShortcut(rollLeftShortcut); connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool))); - CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", this); + addShortcut(rollLeftShortcut); + + CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", widget); rollRightShortcut->enable(false); - handler->addShortcut(rollRightShortcut); connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool))); - CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", this); + addShortcut(rollRightShortcut); + + CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", widget); speedModeShortcut->enable(false); - handler->addShortcut(speedModeShortcut); connect(speedModeShortcut, SIGNAL(activated()), this, SLOT(swapSpeedMode())); + + addShortcut(speedModeShortcut); } double FreeCameraController::getLinearSpeed() const @@ -440,9 +445,11 @@ namespace CSVRender Orbit Camera Controller */ - OrbitCameraController::OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent) - : CameraController(parent) + OrbitCameraController::OrbitCameraController(QWidget* widget) + : CameraController(widget) , mInitialized(false) + , mNaviPrimary(false) + , mNaviSecondary(false) , mFast(false) , mFastAlternate(false) , mLeft(false) @@ -457,51 +464,60 @@ namespace CSVRender , mOrbitSpeed(osg::PI / 4) , mOrbitSpeedMult(4) { - CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", this); + CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", widget); naviPrimaryShortcut->enable(false); - handler->addShortcut(naviPrimaryShortcut); connect(naviPrimaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviPrimary(bool))); - CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", this); + addShortcut(naviPrimaryShortcut); + + CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", widget); naviSecondaryShortcut->enable(false); - handler->addShortcut(naviSecondaryShortcut); connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool))); - CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", CSMPrefs::Shortcut::SM_Detach, this); + addShortcut(naviSecondaryShortcut); + + CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", CSMPrefs::Shortcut::SM_Detach, widget); upShortcut->enable(false); - handler->addShortcut(upShortcut); connect(upShortcut, SIGNAL(activated(bool)), this, SLOT(up(bool))); connect(upShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); - CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("orbit-left", this); + addShortcut(upShortcut); + + CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("orbit-left", widget); leftShortcut->enable(false); - handler->addShortcut(leftShortcut); connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool))); - CSMPrefs::Shortcut* downShortcut = new CSMPrefs::Shortcut("orbit-down", this); + addShortcut(leftShortcut); + + CSMPrefs::Shortcut* downShortcut = new CSMPrefs::Shortcut("orbit-down", widget); downShortcut->enable(false); - handler->addShortcut(downShortcut); connect(downShortcut, SIGNAL(activated(bool)), this, SLOT(down(bool))); - CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("orbit-right", this); + addShortcut(downShortcut); + + CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("orbit-right", widget); rightShortcut->enable(false); - handler->addShortcut(rightShortcut); connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool))); - CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("orbit-roll-left", this); + addShortcut(rightShortcut); + + CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("orbit-roll-left", widget); rollLeftShortcut->enable(false); - handler->addShortcut(rollLeftShortcut); connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool))); - CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("orbit-roll-right", this); + addShortcut(rollLeftShortcut); + + CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("orbit-roll-right", widget); rollRightShortcut->enable(false); - handler->addShortcut(rollRightShortcut); connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool))); - CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("orbit-speed-mode", this); + addShortcut(rollRightShortcut); + + CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("orbit-speed-mode", widget); speedModeShortcut->enable(false); - handler->addShortcut(speedModeShortcut); connect(speedModeShortcut, SIGNAL(activated()), this, SLOT(swapSpeedMode())); + + addShortcut(speedModeShortcut); } osg::Vec3d OrbitCameraController::getCenter() const diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index 45ccfc14e..97af85790 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -2,14 +2,13 @@ #define OPENCS_VIEW_CAMERACONTROLLER_H #include +#include #include #include #include -class QKeyEvent; - namespace osg { class Camera; @@ -18,7 +17,7 @@ namespace osg namespace CSMPrefs { - class ShortcutEventHandler; + class Shortcut; } namespace CSVRender @@ -66,6 +65,8 @@ namespace CSVRender virtual void onActivate(){} + void addShortcut(CSMPrefs::Shortcut* shortcut); + private: bool mActive, mInverted; @@ -74,6 +75,8 @@ namespace CSVRender double mWheelMoveMult; osg::Camera* mCamera; + + std::vector mShortcuts; }; class FreeCameraController : public CameraController @@ -82,7 +85,7 @@ namespace CSVRender public: - FreeCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent=0); + FreeCameraController(QWidget* parent); double getLinearSpeed() const; double getRotationalSpeed() const; @@ -139,7 +142,7 @@ namespace CSVRender public: - OrbitCameraController(CSMPrefs::ShortcutEventHandler* handler, QObject* parent=0); + OrbitCameraController(QWidget* parent); osg::Vec3d getCenter() const; double getOrbitSpeed() const; diff --git a/apps/opencs/view/render/orbitcameramode.cpp b/apps/opencs/view/render/orbitcameramode.cpp index 6c4fb1f1e..286bab3e4 100644 --- a/apps/opencs/view/render/orbitcameramode.cpp +++ b/apps/opencs/view/render/orbitcameramode.cpp @@ -9,22 +9,19 @@ namespace CSVRender { - OrbitCameraMode::OrbitCameraMode(WorldspaceWidget* worldspaceWidget, CSMPrefs::ShortcutEventHandler* handler, - const QIcon& icon, const QString& tooltip, QWidget* parent) + OrbitCameraMode::OrbitCameraMode(WorldspaceWidget* worldspaceWidget, const QIcon& icon, const QString& tooltip, + QWidget* parent) : ModeButton(icon, tooltip, parent) , mWorldspaceWidget(worldspaceWidget) - , mShortcutHandler(handler) , mCenterOnSelection(0) { - mCenterShortcut = new CSMPrefs::Shortcut("orbit-center-selection", this); + mCenterShortcut.reset(new CSMPrefs::Shortcut("orbit-center-selection", worldspaceWidget)); mCenterShortcut->enable(false); - mShortcutHandler->addShortcut(mCenterShortcut); - connect(mCenterShortcut, SIGNAL(activated()), this, SLOT(centerSelection())); + connect(mCenterShortcut.get(), SIGNAL(activated()), this, SLOT(centerSelection())); } OrbitCameraMode::~OrbitCameraMode() { - mShortcutHandler->removeShortcut(mCenterShortcut); } void OrbitCameraMode::activate(CSVWidget::SceneToolbar* toolbar) diff --git a/apps/opencs/view/render/orbitcameramode.hpp b/apps/opencs/view/render/orbitcameramode.hpp index 990999b22..4f72de957 100644 --- a/apps/opencs/view/render/orbitcameramode.hpp +++ b/apps/opencs/view/render/orbitcameramode.hpp @@ -1,12 +1,13 @@ #ifndef CSV_RENDER_ORBITCAMERAPICKMODE_H #define CSV_RENDER_ORBITCAMERAPICKMODE_H +#include + #include "../widget/modebutton.hpp" namespace CSMPrefs { class Shortcut; - class ShortcutEventHandler; } namespace CSVRender @@ -19,8 +20,8 @@ namespace CSVRender public: - OrbitCameraMode(WorldspaceWidget* worldspaceWidget, CSMPrefs::ShortcutEventHandler* shortcutHandler, - const QIcon& icon, const QString& tooltip = "", QWidget* parent = 0); + OrbitCameraMode(WorldspaceWidget* worldspaceWidget, const QIcon& icon, const QString& tooltip = "", + QWidget* parent = 0); ~OrbitCameraMode(); virtual void activate(CSVWidget::SceneToolbar* toolbar); @@ -30,9 +31,8 @@ namespace CSVRender private: WorldspaceWidget* mWorldspaceWidget; - CSMPrefs::ShortcutEventHandler* mShortcutHandler; QAction* mCenterOnSelection; - CSMPrefs::Shortcut* mCenterShortcut; + std::auto_ptr mCenterShortcut; private slots: diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index c32427863..65c7a89f4 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -171,11 +171,8 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys , mPrevMouseY(0) , mCamPositionSet(false) { - mShortcutHandler = new CSMPrefs::ShortcutEventHandler(this); - installEventFilter(mShortcutHandler); - - mFreeCamControl = new FreeCameraController(mShortcutHandler, this); - mOrbitCamControl = new OrbitCameraController(mShortcutHandler, this); + mFreeCamControl = new FreeCameraController(this); + mOrbitCamControl = new OrbitCameraController(this); mCurrentCamControl = mFreeCamControl; mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); @@ -205,18 +202,14 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys // Shortcuts CSMPrefs::Shortcut* focusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); - mShortcutHandler->addShortcut(focusToolbarShortcut); connect(focusToolbarShortcut, SIGNAL(activated()), this, SIGNAL(focusToolbarRequest())); CSMPrefs::Shortcut* renderStatsShortcut = new CSMPrefs::Shortcut("scene-render-stats", this); - mShortcutHandler->addShortcut(renderStatsShortcut); connect(renderStatsShortcut, SIGNAL(activated()), this, SLOT(toggleRenderStats())); } SceneWidget::~SceneWidget() { - removeEventFilter(mShortcutHandler); - // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index fbe5bc13e..723d93c00 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -37,8 +37,6 @@ namespace CSVWidget namespace CSMPrefs { class Setting; - class Shortcut; - class ShortcutEventHandler; } namespace CSVRender @@ -116,8 +114,6 @@ namespace CSVRender OrbitCameraController* mOrbitCamControl; CameraController* mCurrentCamControl; - CSMPrefs::ShortcutEventHandler *mShortcutHandler; - private: bool mCamPositionSet; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index ab6a525d9..fa2a755f2 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -98,23 +98,18 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg // Shortcuts CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", this); - mShortcutHandler->addShortcut(primaryEditShortcut); connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool))); CSMPrefs::Shortcut* secondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this); - mShortcutHandler->addShortcut(secondaryEditShortcut); connect(secondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool))); CSMPrefs::Shortcut* primarySelectShortcut = new CSMPrefs::Shortcut("scene-select-primary", this); - mShortcutHandler->addShortcut(primarySelectShortcut); connect(primarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(primarySelect(bool))); CSMPrefs::Shortcut* secondarySelectShortcut = new CSMPrefs::Shortcut("scene-select-secondary", this); - mShortcutHandler->addShortcut(secondarySelectShortcut); connect(secondarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(secondarySelect(bool))); CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this); - mShortcutHandler->addShortcut(abortShortcut); connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag())); } @@ -184,7 +179,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
    • Hold shift to speed up movement
    • " "
    "); tool->addButton( - new CSVRender::OrbitCameraMode(this, mShortcutHandler, QIcon(":scenetoolbar/orbiting-camera"), + new CSVRender::OrbitCameraMode(this, QIcon(":scenetoolbar/orbiting-camera"), "Orbiting Camera" "
    • Always facing the centre point
    • " "
    • Rotate around the centre point via WASD or by moving the mouse while holding the left button
    • " diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 8a8ce1c6f..f3c31f896 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -15,7 +15,6 @@ namespace CSMPrefs { class Setting; - class Shortcut; } namespace CSMWorld From 051aec272993820e23969e35fb61050ce9a112cd Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Mon, 25 Jul 2016 20:49:09 -0400 Subject: [PATCH 23/46] Added methods to keep text mentioning shortcuts up to date, fixed potential issue with widget relationship tracking, hopefully got rid of signed/unsigned errors (Qt4/5 issue) --- apps/opencs/model/prefs/shortcut.cpp | 29 +++++++ apps/opencs/model/prefs/shortcut.hpp | 11 +++ .../model/prefs/shortcuteventhandler.cpp | 1 + apps/opencs/model/prefs/shortcutmanager.cpp | 2 +- apps/opencs/view/doc/view.cpp | 1 + apps/opencs/view/render/orbitcameramode.cpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 28 ++++--- apps/opencs/view/widget/pushbutton.cpp | 84 ++++++++++++++++++- apps/opencs/view/widget/pushbutton.hpp | 9 ++ apps/opencs/view/widget/scenetoolmode.cpp | 11 +++ apps/opencs/view/widget/scenetoolmode.hpp | 5 ++ 11 files changed, 168 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index c0682fed3..05f016604 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -2,6 +2,7 @@ #include +#include #include #include "state.hpp" @@ -19,6 +20,7 @@ namespace CSMPrefs , mLastPos(0) , mActivationStatus(AS_Inactive) , mModifierStatus(false) + , mAction(0) { assert (parent); @@ -38,6 +40,7 @@ namespace CSMPrefs , mLastPos(0) , mActivationStatus(AS_Inactive) , mModifierStatus(false) + , mAction(0) { assert (parent); @@ -107,6 +110,9 @@ namespace CSMPrefs mSequence = sequence; mCurrentPos = 0; mLastPos = sequence.count() - 1; + + if (mAction) + mAction->setText(mActionText + "\t" + toString()); } void Shortcut::setModifier(int modifier) @@ -129,6 +135,24 @@ namespace CSMPrefs mModifierStatus = status; } + void Shortcut::associateAction(QAction* action) + { + if (mAction) + { + disconnect(this, SLOT(actionDeleted())); + } + + mAction = action; + + if (mAction) + { + mActionText = mAction->text(); + mAction->setText(mActionText + "\t" + toString()); + + connect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted())); + } + } + void Shortcut::signalActivated(bool state) { emit activated(state); @@ -152,4 +176,9 @@ namespace CSMPrefs { return QString(State::get().getShortcutManager().sequenceToString(std::make_pair(mSequence, mModifier)).data()); } + + void Shortcut::actionDeleted() + { + mAction = 0; + } } diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index 2df47f382..fa68e6f19 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -7,6 +7,7 @@ #include #include +class QAction; class QWidget; namespace CSMPrefs @@ -64,6 +65,9 @@ namespace CSMPrefs void setActivationStatus(ActivationStatus status); void setModifierStatus(bool status); + /// Appends the sequence to the QAction text, also keeps it up to date + void associateAction(QAction* action); + // Workaround for Qt4 signals being "protected" void signalActivated(bool state); void signalActivated(); @@ -88,6 +92,13 @@ namespace CSMPrefs ActivationStatus mActivationStatus; bool mModifierStatus; + QAction* mAction; + QString mActionText; + + private slots: + + void actionDeleted(); + signals: /// Triggered when the shortcut is activated or deactivated; can be determined from \p state diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index 341881367..93e2d85d3 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -137,6 +137,7 @@ namespace CSMPrefs if (parentIt != mWidgetShortcuts.end()) { mChildParentRelations.insert(std::make_pair(widget, parent)); + updateParent(parent); break; } diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 300c2b61a..fff81fedc 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -92,7 +92,7 @@ namespace CSMPrefs std::string output; // KeySequence - for (int i = 0; i < data.first.count(); ++i) + for (int i = 0; i < (int)data.first.count(); ++i) { if (data.first[i] & ModMask) { diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index bc4230dfd..4e857db6c 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -64,6 +64,7 @@ void CSVDoc::View::setupFileMenu() file->addAction (mSave); CSMPrefs::Shortcut* saveShortcut = new CSMPrefs::Shortcut("document-save", this); + saveShortcut->associateAction(mSave); connect (saveShortcut, SIGNAL(activated()), this, SLOT(save())); mVerify = new QAction (tr ("&Verify"), this); diff --git a/apps/opencs/view/render/orbitcameramode.cpp b/apps/opencs/view/render/orbitcameramode.cpp index 286bab3e4..c7d980454 100644 --- a/apps/opencs/view/render/orbitcameramode.cpp +++ b/apps/opencs/view/render/orbitcameramode.cpp @@ -26,7 +26,8 @@ namespace CSVRender void OrbitCameraMode::activate(CSVWidget::SceneToolbar* toolbar) { - mCenterOnSelection = new QAction("Center on selected object\t" + mCenterShortcut->toString(), this); + mCenterOnSelection = new QAction("Center on selected object", this); + mCenterShortcut->associateAction(mCenterOnSelection); connect(mCenterOnSelection, SIGNAL(triggered()), this, SLOT(centerSelection())); mCenterShortcut->enable(true); @@ -34,6 +35,7 @@ namespace CSVRender void OrbitCameraMode::deactivate(CSVWidget::SceneToolbar* toolbar) { + mCenterShortcut->associateAction(0); mCenterShortcut->enable(false); } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index fa2a755f2..dda665c31 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -163,30 +163,32 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( /// \todo consider user-defined button-mapping tool->addButton (":scenetoolbar/1st-person", "1st", "First Person" - "
      • Mouse-Look while holding the left button
      • " - "
      • WASD movement keys
      • " + "
        • Camera is held upright
        • " + "
        • Mouse-Look while holding {scene-navi-primary}
        • " + "
        • Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)
        • " + "
        • Strafing (also vertically) by holding {scene-navi-secondary}
        • " "
        • Mouse wheel moves the camera forward/backward
        • " - "
        • Strafing (also vertically) by holding the left mouse button and control
        • " - "
        • Camera is held upright
        • " - "
        • Hold shift to speed up movement
        • " + "
        • Hold {free-forward:mod} to speed up movement
        • " "
        "); tool->addButton (":scenetoolbar/free-camera", "free", "Free Camera" - "
        • Mouse-Look while holding the left button
        • " - "
        • Strafing (also vertically) via WASD or by holding the left mouse button and control
        • " + "
          • Mouse-Look while holding {scene-navi-primary}
          • " + "
          • Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)
          • " + "
          • Roll camera with {free-roll-left} and {free-roll-right} keys
          • " + "
          • Strafing (also vertically) by holding {scene-navi-secondary}
          • " "
          • Mouse wheel moves the camera forward/backward
          • " - "
          • Roll camera with Q and E keys
          • " - "
          • Hold shift to speed up movement
          • " + "
          • Hold {free-forward:mod} to speed up movement
          • " "
          "); tool->addButton( new CSVRender::OrbitCameraMode(this, QIcon(":scenetoolbar/orbiting-camera"), "Orbiting Camera" "
          • Always facing the centre point
          • " - "
          • Rotate around the centre point via WASD or by moving the mouse while holding the left button
          • " + "
          • Rotate around the centre point via {orbit-up}, {orbit-left}, {orbit-down}, {orbit-right} or by moving " + "the mouse while holding {scene-navi-primary}
          • " + "
          • Roll camera with {orbit-roll-left} and {orbit-roll-right} keys
          • " + "
          • Strafing (also vertically) by holding {scene-navi-secondary} (includes relocation of the centre point)
          • " "
          • Mouse wheel moves camera away or towards centre point but can not pass through it
          • " - "
          • Roll camera with Q and E keys
          • " - "
          • Strafing (also vertically) by holding the left mouse button and control (includes relocation of the centre point)
          • " - "
          • Hold shift to speed up movement
          • " + "
          • Hold {orbit-up:mod} to speed up movement
          • " "
          ", tool), "orbit"); diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 424aaf68a..100f3bd43 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -3,9 +3,75 @@ #include #include +#include "../../model/prefs/state.hpp" + +void CSVWidget::PushButton::processShortcuts() +{ + const QChar SequenceStart = '{'; + const QChar SequenceEnd = '}'; + const QString ModifierSequence = QString::fromUtf8(":mod"); + + const QChar SettingSeparator = ';'; + + QStringList substrings; + + int prevIndex = 0; + int startIndex = mToolTip.indexOf(SequenceStart); + int endIndex = (startIndex != -1) ? mToolTip.indexOf(SequenceEnd, startIndex) : -1; + + // Process every valid shortcut escape sequence + while (startIndex != -1 && endIndex != -1) + { + int count = startIndex - prevIndex; + if (count > 0) + { + substrings.push_back(mToolTip.mid(prevIndex, count)); + } + + // Find sequence name + count = endIndex - startIndex - 1; + if (count > 0) + { + // Check if looking for modifier + int separatorIndex = mToolTip.indexOf(ModifierSequence, startIndex); + if (separatorIndex != -1 && separatorIndex < endIndex) + { + count = separatorIndex - startIndex - 1; + + QString settingName = mToolTip.mid(startIndex+1, count); + QString value = QString::fromUtf8( + CSMPrefs::State::get()["Key Bindings"][settingName.toUtf8().data()].toString().c_str()); + + substrings.push_back(value.right(value.size() - value.indexOf(SettingSeparator) - 1)); + } + else + { + QString settingName = mToolTip.mid(startIndex+1, count); + QString value = QString::fromUtf8( + CSMPrefs::State::get()["Key Bindings"][settingName.toUtf8().data()].toString().c_str()); + + // Don't want modifier + substrings.push_back(value.left(value.indexOf(SettingSeparator))); + } + + prevIndex = endIndex + 1; + } + + startIndex = mToolTip.indexOf(SequenceStart, endIndex); + endIndex = (startIndex != -1) ? mToolTip.indexOf(SequenceEnd, startIndex) : -1; + } + + if (prevIndex < mToolTip.size()) + { + substrings.push_back(mToolTip.mid(prevIndex)); + } + + mProcessedToolTip = substrings.join(""); +} + void CSVWidget::PushButton::setExtendedToolTip() { - QString tooltip = mToolTip; + QString tooltip = mProcessedToolTip; if (tooltip.isEmpty()) tooltip = "(Tool tip not implemented yet)"; @@ -77,13 +143,18 @@ CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString& connect (this, SIGNAL (toggled (bool)), this, SLOT (checkedStateChanged (bool))); } setCheckable (type==Type_Mode || type==Type_Toggle); + processShortcuts(); setExtendedToolTip(); + + connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), + this, SLOT (settingChanged (const CSMPrefs::Setting *))); } CSVWidget::PushButton::PushButton (Type type, const QString& tooltip, QWidget *parent) : QPushButton (parent), mKeepOpen (false), mType (type), mToolTip (tooltip) { setCheckable (type==Type_Mode || type==Type_Toggle); + processShortcuts(); setExtendedToolTip(); } @@ -94,7 +165,7 @@ bool CSVWidget::PushButton::hasKeepOpen() const QString CSVWidget::PushButton::getBaseToolTip() const { - return mToolTip; + return mProcessedToolTip; } CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const @@ -106,3 +177,12 @@ void CSVWidget::PushButton::checkedStateChanged (bool checked) { setExtendedToolTip(); } + +void CSVWidget::PushButton::settingChanged (const CSMPrefs::Setting *setting) +{ + if (setting->getParent()->getKey() == "Key Bindings") + { + processShortcuts(); + setExtendedToolTip(); + } +} diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 09cf22757..65df1b7e3 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -3,6 +3,11 @@ #include +namespace CSMPrefs +{ + class Setting; +} + namespace CSVWidget { class PushButton : public QPushButton @@ -24,9 +29,12 @@ namespace CSVWidget bool mKeepOpen; Type mType; QString mToolTip; + QString mProcessedToolTip; private: + // Uses {, :, and } as escape sequences for looking up shortcut settings + void processShortcuts(); void setExtendedToolTip(); protected: @@ -57,6 +65,7 @@ namespace CSVWidget private slots: void checkedStateChanged (bool checked); + void settingChanged (const CSMPrefs::Setting *setting); }; } diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index c91890c69..7b2ff64db 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "scenetoolbar.hpp" #include "modebutton.hpp" @@ -133,6 +134,16 @@ void CSVWidget::SceneToolMode::setButton (const std::string& id) } } +bool CSVWidget::SceneToolMode::event(QEvent* event) +{ + if (event->type() == QEvent::ToolTip) + { + adjustToolTip(mCurrent); + } + + return SceneTool::event(event); +} + void CSVWidget::SceneToolMode::selected() { std::map::iterator iter = diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 192b3ee78..90f1dc419 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -7,6 +7,7 @@ class QHBoxLayout; class QMenu; +class QEvent; namespace CSVWidget { @@ -43,6 +44,10 @@ namespace CSVWidget void setButton (std::map::iterator iter); + protected: + + bool event(QEvent* event); + public: SceneToolMode (SceneToolbar *parent, const QString& toolTip); From 8c5fddf15099e94bfb7692d5008494476bfb88e3 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Mon, 25 Jul 2016 20:49:28 -0400 Subject: [PATCH 24/46] Fix pathgrid selection mode not being removed from toolbar. --- apps/opencs/view/render/pathgridmode.cpp | 18 ++++++++++++++---- apps/opencs/view/render/pathgridmode.hpp | 2 ++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp index 87ec80556..228b2b5e7 100644 --- a/apps/opencs/view/render/pathgridmode.cpp +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -35,10 +35,10 @@ namespace CSVRender { return QString( "Pathgrid editing" - "
          • Primary edit: Add node to scene
          • " - "
          • Secondary edit: Connect selected nodes to node
          • " - "
          • Primary drag: Move selected nodes
          • " - "
          • Secondary drag: Connect one node to another
          • " + "
            • Press {scene-edit-primary} to add a node to the cursor location
            • " + "
            • Press {scene-edit-secondary} to connect the selected nodes to the node beneath the cursor
            • " + "
            • Press {scene-edit-primary} and drag to move selected nodes
            • " + "
            • Press {scene-edit-secondary} and drag to connect one node to another
            • " "

            Note: Only a single cell's pathgrid may be edited at a time"); } @@ -53,6 +53,16 @@ namespace CSVRender toolbar->addTool(mSelectionMode); } + void PathgridMode::deactivate(CSVWidget::SceneToolbar* toolbar) + { + if (mSelectionMode) + { + toolbar->removeTool (mSelectionMode); + delete mSelectionMode; + mSelectionMode = 0; + } + } + void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hitResult) { if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue() && diff --git a/apps/opencs/view/render/pathgridmode.hpp b/apps/opencs/view/render/pathgridmode.hpp index 908eefa5b..e34208f8c 100644 --- a/apps/opencs/view/render/pathgridmode.hpp +++ b/apps/opencs/view/render/pathgridmode.hpp @@ -19,6 +19,8 @@ namespace CSVRender virtual void activate(CSVWidget::SceneToolbar* toolbar); + virtual void deactivate(CSVWidget::SceneToolbar* toolbar); + virtual void primaryEditPressed(const WorldspaceHitResult& hit); virtual void secondaryEditPressed(const WorldspaceHitResult& hit); From 05888e7925904549241a19903dc618a793fca5fc Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Mon, 25 Jul 2016 22:43:37 -0400 Subject: [PATCH 25/46] Updated more tool tips to show shortcut configs. --- apps/opencs/view/render/instancemode.cpp | 8 ++++---- apps/opencs/view/render/instancemovemode.cpp | 4 ++-- apps/opencs/view/render/selectionmode.cpp | 18 ++++++++++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index df5ba7621..4eb9ea388 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -42,14 +42,14 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) mSubMode->addButton (new InstanceMoveMode (this), "move"); mSubMode->addButton (":placeholder", "rotate", "Rotate selected instances" - "

            • Use primary edit to rotate instances freely
            • " - "
            • Use secondary edit to rotate instances within the grid
            • " + "
              • Use {scene-edit-primary} to rotate instances freely
              • " + "
              • Use {scene-edit-secondary} to rotate instances within the grid
              • " "
              " "Not implemented yet"); mSubMode->addButton (":placeholder", "scale", "Scale selected instances" - "
              • Use primary edit to scale instances freely
              • " - "
              • Use secondary edit to scale instances along the grid
              • " + "
                • Use {scene-edit-primary} to scale instances freely
                • " + "
                • Use {scene-edit-secondary} to scale instances along the grid
                • " "
                " "Not implemented yet"); diff --git a/apps/opencs/view/render/instancemovemode.cpp b/apps/opencs/view/render/instancemovemode.cpp index 9929f5fcb..fe58b581b 100644 --- a/apps/opencs/view/render/instancemovemode.cpp +++ b/apps/opencs/view/render/instancemovemode.cpp @@ -4,8 +4,8 @@ CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent) : ModeButton (QIcon (QPixmap (":placeholder")), "Move selected instances" - "
                • Use primary edit to move instances around freely
                • " - "
                • Use secondary edit to move instances around within the grid
                • " + "
                  • Use {scene-edit-primary} to move instances around freely
                  • " + "
                  • Use {scene-edit-secondary} to move instances around within the grid
                  • " "
                  " "Grid move not implemented yet", parent) diff --git a/apps/opencs/view/render/selectionmode.cpp b/apps/opencs/view/render/selectionmode.cpp index 82a3c49e4..cf0967e47 100644 --- a/apps/opencs/view/render/selectionmode.cpp +++ b/apps/opencs/view/render/selectionmode.cpp @@ -15,22 +15,28 @@ namespace CSVRender { addButton(":placeholder", "cube-centre", "Centred cube" - "
                  • Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection cube outwards
                  • " + "
                    • Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} " + "(invert selection state) from the centre of the selection cube outwards
                    • " "
                    • The selection cube is aligned to the word space axis
                    • " - "
                    • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
                    • " + "
                    • If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not " + "starting on an instance will have the same effect
                    • " "
                    " "Not implemented yet"); addButton(":placeholder", "cube-corner", "Cube corner to corner" - "
                    • Drag with primary (make instances the selection) or secondary (invert selection state) select button from one corner of the selection cube to the opposite corner
                    • " + "
                      • Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} " + "(invert selection state) from one corner of the selection cube to the opposite corner
                      • " "
                      • The selection cube is aligned to the word space axis
                      • " - "
                      • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
                      • " + "
                      • If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not " + "starting on an instance will have the same effect
                      • " "
                      " "Not implemented yet"); addButton(":placeholder", "sphere", "Centred sphere" - "
                      • Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection sphere outwards
                      • " - "
                      • If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect
                      • " + "
                        • Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} " + "(invert selection state) from the centre of the selection sphere outwards
                        • " + "
                        • If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not " + "starting on an instance will have the same effect
                        • " "
                        " "Not implemented yet"); From 20f73f4a32a44833ba6e9e702c7bb87ec072da08 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Jul 2016 00:58:31 +0100 Subject: [PATCH 26/46] Relocate escape-related code to new files escape.hpp and escape.cpp. --- apps/openmw/main.cpp | 1 + components/CMakeLists.txt | 2 +- components/fallback/validate.hpp | 53 +----- components/files/configurationmanager.cpp | 157 +---------------- components/files/configurationmanager.hpp | 105 ------------ components/files/escape.cpp | 140 ++++++++++++++++ components/files/escape.hpp | 196 ++++++++++++++++++++++ 7 files changed, 342 insertions(+), 312 deletions(-) create mode 100644 components/files/escape.cpp create mode 100644 components/files/escape.hpp diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 6cc3fbf4e..cfe7fe305 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6d2436824..f50f30fa6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -93,7 +93,7 @@ IF(NOT WIN32 AND NOT APPLE) add_definitions(-DGLOBAL_CONFIG_PATH="${GLOBAL_CONFIG_PATH}") ENDIF() add_component_dir (files - linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager + linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager escape lowlevelfile constrainedfilestream memorystream ) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 43d51dd5e..a1d3f9601 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -2,11 +2,8 @@ #define OPENMW_COMPONENTS_FALLBACK_VALIDATE_H #include -#include -#include -#include -#include +#include // Parses and validates a fallback map from boost program_options. // Note: for boost to pick up the validate function, you need to pull in the namespace e.g. @@ -50,52 +47,4 @@ namespace Fallback } } -namespace Files { - void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) - { - boost::program_options::validators::check_first_occurrence(v); - - if (v.empty()) - v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens))); - } - - void validate(boost::any &v, const std::vector &tokens, EscapeStringVector *, int) - { - if (v.empty()) - v = boost::any(EscapeStringVector()); - - EscapeStringVector * eSV = boost::any_cast(&v); - - for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) - eSV->mVector.push_back(EscapeHashString(*it)); - } - - struct EscapePath { - boost::filesystem::path mPath; - - static PathContainer toPathContainer(const std::vector & escapePathContainer); - }; - - typedef std::vector EscapePathContainer; - - PathContainer EscapePath::toPathContainer(const EscapePathContainer & escapePathContainer) - { - PathContainer temp; - for (EscapePathContainer::const_iterator it = escapePathContainer.begin(); it != escapePathContainer.end(); ++it) - temp.push_back(it->mPath); - return temp; - } - - std::istream & operator>> (std::istream & istream, EscapePath & escapePath) - { - boost::iostreams::filtering_istream filteredStream; - filteredStream.push(unescape_hash_filter()); - filteredStream.push(istream); - - filteredStream >> escapePath.mPath; - - return istream; - } -} - #endif diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index e5313bfee..b53e3834a 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -5,10 +5,13 @@ #include #include +#include + #include #include #include #include +#include /** * \namespace Files @@ -164,160 +167,6 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } -const int escape_hash_filter::sEscape = '@'; -const int escape_hash_filter::sEscapeIdentifier = 'a'; -const int escape_hash_filter::sHashIdentifier = 'h'; - -escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false) -{ -} - -escape_hash_filter::~escape_hash_filter() -{ -} - -template -int escape_hash_filter::get(Source & src) -{ - if (mNext.empty()) - { - int character = boost::iostreams::get(src); - bool record = true; - if (character == boost::iostreams::WOULD_BLOCK) - { - mNext.push(character); - record = false; - } - else if (character == EOF) - { - mSeenNonWhitespace = false; - mFinishLine = false; - mNext.push(character); - } - else if (character == '\n') - { - mSeenNonWhitespace = false; - mFinishLine = false; - mNext.push(character); - } - else if (mFinishLine) - { - mNext.push(character); - } - else if (character == '#') - { - if (mSeenNonWhitespace) - { - mNext.push(sEscape); - mNext.push(sHashIdentifier); - } - else - { - //it's fine being interpreted by Boost as a comment, and so is anything afterwards - mNext.push(character); - mFinishLine = true; - } - } - else if (mPrevious == sEscape) - { - mNext.push(sEscape); - mNext.push(sEscapeIdentifier); - } - else - { - mNext.push(character); - } - if (!mSeenNonWhitespace && !isspace(character)) - mSeenNonWhitespace = true; - if (record) - mPrevious = character; - } - int retval = mNext.front(); - mNext.pop(); - return retval; -} - -unescape_hash_filter::unescape_hash_filter() : expectingIdentifier(false) -{ -} - -unescape_hash_filter::~unescape_hash_filter() -{ -} - -std::string EscapeHashString::processString(const std::string & str) -{ - std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1)); - return temp; -} - -EscapeHashString::EscapeHashString() : mData() -{ -} - -EscapeHashString::EscapeHashString(const std::string & str) : mData(EscapeHashString::processString(str)) -{ -} - -EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : mData(EscapeHashString::processString(str), pos, len) -{ -} - -EscapeHashString::EscapeHashString(const char * s) : mData(EscapeHashString::processString(std::string(s))) -{ -} - -EscapeHashString::EscapeHashString(const char * s, size_t n) : mData(EscapeHashString::processString(std::string(s)), 0, n) -{ -} - -EscapeHashString::EscapeHashString(size_t n, char c) : mData(n, c) -{ -} - -template -EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mData(EscapeHashString::processString(std::string(first, last))) -{ -} - -std::string EscapeHashString::toStdString() const -{ - return std::string(mData); -} - -std::istream & operator>> (std::istream & is, EscapeHashString & eHS) -{ - std::string temp; - is >> temp; - eHS = EscapeHashString(temp); - return is; -} - -std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS) -{ - os << eHS.mData; - return os; -} - -EscapeStringVector::EscapeStringVector() : mVector() -{ -} - -EscapeStringVector::~EscapeStringVector() -{ -} - -std::vector EscapeStringVector::toStdStringVector() const -{ - std::vector temp = std::vector(); - for (std::vector::const_iterator it = mVector.begin(); it != mVector.end(); ++it) - { - temp.push_back(it->toStdString()); - } - return temp; -} - const boost::filesystem::path& ConfigurationManager::getGlobalPath() const { return mFixedPath.getGlobalConfigPath(); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 494dfdd0c..df131e671 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -2,10 +2,8 @@ #define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP #include -#include #include -#include #include #include @@ -64,109 +62,6 @@ struct ConfigurationManager bool mSilent; }; - - -/** - * \struct escape_hash_filter - */ -struct escape_hash_filter : public boost::iostreams::input_filter -{ - static const int sEscape; - static const int sHashIdentifier; - static const int sEscapeIdentifier; - - escape_hash_filter(); - virtual ~escape_hash_filter(); - - template int get(Source & src); - - private: - std::queue mNext; - int mPrevious; - - bool mSeenNonWhitespace; - bool mFinishLine; -}; - -struct unescape_hash_filter : public boost::iostreams::input_filter -{ - unescape_hash_filter(); - virtual ~unescape_hash_filter(); - - template int get(Source & src); - - private: - bool expectingIdentifier; -}; - -template -int unescape_hash_filter::get(Source & src) -{ - int character; - if (!expectingIdentifier) - character = boost::iostreams::get(src); - else - { - character = escape_hash_filter::sEscape; - expectingIdentifier = false; - } - if (character == escape_hash_filter::sEscape) - { - int nextChar = boost::iostreams::get(src); - int intended; - if (nextChar == escape_hash_filter::sEscapeIdentifier) - intended = escape_hash_filter::sEscape; - else if (nextChar == escape_hash_filter::sHashIdentifier) - intended = '#'; - else if (nextChar == boost::iostreams::WOULD_BLOCK) - { - expectingIdentifier = true; - intended = nextChar; - } - else - intended = '?'; - return intended; - } - else - return character; -} - -/** - * \class EscapeHashString - */ -class EscapeHashString -{ - private: - std::string mData; - public: - static std::string processString(const std::string & str); - - EscapeHashString(); - EscapeHashString(const std::string & str); - EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos); - EscapeHashString(const char * s); - EscapeHashString(const char * s, size_t n); - EscapeHashString(size_t n, char c); - template - EscapeHashString(InputIterator first, InputIterator last); - - std::string toStdString() const; - - friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS); -}; - -std::istream & operator>> (std::istream & is, EscapeHashString & eHS); - -struct EscapeStringVector -{ - std::vector mVector; - - EscapeStringVector(); - virtual ~EscapeStringVector(); - - std::vector toStdStringVector() const; -}; - } /* namespace Cfg */ #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ diff --git a/components/files/escape.cpp b/components/files/escape.cpp new file mode 100644 index 000000000..78365288a --- /dev/null +++ b/components/files/escape.cpp @@ -0,0 +1,140 @@ +#include + +#include +#include + +namespace Files +{ + const int escape_hash_filter::sEscape = '@'; + const int escape_hash_filter::sEscapeIdentifier = 'a'; + const int escape_hash_filter::sHashIdentifier = 'h'; + + escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false) + { + } + + escape_hash_filter::~escape_hash_filter() + { + } + + unescape_hash_filter::unescape_hash_filter() : expectingIdentifier(false) + { + } + + unescape_hash_filter::~unescape_hash_filter() + { + } + + std::string EscapeHashString::processString(const std::string & str) + { + std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char)escape_hash_filter::sEscape, 1)); + return temp; + } + + EscapeHashString::EscapeHashString() : mData() + { + } + + EscapeHashString::EscapeHashString(const std::string & str) : mData(EscapeHashString::processString(str)) + { + } + + EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : mData(EscapeHashString::processString(str), pos, len) + { + } + + EscapeHashString::EscapeHashString(const char * s) : mData(EscapeHashString::processString(std::string(s))) + { + } + + EscapeHashString::EscapeHashString(const char * s, size_t n) : mData(EscapeHashString::processString(std::string(s)), 0, n) + { + } + + EscapeHashString::EscapeHashString(size_t n, char c) : mData(n, c) + { + } + + template + EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mData(EscapeHashString::processString(std::string(first, last))) + { + } + + std::string EscapeHashString::toStdString() const + { + return std::string(mData); + } + + std::istream & operator>> (std::istream & is, EscapeHashString & eHS) + { + std::string temp; + is >> temp; + eHS = EscapeHashString(temp); + return is; + } + + std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS) + { + os << eHS.mData; + return os; + } + + EscapeStringVector::EscapeStringVector() : mVector() + { + } + + EscapeStringVector::~EscapeStringVector() + { + } + + std::vector EscapeStringVector::toStdStringVector() const + { + std::vector temp = std::vector(); + for (std::vector::const_iterator it = mVector.begin(); it != mVector.end(); ++it) + { + temp.push_back(it->toStdString()); + } + return temp; + } + + // boost program options validation + + void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) + { + boost::program_options::validators::check_first_occurrence(v); + + if (v.empty()) + v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens))); + } + + void validate(boost::any &v, const std::vector &tokens, EscapeStringVector *, int) + { + if (v.empty()) + v = boost::any(EscapeStringVector()); + + EscapeStringVector * eSV = boost::any_cast(&v); + + for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) + eSV->mVector.push_back(EscapeHashString(*it)); + } + + PathContainer EscapePath::toPathContainer(const EscapePathContainer & escapePathContainer) + { + PathContainer temp; + for (EscapePathContainer::const_iterator it = escapePathContainer.begin(); it != escapePathContainer.end(); ++it) + temp.push_back(it->mPath); + return temp; + } + + std::istream & operator>> (std::istream & istream, EscapePath & escapePath) + { + boost::iostreams::filtering_istream filteredStream; + filteredStream.push(unescape_hash_filter()); + filteredStream.push(istream); + + filteredStream >> escapePath.mPath; + + return istream; + } +} \ No newline at end of file diff --git a/components/files/escape.hpp b/components/files/escape.hpp new file mode 100644 index 000000000..3b016a12d --- /dev/null +++ b/components/files/escape.hpp @@ -0,0 +1,196 @@ +#ifndef COMPONENTS_FILES_ESCAPE_HPP +#define COMPONENTS_FILES_ESCAPE_HPP + +#include + +#include + +#include +#include +#include + +/** + * \namespace Files + */ +namespace Files +{ + /** + * \struct escape_hash_filter + */ + struct escape_hash_filter : public boost::iostreams::input_filter + { + static const int sEscape; + static const int sHashIdentifier; + static const int sEscapeIdentifier; + + escape_hash_filter(); + virtual ~escape_hash_filter(); + + template int get(Source & src); + + private: + std::queue mNext; + int mPrevious; + + bool mSeenNonWhitespace; + bool mFinishLine; + }; + + template + int escape_hash_filter::get(Source & src) + { + if (mNext.empty()) + { + int character = boost::iostreams::get(src); + bool record = true; + if (character == boost::iostreams::WOULD_BLOCK) + { + mNext.push(character); + record = false; + } + else if (character == EOF) + { + mSeenNonWhitespace = false; + mFinishLine = false; + mNext.push(character); + } + else if (character == '\n') + { + mSeenNonWhitespace = false; + mFinishLine = false; + mNext.push(character); + } + else if (mFinishLine) + { + mNext.push(character); + } + else if (character == '#') + { + if (mSeenNonWhitespace) + { + mNext.push(sEscape); + mNext.push(sHashIdentifier); + } + else + { + //it's fine being interpreted by Boost as a comment, and so is anything afterwards + mNext.push(character); + mFinishLine = true; + } + } + else if (mPrevious == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + } + else + { + mNext.push(character); + } + if (!mSeenNonWhitespace && !isspace(character)) + mSeenNonWhitespace = true; + if (record) + mPrevious = character; + } + int retval = mNext.front(); + mNext.pop(); + return retval; + } + + struct unescape_hash_filter : public boost::iostreams::input_filter + { + unescape_hash_filter(); + virtual ~unescape_hash_filter(); + + template int get(Source & src); + + private: + bool expectingIdentifier; + }; + + template + int unescape_hash_filter::get(Source & src) + { + int character; + if (!expectingIdentifier) + character = boost::iostreams::get(src); + else + { + character = escape_hash_filter::sEscape; + expectingIdentifier = false; + } + if (character == escape_hash_filter::sEscape) + { + int nextChar = boost::iostreams::get(src); + int intended; + if (nextChar == escape_hash_filter::sEscapeIdentifier) + intended = escape_hash_filter::sEscape; + else if (nextChar == escape_hash_filter::sHashIdentifier) + intended = '#'; + else if (nextChar == boost::iostreams::WOULD_BLOCK) + { + expectingIdentifier = true; + intended = nextChar; + } + else + intended = '?'; + return intended; + } + else + return character; + } + + /** + * \class EscapeHashString + */ + class EscapeHashString + { + private: + std::string mData; + public: + static std::string processString(const std::string & str); + + EscapeHashString(); + EscapeHashString(const std::string & str); + EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos); + EscapeHashString(const char * s); + EscapeHashString(const char * s, size_t n); + EscapeHashString(size_t n, char c); + template + EscapeHashString(InputIterator first, InputIterator last); + + std::string toStdString() const; + + friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS); + }; + + std::istream & operator>> (std::istream & is, EscapeHashString & eHS); + + struct EscapeStringVector + { + std::vector mVector; + + EscapeStringVector(); + virtual ~EscapeStringVector(); + + std::vector toStdStringVector() const; + }; + + //boost program options validation + + void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a); + + void validate(boost::any &v, const std::vector &tokens, EscapeStringVector *, int); + + struct EscapePath + { + boost::filesystem::path mPath; + + static PathContainer toPathContainer(const std::vector & escapePathContainer); + }; + + typedef std::vector EscapePathContainer; + + std::istream & operator>> (std::istream & istream, EscapePath & escapePath); +} /* namespace Files */ +#endif /* COMPONENTS_FILES_ESCAPE_HPP */ \ No newline at end of file From a0699ce20d4abb6aad078784f03fcc1e66f1a479 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Jul 2016 01:19:05 +0100 Subject: [PATCH 27/46] Change some <> characters to double quotes, resolving compilation problems. --- components/files/escape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index 78365288a..9a795b95f 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -1,4 +1,4 @@ -#include +#include "escape.hpp" #include #include From 08af82e1bdc886f7733faf82978cf43ed910de04 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Tue, 26 Jul 2016 21:22:31 -0400 Subject: [PATCH 28/46] Switched to an interactive method for key input, Redid text representation for shortcuts --- apps/opencs/model/prefs/shortcut.cpp | 16 +- apps/opencs/model/prefs/shortcutmanager.cpp | 726 ++++++++++++++++---- apps/opencs/model/prefs/shortcutmanager.hpp | 31 +- apps/opencs/model/prefs/shortcutsetting.cpp | 155 ++++- apps/opencs/model/prefs/shortcutsetting.hpp | 24 +- apps/opencs/model/prefs/state.cpp | 15 +- apps/opencs/model/prefs/state.hpp | 2 +- 7 files changed, 798 insertions(+), 171 deletions(-) diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index 05f016604..182437f47 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -25,9 +25,7 @@ namespace CSMPrefs assert (parent); State::get().getShortcutManager().addShortcut(this); - ShortcutManager::SequenceData data = State::get().getShortcutManager().getSequence(name); - setSequence(data.first); - setModifier(data.second); + State::get().getShortcutManager().getSequence(name, mSequence, mModifier); } Shortcut::Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent) @@ -45,9 +43,7 @@ namespace CSMPrefs assert (parent); State::get().getShortcutManager().addShortcut(this); - ShortcutManager::SequenceData data = State::get().getShortcutManager().getSequence(name); - setSequence(data.first); - setModifier(data.second); + State::get().getShortcutManager().getSequence(name, mSequence, mModifier); } Shortcut::~Shortcut() @@ -112,7 +108,9 @@ namespace CSMPrefs mLastPos = sequence.count() - 1; if (mAction) - mAction->setText(mActionText + "\t" + toString()); + { + mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data()); + } } void Shortcut::setModifier(int modifier) @@ -147,7 +145,7 @@ namespace CSMPrefs if (mAction) { mActionText = mAction->text(); - mAction->setText(mActionText + "\t" + toString()); + mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data()); connect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted())); } @@ -174,7 +172,7 @@ namespace CSMPrefs QString Shortcut::toString() const { - return QString(State::get().getShortcutManager().sequenceToString(std::make_pair(mSequence, mModifier)).data()); + return QString(State::get().getShortcutManager().convertToString(mSequence, mModifier).data()); } void Shortcut::actionDeleted() diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index fff81fedc..6be1840dd 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -1,5 +1,6 @@ #include "shortcutmanager.hpp" +#include #include #include @@ -15,6 +16,7 @@ namespace CSMPrefs { ShortcutManager::ShortcutManager() { + createLookupTables(); mEventHandler = new ShortcutEventHandler(this); } @@ -43,31 +45,31 @@ namespace CSMPrefs mEventHandler->removeShortcut(shortcut); } - ShortcutManager::SequenceData ShortcutManager::getSequence(const std::string& name) const + bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence, int& modifier) const { - SequenceData data; SequenceMap::const_iterator item = mSequences.find(name); - if (item != mSequences.end()) { - data = item->second; - } + sequence = item->second.first; + modifier = item->second.second; - return data; + return true; + } + else + return false; } - void ShortcutManager::setSequence(const std::string& name, const SequenceData& data) + void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence, int modifier) { // Add to map/modify SequenceMap::iterator item = mSequences.find(name); - if (item != mSequences.end()) { - item->second = data; + item->second = std::make_pair(sequence, modifier); } else { - mSequences.insert(std::make_pair(name, data)); + mSequences.insert(std::make_pair(name, std::make_pair(sequence, modifier))); } // Change active shortcuts @@ -75,166 +77,628 @@ namespace CSMPrefs for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) { - it->second->setSequence(data.first); - it->second->setModifier(data.second); + it->second->setSequence(sequence); + it->second->setModifier(modifier); } } - std::string ShortcutManager::sequenceToString(const SequenceData& data) + std::string ShortcutManager::convertToString(const QKeySequence& sequence) const { - const int MouseMask = 0x0000001F; // Conflicts with key - const int KeyMask = 0x01FFFFFF; + const int MouseKeyMask = 0x01FFFFFF; const int ModMask = 0x7E000000; - const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); - const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); - - std::string output; + std::string result; - // KeySequence - for (int i = 0; i < (int)data.first.count(); ++i) + for (int i = 0; i < (int)sequence.count(); ++i) { - if (data.first[i] & ModMask) - { - // TODO separate out modifiers to allow more than 1 - output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(data.first[i] & ModMask)); - output.append("+"); - } + int mods = sequence[i] & ModMask; + int key = sequence[i] & MouseKeyMask; - if (data.first[i] & KeyMask & ~MouseMask) + if (key) { - // Is a key - output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(data.first[i] & KeyMask)); - output.append(","); - } - else if (data.first[i] & MouseMask) - { - std::stringstream ss; - std::string num; - - unsigned int value = (unsigned int)(data.first[i] & MouseMask); - - // value will never be 0 - int exponent = 1; // Offset by 1 - while (value >>= 1) - ++exponent; - - ss << exponent; - ss >> num; + NameMap::const_iterator searchResult = mNames.find(key); + if (searchResult != mNames.end()) + { + if (mods && i == 0) + { + if (mods & Qt::ControlModifier) + result.append("Ctl+"); + if (mods & Qt::ShiftModifier) + result.append("Shift+"); + if (mods & Qt::AltModifier) + result.append("Alt+"); + if (mods & Qt::MetaModifier) + result.append("Meta+"); + if (mods & Qt::KeypadModifier) + result.append("Keypad+"); + if (mods & Qt::GroupSwitchModifier) + result.append("GroupSwitch+"); + } + else if (i > 0) + { + result.append("+"); + } - // Is a mouse button - output.append("Mouse"); - output.append(num); - output.append(","); + result.append(searchResult->second); + } } } - // Remove last comma - if (output.size() > 0) - { - output.resize(output.size() - 1); - } + return result; + } - // Add modifier if needed - if (data.second & ModMask) - { - output.append(";"); - output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(data.second & ModMask)); - } - else if (data.second & KeyMask & ~MouseMask) + std::string ShortcutManager::convertToString(int modifier) const + { + NameMap::const_iterator searchResult = mNames.find(modifier); + if (searchResult != mNames.end()) { - output.append(";"); - output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(data.second & KeyMask)); + return searchResult->second; } - else if (data.second & MouseMask) - { - std::stringstream ss; - std::string num; - - unsigned int value = (unsigned int)(data.second & MouseMask); - - // value will never be 0 - int exponent = 1; // Offset by 1 - while (value >>= 1) - ++exponent; - - ss << exponent; - ss >> num; + else + return ""; + } - // Is a mouse button - output.append(";Mouse"); - output.append(num); - } + std::string ShortcutManager::convertToString(const QKeySequence& sequence, int modifier) const + { + std::string concat = convertToString(sequence) + ";" + convertToString(modifier); + std::cout << sequence[0] << "." << sequence[1] << "."<< sequence[2] << "."<< sequence[3] << "." << modifier << std::endl; + std::cout << concat << std::endl; - return output; + return concat; } - ShortcutManager::SequenceData ShortcutManager::stringToSequence(const std::string& input) + void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence) const { - // TODO clean and standardize + const int MaxKeys = 4; // A limitation of QKeySequence - const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); - const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); + size_t end = data.find(";"); + size_t size = std::min(end, data.size()); - int keys[4] = { 0, 0, 0, 0 }; - int modifier = 0; + std::string value = data.substr(0, size); + size_t start = 0; - size_t middle = input.find(';'); - std::string sequenceStr = input.substr(0, middle); - std::string modifierStr = input.substr((middle < input.size())? middle + 1 : input.size()); + int keyPos = 0; + int mods = 0; - QRegExp splitRX("[, ]"); - QStringList keyStrs = QString(sequenceStr.c_str()).split(splitRX, QString::SkipEmptyParts); + int keys[MaxKeys] = {}; - for (int i = 0; i < keyStrs.size(); ++i) + while (start < value.size()) { - QRegExp modSeparator("[+]"); + end = data.find("+", start); + end = std::min(end, value.size()); + + std::string name = value.substr(start, end - start); - QStringList separatedList = keyStrs[i].split(modSeparator, QString::SkipEmptyParts); - for (int j = 0; j < separatedList.size(); ++j) + if (name == "Ctl") { - if (separatedList[j].startsWith("Mouse")) - { - QString num = separatedList[j].mid(5); - if (num > 0) - { - keys[i] |= 1 << (num.toInt() - 1); // offset by 1 - } - } - else if (staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(separatedList[j].toUtf8().data()) != -1) - { - keys[i] |= staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(separatedList[j].toUtf8().data()); - } - else if (staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(separatedList[j].toUtf8().data()) != -1) - { - keys[i] |= staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(separatedList[j].toUtf8().data()); - } + mods |= Qt::ControlModifier; } - } - - if (!modifierStr.empty()) - { - if (modifierStr.find("Mouse") != std::string::npos) + else if (name == "Shift") { - QString num = QString::fromUtf8(modifierStr.substr(5).data()); - if (num > 0) - { - modifier = 1 << (num.toInt() - 1); // offset by 1 - } + mods |= Qt::ShiftModifier; + } + else if (name == "Alt") + { + mods |= Qt::AltModifier; + } + else if (name == "Meta") + { + mods |= Qt::MetaModifier; } - else if (staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(modifierStr.data()) != -1) + else if (name == "Keypad") { - modifier = staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(modifierStr.data()); + mods |= Qt::KeypadModifier; } - else if (staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(modifierStr.data()) != -1) + else if (name == "GroupSwitch") { - modifier = staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(modifierStr.data()); + mods |= Qt::GroupSwitchModifier; } + else + { + KeyMap::const_iterator searchResult = mKeys.find(name); + if (searchResult != mKeys.end()) + { + keys[keyPos] = mods | searchResult->second; + + mods = 0; + keyPos += 1; + + if (keyPos >= MaxKeys) + break; + } + } + + start = end + 1; + } + + sequence = QKeySequence(keys[0], keys[1], keys[2], keys[3]); + } + + void ShortcutManager::convertFromString(const std::string& data, int& modifier) const + { + size_t start = data.find(";") + 1; + start = std::min(start, data.size()); + + std::string name = data.substr(start); + KeyMap::const_iterator searchResult = mKeys.find(name); + if (searchResult != mKeys.end()) + { + modifier = searchResult->second; } + else + { + modifier = 0; + } + } + + void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const + { + convertFromString(data, sequence); + convertFromString(data, modifier); + } - // TODO remove - std::cout << input << '.' << keys[0] << '.'<< keys[1] << '.'<< keys[2] << '.'<< keys[3] << '.' << modifier << std::endl; + void ShortcutManager::createLookupTables() + { + // Mouse buttons + mNames.insert(std::make_pair(Qt::LeftButton, "LMB")); + mNames.insert(std::make_pair(Qt::RightButton, "RMB")); + mNames.insert(std::make_pair(Qt::MiddleButton, "MMB")); + mNames.insert(std::make_pair(Qt::XButton1, "Mouse4")); + mNames.insert(std::make_pair(Qt::XButton2, "Mouse5")); + + // Keyboard buttons + for (size_t i = 0; QtKeys[i].first != 0; ++i) + { + mNames.insert(QtKeys[i]); + } - return std::make_pair(QKeySequence(keys[0], keys[1], keys[2], keys[3]), modifier); + // Generate inverse map + for (NameMap::const_iterator it = mNames.begin(); it != mNames.end(); ++it) + { + mKeys.insert(std::make_pair(it->second, it->first)); + } } + + const std::pair ShortcutManager::QtKeys[] = + { + std::make_pair((int)Qt::Key_Space , "Space"), + std::make_pair((int)Qt::Key_Exclam , "Exclam"), + std::make_pair((int)Qt::Key_QuoteDbl , "QuoteDbl"), + std::make_pair((int)Qt::Key_NumberSign , "NumberSign"), + std::make_pair((int)Qt::Key_Dollar , "Dollar"), + std::make_pair((int)Qt::Key_Percent , "Percent"), + std::make_pair((int)Qt::Key_Ampersand , "Ampersand"), + std::make_pair((int)Qt::Key_Apostrophe , "Apostrophe"), + std::make_pair((int)Qt::Key_ParenLeft , "ParenLeft"), + std::make_pair((int)Qt::Key_ParenRight , "ParenRight"), + std::make_pair((int)Qt::Key_Asterisk , "Asterisk"), + std::make_pair((int)Qt::Key_Plus , "Plus"), + std::make_pair((int)Qt::Key_Comma , "Comma"), + std::make_pair((int)Qt::Key_Minus , "Minus"), + std::make_pair((int)Qt::Key_Period , "Period"), + std::make_pair((int)Qt::Key_Slash , "Slash"), + std::make_pair((int)Qt::Key_0 , "0"), + std::make_pair((int)Qt::Key_1 , "1"), + std::make_pair((int)Qt::Key_2 , "2"), + std::make_pair((int)Qt::Key_3 , "3"), + std::make_pair((int)Qt::Key_4 , "4"), + std::make_pair((int)Qt::Key_5 , "5"), + std::make_pair((int)Qt::Key_6 , "6"), + std::make_pair((int)Qt::Key_7 , "7"), + std::make_pair((int)Qt::Key_8 , "8"), + std::make_pair((int)Qt::Key_9 , "9"), + std::make_pair((int)Qt::Key_Colon , "Colon"), + std::make_pair((int)Qt::Key_Semicolon , "Semicolon"), + std::make_pair((int)Qt::Key_Less , "Less"), + std::make_pair((int)Qt::Key_Equal , "Equal"), + std::make_pair((int)Qt::Key_Greater , "Greater"), + std::make_pair((int)Qt::Key_Question , "Question"), + std::make_pair((int)Qt::Key_At , "At"), + std::make_pair((int)Qt::Key_A , "A"), + std::make_pair((int)Qt::Key_B , "B"), + std::make_pair((int)Qt::Key_C , "C"), + std::make_pair((int)Qt::Key_D , "D"), + std::make_pair((int)Qt::Key_E , "E"), + std::make_pair((int)Qt::Key_F , "F"), + std::make_pair((int)Qt::Key_G , "G"), + std::make_pair((int)Qt::Key_H , "H"), + std::make_pair((int)Qt::Key_I , "I"), + std::make_pair((int)Qt::Key_J , "J"), + std::make_pair((int)Qt::Key_K , "K"), + std::make_pair((int)Qt::Key_L , "L"), + std::make_pair((int)Qt::Key_M , "M"), + std::make_pair((int)Qt::Key_N , "N"), + std::make_pair((int)Qt::Key_O , "O"), + std::make_pair((int)Qt::Key_P , "P"), + std::make_pair((int)Qt::Key_Q , "Q"), + std::make_pair((int)Qt::Key_R , "R"), + std::make_pair((int)Qt::Key_S , "S"), + std::make_pair((int)Qt::Key_T , "T"), + std::make_pair((int)Qt::Key_U , "U"), + std::make_pair((int)Qt::Key_V , "V"), + std::make_pair((int)Qt::Key_W , "W"), + std::make_pair((int)Qt::Key_X , "X"), + std::make_pair((int)Qt::Key_Y , "Y"), + std::make_pair((int)Qt::Key_Z , "Z"), + std::make_pair((int)Qt::Key_BracketLeft , "BracketLeft"), + std::make_pair((int)Qt::Key_Backslash , "Backslash"), + std::make_pair((int)Qt::Key_BracketRight , "BracketRight"), + std::make_pair((int)Qt::Key_AsciiCircum , "AsciiCircum"), + std::make_pair((int)Qt::Key_Underscore , "Underscore"), + std::make_pair((int)Qt::Key_QuoteLeft , "QuoteLeft"), + std::make_pair((int)Qt::Key_BraceLeft , "BraceLeft"), + std::make_pair((int)Qt::Key_Bar , "Bar"), + std::make_pair((int)Qt::Key_BraceRight , "BraceRight"), + std::make_pair((int)Qt::Key_AsciiTilde , "AsciiTilde"), + std::make_pair((int)Qt::Key_nobreakspace , "nobreakspace"), + std::make_pair((int)Qt::Key_exclamdown , "exclamdown"), + std::make_pair((int)Qt::Key_cent , "cent"), + std::make_pair((int)Qt::Key_sterling , "sterling"), + std::make_pair((int)Qt::Key_currency , "currency"), + std::make_pair((int)Qt::Key_yen , "yen"), + std::make_pair((int)Qt::Key_brokenbar , "brokenbar"), + std::make_pair((int)Qt::Key_section , "section"), + std::make_pair((int)Qt::Key_diaeresis , "diaeresis"), + std::make_pair((int)Qt::Key_copyright , "copyright"), + std::make_pair((int)Qt::Key_ordfeminine , "ordfeminine"), + std::make_pair((int)Qt::Key_guillemotleft , "guillemotleft"), + std::make_pair((int)Qt::Key_notsign , "notsign"), + std::make_pair((int)Qt::Key_hyphen , "hyphen"), + std::make_pair((int)Qt::Key_registered , "registered"), + std::make_pair((int)Qt::Key_macron , "macron"), + std::make_pair((int)Qt::Key_degree , "degree"), + std::make_pair((int)Qt::Key_plusminus , "plusminus"), + std::make_pair((int)Qt::Key_twosuperior , "twosuperior"), + std::make_pair((int)Qt::Key_threesuperior , "threesuperior"), + std::make_pair((int)Qt::Key_acute , "acute"), + std::make_pair((int)Qt::Key_mu , "mu"), + std::make_pair((int)Qt::Key_paragraph , "paragraph"), + std::make_pair((int)Qt::Key_periodcentered , "periodcentered"), + std::make_pair((int)Qt::Key_cedilla , "cedilla"), + std::make_pair((int)Qt::Key_onesuperior , "onesuperior"), + std::make_pair((int)Qt::Key_masculine , "masculine"), + std::make_pair((int)Qt::Key_guillemotright , "guillemotright"), + std::make_pair((int)Qt::Key_onequarter , "onequarter"), + std::make_pair((int)Qt::Key_onehalf , "onehalf"), + std::make_pair((int)Qt::Key_threequarters , "threequarters"), + std::make_pair((int)Qt::Key_questiondown , "questiondown"), + std::make_pair((int)Qt::Key_Agrave , "Agrave"), + std::make_pair((int)Qt::Key_Aacute , "Aacute"), + std::make_pair((int)Qt::Key_Acircumflex , "Acircumflex"), + std::make_pair((int)Qt::Key_Atilde , "Atilde"), + std::make_pair((int)Qt::Key_Adiaeresis , "Adiaeresis"), + std::make_pair((int)Qt::Key_Aring , "Aring"), + std::make_pair((int)Qt::Key_AE , "AE"), + std::make_pair((int)Qt::Key_Ccedilla , "Ccedilla"), + std::make_pair((int)Qt::Key_Egrave , "Egrave"), + std::make_pair((int)Qt::Key_Eacute , "Eacute"), + std::make_pair((int)Qt::Key_Ecircumflex , "Ecircumflex"), + std::make_pair((int)Qt::Key_Ediaeresis , "Ediaeresis"), + std::make_pair((int)Qt::Key_Igrave , "Igrave"), + std::make_pair((int)Qt::Key_Iacute , "Iacute"), + std::make_pair((int)Qt::Key_Icircumflex , "Icircumflex"), + std::make_pair((int)Qt::Key_Idiaeresis , "Idiaeresis"), + std::make_pair((int)Qt::Key_ETH , "ETH"), + std::make_pair((int)Qt::Key_Ntilde , "Ntilde"), + std::make_pair((int)Qt::Key_Ograve , "Ograve"), + std::make_pair((int)Qt::Key_Oacute , "Oacute"), + std::make_pair((int)Qt::Key_Ocircumflex , "Ocircumflex"), + std::make_pair((int)Qt::Key_Otilde , "Otilde"), + std::make_pair((int)Qt::Key_Odiaeresis , "Odiaeresis"), + std::make_pair((int)Qt::Key_multiply , "multiply"), + std::make_pair((int)Qt::Key_Ooblique , "Ooblique"), + std::make_pair((int)Qt::Key_Ugrave , "Ugrave"), + std::make_pair((int)Qt::Key_Uacute , "Uacute"), + std::make_pair((int)Qt::Key_Ucircumflex , "Ucircumflex"), + std::make_pair((int)Qt::Key_Udiaeresis , "Udiaeresis"), + std::make_pair((int)Qt::Key_Yacute , "Yacute"), + std::make_pair((int)Qt::Key_THORN , "THORN"), + std::make_pair((int)Qt::Key_ssharp , "ssharp"), + std::make_pair((int)Qt::Key_division , "division"), + std::make_pair((int)Qt::Key_ydiaeresis , "ydiaeresis"), + std::make_pair((int)Qt::Key_Escape , "Escape"), + std::make_pair((int)Qt::Key_Tab , "Tab"), + std::make_pair((int)Qt::Key_Backtab , "Backtab"), + std::make_pair((int)Qt::Key_Backspace , "Backspace"), + std::make_pair((int)Qt::Key_Return , "Return"), + std::make_pair((int)Qt::Key_Enter , "Enter"), + std::make_pair((int)Qt::Key_Insert , "Insert"), + std::make_pair((int)Qt::Key_Delete , "Delete"), + std::make_pair((int)Qt::Key_Pause , "Pause"), + std::make_pair((int)Qt::Key_Print , "Print"), + std::make_pair((int)Qt::Key_SysReq , "SysReq"), + std::make_pair((int)Qt::Key_Clear , "Clear"), + std::make_pair((int)Qt::Key_Home , "Home"), + std::make_pair((int)Qt::Key_End , "End"), + std::make_pair((int)Qt::Key_Left , "Left"), + std::make_pair((int)Qt::Key_Up , "Up"), + std::make_pair((int)Qt::Key_Right , "Right"), + std::make_pair((int)Qt::Key_Down , "Down"), + std::make_pair((int)Qt::Key_PageUp , "PageUp"), + std::make_pair((int)Qt::Key_PageDown , "PageDown"), + std::make_pair((int)Qt::Key_Shift , "Shift"), + std::make_pair((int)Qt::Key_Control , "Control"), + std::make_pair((int)Qt::Key_Meta , "Meta"), + std::make_pair((int)Qt::Key_Alt , "Alt"), + std::make_pair((int)Qt::Key_CapsLock , "CapsLock"), + std::make_pair((int)Qt::Key_NumLock , "NumLock"), + std::make_pair((int)Qt::Key_ScrollLock , "ScrollLock"), + std::make_pair((int)Qt::Key_F1 , "F1"), + std::make_pair((int)Qt::Key_F2 , "F2"), + std::make_pair((int)Qt::Key_F3 , "F3"), + std::make_pair((int)Qt::Key_F4 , "F4"), + std::make_pair((int)Qt::Key_F5 , "F5"), + std::make_pair((int)Qt::Key_F6 , "F6"), + std::make_pair((int)Qt::Key_F7 , "F7"), + std::make_pair((int)Qt::Key_F8 , "F8"), + std::make_pair((int)Qt::Key_F9 , "F9"), + std::make_pair((int)Qt::Key_F10 , "F10"), + std::make_pair((int)Qt::Key_F11 , "F11"), + std::make_pair((int)Qt::Key_F12 , "F12"), + std::make_pair((int)Qt::Key_F13 , "F13"), + std::make_pair((int)Qt::Key_F14 , "F14"), + std::make_pair((int)Qt::Key_F15 , "F15"), + std::make_pair((int)Qt::Key_F16 , "F16"), + std::make_pair((int)Qt::Key_F17 , "F17"), + std::make_pair((int)Qt::Key_F18 , "F18"), + std::make_pair((int)Qt::Key_F19 , "F19"), + std::make_pair((int)Qt::Key_F20 , "F20"), + std::make_pair((int)Qt::Key_F21 , "F21"), + std::make_pair((int)Qt::Key_F22 , "F22"), + std::make_pair((int)Qt::Key_F23 , "F23"), + std::make_pair((int)Qt::Key_F24 , "F24"), + std::make_pair((int)Qt::Key_F25 , "F25"), + std::make_pair((int)Qt::Key_F26 , "F26"), + std::make_pair((int)Qt::Key_F27 , "F27"), + std::make_pair((int)Qt::Key_F28 , "F28"), + std::make_pair((int)Qt::Key_F29 , "F29"), + std::make_pair((int)Qt::Key_F30 , "F30"), + std::make_pair((int)Qt::Key_F31 , "F31"), + std::make_pair((int)Qt::Key_F32 , "F32"), + std::make_pair((int)Qt::Key_F33 , "F33"), + std::make_pair((int)Qt::Key_F34 , "F34"), + std::make_pair((int)Qt::Key_F35 , "F35"), + std::make_pair((int)Qt::Key_Super_L , "Super_L"), + std::make_pair((int)Qt::Key_Super_R , "Super_R"), + std::make_pair((int)Qt::Key_Menu , "Menu"), + std::make_pair((int)Qt::Key_Hyper_L , "Hyper_L"), + std::make_pair((int)Qt::Key_Hyper_R , "Hyper_R"), + std::make_pair((int)Qt::Key_Help , "Help"), + std::make_pair((int)Qt::Key_Direction_L , "Direction_L"), + std::make_pair((int)Qt::Key_Direction_R , "Direction_R"), + std::make_pair((int)Qt::Key_Back , "Back"), + std::make_pair((int)Qt::Key_Forward , "Forward"), + std::make_pair((int)Qt::Key_Stop , "Stop"), + std::make_pair((int)Qt::Key_Refresh , "Refresh"), + std::make_pair((int)Qt::Key_VolumeDown , "VolumeDown"), + std::make_pair((int)Qt::Key_VolumeMute , "VolumeMute"), + std::make_pair((int)Qt::Key_VolumeUp , "VolumeUp"), + std::make_pair((int)Qt::Key_BassBoost , "BassBoost"), + std::make_pair((int)Qt::Key_BassUp , "BassUp"), + std::make_pair((int)Qt::Key_BassDown , "BassDown"), + std::make_pair((int)Qt::Key_TrebleUp , "TrebleUp"), + std::make_pair((int)Qt::Key_TrebleDown , "TrebleDown"), + std::make_pair((int)Qt::Key_MediaPlay , "MediaPlay"), + std::make_pair((int)Qt::Key_MediaStop , "MediaStop"), + std::make_pair((int)Qt::Key_MediaPrevious , "MediaPrevious"), + std::make_pair((int)Qt::Key_MediaNext , "MediaNext"), + std::make_pair((int)Qt::Key_MediaRecord , "MediaRecord"), + std::make_pair((int)Qt::Key_MediaPause , "MediaPause"), + std::make_pair((int)Qt::Key_MediaTogglePlayPause , "MediaTogglePlayPause"), + std::make_pair((int)Qt::Key_HomePage , "HomePage"), + std::make_pair((int)Qt::Key_Favorites , "Favorites"), + std::make_pair((int)Qt::Key_Search , "Search"), + std::make_pair((int)Qt::Key_Standby , "Standby"), + std::make_pair((int)Qt::Key_OpenUrl , "OpenUrl"), + std::make_pair((int)Qt::Key_LaunchMail , "LaunchMail"), + std::make_pair((int)Qt::Key_LaunchMedia , "LaunchMedia"), + std::make_pair((int)Qt::Key_Launch0 , "Launch0"), + std::make_pair((int)Qt::Key_Launch1 , "Launch1"), + std::make_pair((int)Qt::Key_Launch2 , "Launch2"), + std::make_pair((int)Qt::Key_Launch3 , "Launch3"), + std::make_pair((int)Qt::Key_Launch4 , "Launch4"), + std::make_pair((int)Qt::Key_Launch5 , "Launch5"), + std::make_pair((int)Qt::Key_Launch6 , "Launch6"), + std::make_pair((int)Qt::Key_Launch7 , "Launch7"), + std::make_pair((int)Qt::Key_Launch8 , "Launch8"), + std::make_pair((int)Qt::Key_Launch9 , "Launch9"), + std::make_pair((int)Qt::Key_LaunchA , "LaunchA"), + std::make_pair((int)Qt::Key_LaunchB , "LaunchB"), + std::make_pair((int)Qt::Key_LaunchC , "LaunchC"), + std::make_pair((int)Qt::Key_LaunchD , "LaunchD"), + std::make_pair((int)Qt::Key_LaunchE , "LaunchE"), + std::make_pair((int)Qt::Key_LaunchF , "LaunchF"), + std::make_pair((int)Qt::Key_MonBrightnessUp , "MonBrightnessUp"), + std::make_pair((int)Qt::Key_MonBrightnessDown , "MonBrightnessDown"), + std::make_pair((int)Qt::Key_KeyboardLightOnOff , "KeyboardLightOnOff"), + std::make_pair((int)Qt::Key_KeyboardBrightnessUp , "KeyboardBrightnessUp"), + std::make_pair((int)Qt::Key_KeyboardBrightnessDown , "KeyboardBrightnessDown"), + std::make_pair((int)Qt::Key_PowerOff , "PowerOff"), + std::make_pair((int)Qt::Key_WakeUp , "WakeUp"), + std::make_pair((int)Qt::Key_Eject , "Eject"), + std::make_pair((int)Qt::Key_ScreenSaver , "ScreenSaver"), + std::make_pair((int)Qt::Key_WWW , "WWW"), + std::make_pair((int)Qt::Key_Memo , "Memo"), + std::make_pair((int)Qt::Key_LightBulb , "LightBulb"), + std::make_pair((int)Qt::Key_Shop , "Shop"), + std::make_pair((int)Qt::Key_History , "History"), + std::make_pair((int)Qt::Key_AddFavorite , "AddFavorite"), + std::make_pair((int)Qt::Key_HotLinks , "HotLinks"), + std::make_pair((int)Qt::Key_BrightnessAdjust , "BrightnessAdjust"), + std::make_pair((int)Qt::Key_Finance , "Finance"), + std::make_pair((int)Qt::Key_Community , "Community"), + std::make_pair((int)Qt::Key_AudioRewind , "AudioRewind"), + std::make_pair((int)Qt::Key_BackForward , "BackForward"), + std::make_pair((int)Qt::Key_ApplicationLeft , "ApplicationLeft"), + std::make_pair((int)Qt::Key_ApplicationRight , "ApplicationRight"), + std::make_pair((int)Qt::Key_Book , "Book"), + std::make_pair((int)Qt::Key_CD , "CD"), + std::make_pair((int)Qt::Key_Calculator , "Calculator"), + std::make_pair((int)Qt::Key_ToDoList , "ToDoList"), + std::make_pair((int)Qt::Key_ClearGrab , "ClearGrab"), + std::make_pair((int)Qt::Key_Close , "Close"), + std::make_pair((int)Qt::Key_Copy , "Copy"), + std::make_pair((int)Qt::Key_Cut , "Cut"), + std::make_pair((int)Qt::Key_Display , "Display"), + std::make_pair((int)Qt::Key_DOS , "DOS"), + std::make_pair((int)Qt::Key_Documents , "Documents"), + std::make_pair((int)Qt::Key_Excel , "Excel"), + std::make_pair((int)Qt::Key_Explorer , "Explorer"), + std::make_pair((int)Qt::Key_Game , "Game"), + std::make_pair((int)Qt::Key_Go , "Go"), + std::make_pair((int)Qt::Key_iTouch , "iTouch"), + std::make_pair((int)Qt::Key_LogOff , "LogOff"), + std::make_pair((int)Qt::Key_Market , "Market"), + std::make_pair((int)Qt::Key_Meeting , "Meeting"), + std::make_pair((int)Qt::Key_MenuKB , "MenuKB"), + std::make_pair((int)Qt::Key_MenuPB , "MenuPB"), + std::make_pair((int)Qt::Key_MySites , "MySites"), + std::make_pair((int)Qt::Key_News , "News"), + std::make_pair((int)Qt::Key_OfficeHome , "OfficeHome"), + std::make_pair((int)Qt::Key_Option , "Option"), + std::make_pair((int)Qt::Key_Paste , "Paste"), + std::make_pair((int)Qt::Key_Phone , "Phone"), + std::make_pair((int)Qt::Key_Calendar , "Calendar"), + std::make_pair((int)Qt::Key_Reply , "Reply"), + std::make_pair((int)Qt::Key_Reload , "Reload"), + std::make_pair((int)Qt::Key_RotateWindows , "RotateWindows"), + std::make_pair((int)Qt::Key_RotationPB , "RotationPB"), + std::make_pair((int)Qt::Key_RotationKB , "RotationKB"), + std::make_pair((int)Qt::Key_Save , "Save"), + std::make_pair((int)Qt::Key_Send , "Send"), + std::make_pair((int)Qt::Key_Spell , "Spell"), + std::make_pair((int)Qt::Key_SplitScreen , "SplitScreen"), + std::make_pair((int)Qt::Key_Support , "Support"), + std::make_pair((int)Qt::Key_TaskPane , "TaskPane"), + std::make_pair((int)Qt::Key_Terminal , "Terminal"), + std::make_pair((int)Qt::Key_Tools , "Tools"), + std::make_pair((int)Qt::Key_Travel , "Travel"), + std::make_pair((int)Qt::Key_Video , "Video"), + std::make_pair((int)Qt::Key_Word , "Word"), + std::make_pair((int)Qt::Key_Xfer , "Xfer"), + std::make_pair((int)Qt::Key_ZoomIn , "ZoomIn"), + std::make_pair((int)Qt::Key_ZoomOut , "ZoomOut"), + std::make_pair((int)Qt::Key_Away , "Away"), + std::make_pair((int)Qt::Key_Messenger , "Messenger"), + std::make_pair((int)Qt::Key_WebCam , "WebCam"), + std::make_pair((int)Qt::Key_MailForward , "MailForward"), + std::make_pair((int)Qt::Key_Pictures , "Pictures"), + std::make_pair((int)Qt::Key_Music , "Music"), + std::make_pair((int)Qt::Key_Battery , "Battery"), + std::make_pair((int)Qt::Key_Bluetooth , "Bluetooth"), + std::make_pair((int)Qt::Key_WLAN , "WLAN"), + std::make_pair((int)Qt::Key_UWB , "UWB"), + std::make_pair((int)Qt::Key_AudioForward , "AudioForward"), + std::make_pair((int)Qt::Key_AudioRepeat , "AudioRepeat"), + std::make_pair((int)Qt::Key_AudioRandomPlay , "AudioRandomPlay"), + std::make_pair((int)Qt::Key_Subtitle , "Subtitle"), + std::make_pair((int)Qt::Key_AudioCycleTrack , "AudioCycleTrack"), + std::make_pair((int)Qt::Key_Time , "Time"), + std::make_pair((int)Qt::Key_Hibernate , "Hibernate"), + std::make_pair((int)Qt::Key_View , "View"), + std::make_pair((int)Qt::Key_TopMenu , "TopMenu"), + std::make_pair((int)Qt::Key_PowerDown , "PowerDown"), + std::make_pair((int)Qt::Key_Suspend , "Suspend"), + std::make_pair((int)Qt::Key_ContrastAdjust , "ContrastAdjust"), + std::make_pair((int)Qt::Key_LaunchG , "LaunchG"), + std::make_pair((int)Qt::Key_LaunchH , "LaunchH"), + std::make_pair((int)Qt::Key_TouchpadToggle , "TouchpadToggle"), + std::make_pair((int)Qt::Key_TouchpadOn , "TouchpadOn"), + std::make_pair((int)Qt::Key_TouchpadOff , "TouchpadOff"), + std::make_pair((int)Qt::Key_MicMute , "MicMute"), + std::make_pair((int)Qt::Key_Red , "Red"), + std::make_pair((int)Qt::Key_Green , "Green"), + std::make_pair((int)Qt::Key_Yellow , "Yellow"), + std::make_pair((int)Qt::Key_Blue , "Blue"), + std::make_pair((int)Qt::Key_ChannelUp , "ChannelUp"), + std::make_pair((int)Qt::Key_ChannelDown , "ChannelDown"), + std::make_pair((int)Qt::Key_Guide , "Guide"), + std::make_pair((int)Qt::Key_Info , "Info"), + std::make_pair((int)Qt::Key_Settings , "Settings"), + std::make_pair((int)Qt::Key_MicVolumeUp , "MicVolumeUp"), + std::make_pair((int)Qt::Key_MicVolumeDown , "MicVolumeDown"), + std::make_pair((int)Qt::Key_New , "New"), + std::make_pair((int)Qt::Key_Open , "Open"), + std::make_pair((int)Qt::Key_Find , "Find"), + std::make_pair((int)Qt::Key_Undo , "Undo"), + std::make_pair((int)Qt::Key_Redo , "Redo"), + std::make_pair((int)Qt::Key_AltGr , "AltGr"), + std::make_pair((int)Qt::Key_Multi_key , "Multi_key"), + std::make_pair((int)Qt::Key_Kanji , "Kanji"), + std::make_pair((int)Qt::Key_Muhenkan , "Muhenkan"), + std::make_pair((int)Qt::Key_Henkan , "Henkan"), + std::make_pair((int)Qt::Key_Romaji , "Romaji"), + std::make_pair((int)Qt::Key_Hiragana , "Hiragana"), + std::make_pair((int)Qt::Key_Katakana , "Katakana"), + std::make_pair((int)Qt::Key_Hiragana_Katakana , "Hiragana_Katakana"), + std::make_pair((int)Qt::Key_Zenkaku , "Zenkaku"), + std::make_pair((int)Qt::Key_Hankaku , "Hankaku"), + std::make_pair((int)Qt::Key_Zenkaku_Hankaku , "Zenkaku_Hankaku"), + std::make_pair((int)Qt::Key_Touroku , "Touroku"), + std::make_pair((int)Qt::Key_Massyo , "Massyo"), + std::make_pair((int)Qt::Key_Kana_Lock , "Kana_Lock"), + std::make_pair((int)Qt::Key_Kana_Shift , "Kana_Shift"), + std::make_pair((int)Qt::Key_Eisu_Shift , "Eisu_Shift"), + std::make_pair((int)Qt::Key_Eisu_toggle , "Eisu_toggle"), + std::make_pair((int)Qt::Key_Hangul , "Hangul"), + std::make_pair((int)Qt::Key_Hangul_Start , "Hangul_Start"), + std::make_pair((int)Qt::Key_Hangul_End , "Hangul_End"), + std::make_pair((int)Qt::Key_Hangul_Hanja , "Hangul_Hanja"), + std::make_pair((int)Qt::Key_Hangul_Jamo , "Hangul_Jamo"), + std::make_pair((int)Qt::Key_Hangul_Romaja , "Hangul_Romaja"), + std::make_pair((int)Qt::Key_Codeinput , "Codeinput"), + std::make_pair((int)Qt::Key_Hangul_Jeonja , "Hangul_Jeonja"), + std::make_pair((int)Qt::Key_Hangul_Banja , "Hangul_Banja"), + std::make_pair((int)Qt::Key_Hangul_PreHanja , "Hangul_PreHanja"), + std::make_pair((int)Qt::Key_Hangul_PostHanja , "Hangul_PostHanja"), + std::make_pair((int)Qt::Key_SingleCandidate , "SingleCandidate"), + std::make_pair((int)Qt::Key_MultipleCandidate , "MultipleCandidate"), + std::make_pair((int)Qt::Key_PreviousCandidate , "PreviousCandidate"), + std::make_pair((int)Qt::Key_Hangul_Special , "Hangul_Special"), + std::make_pair((int)Qt::Key_Mode_switch , "Mode_switch"), + std::make_pair((int)Qt::Key_Dead_Grave , "Dead_Grave"), + std::make_pair((int)Qt::Key_Dead_Acute , "Dead_Acute"), + std::make_pair((int)Qt::Key_Dead_Circumflex , "Dead_Circumflex"), + std::make_pair((int)Qt::Key_Dead_Tilde , "Dead_Tilde"), + std::make_pair((int)Qt::Key_Dead_Macron , "Dead_Macron"), + std::make_pair((int)Qt::Key_Dead_Breve , "Dead_Breve"), + std::make_pair((int)Qt::Key_Dead_Abovedot , "Dead_Abovedot"), + std::make_pair((int)Qt::Key_Dead_Diaeresis , "Dead_Diaeresis"), + std::make_pair((int)Qt::Key_Dead_Abovering , "Dead_Abovering"), + std::make_pair((int)Qt::Key_Dead_Doubleacute , "Dead_Doubleacute"), + std::make_pair((int)Qt::Key_Dead_Caron , "Dead_Caron"), + std::make_pair((int)Qt::Key_Dead_Cedilla , "Dead_Cedilla"), + std::make_pair((int)Qt::Key_Dead_Ogonek , "Dead_Ogonek"), + std::make_pair((int)Qt::Key_Dead_Iota , "Dead_Iota"), + std::make_pair((int)Qt::Key_Dead_Voiced_Sound , "Dead_Voiced_Sound"), + std::make_pair((int)Qt::Key_Dead_Semivoiced_Sound , "Dead_Semivoiced_Sound"), + std::make_pair((int)Qt::Key_Dead_Belowdot , "Dead_Belowdot"), + std::make_pair((int)Qt::Key_Dead_Hook , "Dead_Hook"), + std::make_pair((int)Qt::Key_Dead_Horn , "Dead_Horn"), + std::make_pair((int)Qt::Key_MediaLast , "MediaLast"), + std::make_pair((int)Qt::Key_Select , "Select"), + std::make_pair((int)Qt::Key_Yes , "Yes"), + std::make_pair((int)Qt::Key_No , "No"), + std::make_pair((int)Qt::Key_Cancel , "Cancel"), + std::make_pair((int)Qt::Key_Printer , "Printer"), + std::make_pair((int)Qt::Key_Execute , "Execute"), + std::make_pair((int)Qt::Key_Sleep , "Sleep"), + std::make_pair((int)Qt::Key_Play , "Play"), + std::make_pair((int)Qt::Key_Zoom , "Zoom"), + std::make_pair((int)Qt::Key_Exit , "Exit"), + std::make_pair((int)Qt::Key_Context1 , "Context1"), + std::make_pair((int)Qt::Key_Context2 , "Context2"), + std::make_pair((int)Qt::Key_Context3 , "Context3"), + std::make_pair((int)Qt::Key_Context4 , "Context4"), + std::make_pair((int)Qt::Key_Call , "Call"), + std::make_pair((int)Qt::Key_Hangup , "Hangup"), + std::make_pair((int)Qt::Key_Flip , "Flip"), + std::make_pair((int)Qt::Key_ToggleCallHangup , "ToggleCallHangup"), + std::make_pair((int)Qt::Key_VoiceDial , "VoiceDial"), + std::make_pair((int)Qt::Key_LastNumberRedial , "LastNumberRedial"), + std::make_pair((int)Qt::Key_Camera , "Camera"), + std::make_pair((int)Qt::Key_CameraFocus , "CameraFocus"), + std::make_pair(0 , (const char*) 0) + }; + } diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index fe813341c..26bdc4255 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -18,10 +18,6 @@ namespace CSMPrefs public: - /// Key Sequence, Modifier (for secondary signal) - typedef std::pair SequenceData; - - ShortcutManager(); /// The shortcut class will do this automatically @@ -30,22 +26,41 @@ namespace CSMPrefs /// The shortcut class will do this automatically void removeShortcut(Shortcut* shortcut); - SequenceData getSequence(const std::string& name) const; - void setSequence(const std::string& name, const SequenceData& sequence); + bool getSequence(const std::string& name, QKeySequence& sequence, int& modifier) const; + void setSequence(const std::string& name, const QKeySequence& sequence, int modifier); + + std::string convertToString(const QKeySequence& sequence) const; + std::string convertToString(int modifier) const; + + std::string convertToString(const QKeySequence& sequence, int modifier) const; + + void convertFromString(const std::string& data, QKeySequence& sequence) const; + void convertFromString(const std::string& data, int& modifier) const; - std::string sequenceToString(const SequenceData& sequence); - SequenceData stringToSequence(const std::string& str); + void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const; private: + /// Key Sequence, Modifier (for secondary signal) + typedef std::pair SequenceData; + // Need a multimap in case multiple shortcuts share the same name typedef std::multimap ShortcutMap; typedef std::map SequenceMap; + typedef std::map NameMap; + typedef std::map KeyMap; ShortcutMap mShortcuts; SequenceMap mSequences; + NameMap mNames; + KeyMap mKeys; + ShortcutEventHandler* mEventHandler; + + void createLookupTables(); + + static const std::pair QtKeys[]; }; } diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index fa2628e32..074f9c0b2 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -1,7 +1,13 @@ #include "shortcutsetting.hpp" +#include + +#include +#include #include #include +#include +#include #include #include "state.hpp" @@ -10,34 +16,163 @@ namespace CSMPrefs { ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, - const std::string& label, const SequenceData& default_) + const std::string& label, const QKeySequence& default_) : Setting(parent, values, mutex, key, label) , mDefault(default_) + , mEditorActive(false) + , mEditorPos(0) { - State::get().getShortcutManager().setSequence(key, mDefault); + const int MaxKeys = 4; // A limitation of QKeySequence + + for (int i = 0; i < MaxKeys; ++i) + { + mEditorKeys[i] = 0; + } } std::pair ShortcutSetting::makeWidgets(QWidget* parent) { + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(mDefault).c_str()); + QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent); - QLineEdit* widget = new QLineEdit(State::get().getShortcutManager().sequenceToString(mDefault).c_str(), parent); + QPushButton* widget = new QPushButton(text, parent); + + widget->setCheckable(true); + widget->installEventFilter(this); + mButton = widget; - connect(widget, SIGNAL(textChanged(const QString&)), this, SLOT(valueChanged(const QString&))); + connect(widget, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool))); return std::make_pair(label, widget); } - void ShortcutSetting::valueChanged(const QString& text) + bool ShortcutSetting::eventFilter(QObject* target, QEvent* event) { + if (event->type() == QEvent::KeyPress) { - QMutexLocker lock(getMutex()); - getValues().setString(getKey(), getParent()->getKey(), text.toUtf8().data()); + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->isAutoRepeat()) + return true; - SequenceData data = State::get().getShortcutManager().stringToSequence(text.toUtf8().data()); + int mod = keyEvent->modifiers(); + int key = keyEvent->key(); - State::get().getShortcutManager().setSequence(getKey(), data); + return handleEvent(target, mod, key, true); } + else if (event->type() == QEvent::KeyRelease) + { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->isAutoRepeat()) + return true; + + int mod = keyEvent->modifiers(); + int key = keyEvent->key(); + + return handleEvent(target, mod, key, false); + } + else if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* mouseEvent = static_cast(event); + int mod = mouseEvent->modifiers(); + int key = mouseEvent->button(); + + return handleEvent(target, mod, key, true); + } + else if (event->type() == QEvent::MouseButtonRelease) + { + QMouseEvent* mouseEvent = static_cast(event); + int mod = mouseEvent->modifiers(); + int key = mouseEvent->button(); + + return handleEvent(target, mod, key, false); + } + + return false; + } + + bool ShortcutSetting::handleEvent(QObject* target, int mod, int value, bool active) + { + const int MaxKeys = 4; // A limitation of QKeySequence + + // Modifiers are handled differently + const int Blacklist[] + { + Qt::Key_Shift, + Qt::Key_Control, + Qt::Key_Meta, + Qt::Key_Alt, + Qt::Key_AltGr + }; + + const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int); + + if (!mEditorActive) + return false; + + // Handle blacklist + for (size_t i = 0; i < BlacklistSize; ++i) + { + if (value == Blacklist[i]) + return true; + } + + if (!active || mEditorPos >= MaxKeys) + { + // Update key + QKeySequence sequence; + int modifier = 0; + + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + sequence = QKeySequence(mEditorKeys[0], mEditorKeys[1], mEditorKeys[2], mEditorKeys[3]); + State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + + // Store + { + std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), value); + } + + getParent()->getState()->update(*this); + + // Update button + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); + + mButton->setText(text); + mButton->setChecked(false); + mEditorActive = false; + + // Reset + mEditorPos = 0; + for (int i = 0; i < MaxKeys; ++i) + { + mEditorKeys[i] = 0; + } + } + else + { + if (mEditorPos == 0) + { + mEditorKeys[0] = mod | value; + } + else + { + mEditorKeys[mEditorPos] = value; + } + + mEditorPos += 1; + } + + return true; + } + + void ShortcutSetting::buttonToggled(bool checked) + { + if (checked) + mButton->setText("Press keys or click here..."); - getParent()->getState()->update(*this); + mEditorActive = checked; } } diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp index e1979c800..2a86e68dd 100644 --- a/apps/opencs/model/prefs/shortcutsetting.hpp +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -5,6 +5,9 @@ #include "setting.hpp" +class QEvent; +class QPushButton; + namespace CSMPrefs { class ShortcutSetting : public Setting @@ -13,21 +16,30 @@ namespace CSMPrefs public: - typedef std::pair SequenceData; - ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, - const std::string& label, const SequenceData& default_); + const std::string& label, const QKeySequence& default_); - // TODO replace with custom page virtual std::pair makeWidgets(QWidget* parent); + protected: + + bool eventFilter(QObject* target, QEvent* event); + private: - SequenceData mDefault; + bool handleEvent(QObject* target, int mod, int value, bool active); + + QKeySequence mDefault; + + QPushButton* mButton; + + bool mEditorActive; + int mEditorPos; + int mEditorKeys[4]; private slots: - void valueChanged(const QString& text); + void buttonToggled(bool checked); }; } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 75e15c08c..5803e56a0 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -381,20 +381,23 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, } CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_, int modifier) + const QKeySequence& default_, int modifier_) { if (mCurrentCategory==mCategories.end()) throw std::logic_error ("no category for setting"); - std::string seqStr = getShortcutManager().sequenceToString(std::make_pair(default_, modifier)); + std::string seqStr = getShortcutManager().convertToString(default_, modifier_); setDefault (key, seqStr); - ShortcutManager::SequenceData data = getShortcutManager().stringToSequence(mSettings.getString(key, - mCurrentCategory->second.getKey())); + // Setup with actual data + QKeySequence sequence; + int mod; - CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, - key, label, data); + getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence, mod); + getShortcutManager().setSequence(key, sequence, mod); + CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, + key, label, sequence); mCurrentCategory->second.addSetting (setting); return *setting; diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 4ab713167..23d9df387 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -75,7 +75,7 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_, int modifier=0); + const QKeySequence& default_, int modifier_=0); void declareSeparator(); From 3edc77a32b5b824a7fc813f84e8291eb8869b582 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 00:24:16 -0400 Subject: [PATCH 29/46] Remove QShortcut usage, Add a lot of shortcuts, Remove debug messages --- apps/opencs/model/prefs/shortcut.cpp | 6 +- apps/opencs/model/prefs/shortcutmanager.cpp | 4 -- apps/opencs/model/prefs/shortcutsetting.cpp | 2 - apps/opencs/model/prefs/state.cpp | 66 ++++++++++++++++----- apps/opencs/view/doc/view.cpp | 65 ++++++++++++++++++-- apps/opencs/view/doc/view.hpp | 2 + apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/widget/scenetoolbar.cpp | 8 +-- 8 files changed, 121 insertions(+), 33 deletions(-) diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index 182437f47..90ec987ff 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -137,7 +137,10 @@ namespace CSMPrefs { if (mAction) { - disconnect(this, SLOT(actionDeleted())); + mAction->setText(mActionText); + + disconnect(this, SIGNAL(activated()), mAction, SLOT(trigger())); + disconnect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted())); } mAction = action; @@ -147,6 +150,7 @@ namespace CSMPrefs mActionText = mAction->text(); mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data()); + connect(this, SIGNAL(activated()), mAction, SLOT(trigger())); connect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted())); } } diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 6be1840dd..4d283f93f 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -141,9 +140,6 @@ namespace CSMPrefs std::string ShortcutManager::convertToString(const QKeySequence& sequence, int modifier) const { std::string concat = convertToString(sequence) + ";" + convertToString(modifier); - std::cout << sequence[0] << "." << sequence[1] << "."<< sequence[2] << "."<< sequence[3] << "." << modifier << std::endl; - std::cout << concat << std::endl; - return concat; } diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 074f9c0b2..cd2c1fcf5 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -1,7 +1,5 @@ #include "shortcutsetting.hpp" -#include - #include #include #include diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 5803e56a0..4b5ddffd1 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -168,16 +168,6 @@ void CSMPrefs::State::declare() "list go to the first/last item"); declareCategory ("3D Scene Input"); - EnumValue left ("Left Mouse-Button"); - EnumValue cLeft ("Ctrl-Left Mouse-Button"); - EnumValue right ("Right Mouse-Button"); - EnumValue cRight ("Ctrl-Right Mouse-Button"); - EnumValue middle ("Middle Mouse-Button"); - EnumValue cMiddle ("Ctrl-Middle Mouse-Button"); - EnumValues inputButtons; - inputButtons.add (left).add (cLeft).add (right).add (cRight).add (middle).add (cMiddle); - declareEnum ("p-navi", "Primary Camera Navigation Button", left).addValues (inputButtons); - declareEnum ("s-navi", "Secondary Camera Navigation Button", cLeft).addValues (inputButtons); declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0); declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false); declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0); @@ -189,10 +179,6 @@ void CSMPrefs::State::declare() declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0); declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28); declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0); - declareEnum ("p-edit", "Primary Editing Button", right).addValues (inputButtons); - declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons); - declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons); - declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons); declareSeparator(); declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). @@ -230,7 +216,57 @@ void CSMPrefs::State::declare() declareCategory ("Key Bindings"); - declareShortcut ("document-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); + declareShortcut ("document-file-newgame", "Create new game", QKeySequence()); + declareShortcut ("document-file-newaddon", "Create new addon", QKeySequence()); + declareShortcut ("document-file-open", "Open", QKeySequence()); + declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); + declareShortcut ("document-file-verify", "Verify", QKeySequence(Qt::ControlModifier | Qt::Key_V)); + declareShortcut ("document-file-merge", "Merge", QKeySequence()); + declareShortcut ("document-file-errorlog", "Load error log", QKeySequence()); + declareShortcut ("document-file-metadata", "Meta Data", QKeySequence()); + declareShortcut ("document-file-close", "Close", QKeySequence()); + declareShortcut ("document-file-exit", "Exit", QKeySequence()); + declareShortcut ("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z)); + declareShortcut ("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z)); + declareShortcut ("document-edit-preferences", "Show Preferences", QKeySequence()); + declareShortcut ("document-edit-search", "Show Search", QKeySequence()); + declareShortcut ("document-view-newview", "New View", QKeySequence()); + declareShortcut ("document-view-statusbar", "Show Status Bar", QKeySequence()); + declareShortcut ("document-view-filters", "Show Filters", QKeySequence()); + declareShortcut ("document-world-regions", "Show Regions", QKeySequence()); + declareShortcut ("document-world-cells", "Show Cells", QKeySequence()); + declareShortcut ("document-world-referencables", "Show Referencables", QKeySequence()); + declareShortcut ("document-world-references", "Show References", QKeySequence()); + declareShortcut ("document-world-pathgrid", "Show Pathgrids", QKeySequence()); + declareShortcut ("document-world-regionmap", "Show Region Map", QKeySequence()); + declareShortcut ("document-mechanics-globals", "Show Globals", QKeySequence()); + declareShortcut ("document-mechanics-gamesettings", "Show Game Settings", QKeySequence()); + declareShortcut ("document-mechanics-scripts", "Show Scripts", QKeySequence()); + declareShortcut ("document-mechanics-spells", "Show Spells", QKeySequence()); + declareShortcut ("document-mechanics-enchantments", "Show Enchantments", QKeySequence()); + declareShortcut ("document-mechanics-magiceffects", "Show Magic Effects", QKeySequence()); + declareShortcut ("document-mechanics-startscripts", "Show Start Scripts", QKeySequence()); + declareShortcut ("document-character-skills", "Show Skills", QKeySequence()); + declareShortcut ("document-character-classes", "Show Classes", QKeySequence()); + declareShortcut ("document-character-factions", "Show Factions", QKeySequence()); + declareShortcut ("document-character-races", "Show Races", QKeySequence()); + declareShortcut ("document-character-birthsigns", "Show Birthsigns", QKeySequence()); + declareShortcut ("document-character-topics", "Show Topics", QKeySequence()); + declareShortcut ("document-character-journals", "Show Journals", QKeySequence()); + declareShortcut ("document-character-topicinfos", "Show Topic Infos", QKeySequence()); + declareShortcut ("document-character-journalinfos", "Show Journal Infos", QKeySequence()); + declareShortcut ("document-character-bodyparts", "Show Body Parts", QKeySequence()); + declareShortcut ("document-assets-sounds", "Show Sound Assets", QKeySequence()); + declareShortcut ("document-assets-soundgens", "Show Sound Generators", QKeySequence()); + declareShortcut ("document-assets-meshes", "Show Mesh Assets", QKeySequence()); + declareShortcut ("document-assets-icons", "Show Icon Assets", QKeySequence()); + declareShortcut ("document-assets-music", "Show Music Assets", QKeySequence()); + declareShortcut ("document-assets-soundres", "Show Sound Files", QKeySequence()); + declareShortcut ("document-assets-textures", "TShow exture Assets", QKeySequence()); + declareShortcut ("document-assets-videos", "Show Video Assets", QKeySequence()); + declareShortcut ("document-debug-run", "Run Debug", QKeySequence()); + declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence()); + declareShortcut ("document-debug-runlog", "Run Log", QKeySequence()); declareSeparator (); declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 4e857db6c..df7146404 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -49,47 +49,54 @@ void CSVDoc::View::setupFileMenu() QAction *newGame = new QAction (tr ("New Game"), this); connect (newGame, SIGNAL (triggered()), this, SIGNAL (newGameRequest())); + setupShortcut("document-file-newgame", newGame); file->addAction (newGame); + QAction *newAddon = new QAction (tr ("New Addon"), this); connect (newAddon, SIGNAL (triggered()), this, SIGNAL (newAddonRequest())); + setupShortcut("document-file-newaddon", newAddon); file->addAction (newAddon); QAction *open = new QAction (tr ("&Open"), this); connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); + setupShortcut("document-file-open", open); file->addAction (open); mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); + setupShortcut("document-file-save", mSave); file->addAction (mSave); - CSMPrefs::Shortcut* saveShortcut = new CSMPrefs::Shortcut("document-save", this); - saveShortcut->associateAction(mSave); - connect (saveShortcut, SIGNAL(activated()), this, SLOT(save())); - mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); + setupShortcut("document-file-verify", mVerify); file->addAction (mVerify); mMerge = new QAction (tr ("Merge"), this); connect (mMerge, SIGNAL (triggered()), this, SLOT (merge())); + setupShortcut("document-file-merge", mMerge); file->addAction (mMerge); QAction *loadErrors = new QAction (tr ("Load Error Log"), this); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); + setupShortcut("document-file-errorlog", loadErrors); file->addAction (loadErrors); QAction *meta = new QAction (tr ("Meta Data"), this); connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView())); + setupShortcut("document-file-metadata", meta); file->addAction (meta); QAction *close = new QAction (tr ("&Close"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); + setupShortcut("document-file-close", close); file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); connect (exit, SIGNAL (triggered()), this, SLOT (exit())); connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); + setupShortcut("document-file-exit", exit); file->addAction(exit); } @@ -99,19 +106,21 @@ void CSVDoc::View::setupEditMenu() QMenu *edit = menuBar()->addMenu (tr ("&Edit")); mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo")); - mUndo->setShortcuts (QKeySequence::Undo); + setupShortcut("document-edit-undo", mUndo); edit->addAction (mUndo); mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); - mRedo->setShortcuts (QKeySequence::Redo); + setupShortcut("document-edit-redo", mRedo); edit->addAction (mRedo); QAction *userSettings = new QAction (tr ("&Preferences"), this); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); + setupShortcut("document-edit-preferences", userSettings); edit->addAction (userSettings); QAction *search = new QAction (tr ("Search"), this); connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + setupShortcut("document-edit-search", search); edit->addAction (search); } @@ -121,11 +130,13 @@ void CSVDoc::View::setupViewMenu() QAction *newWindow = new QAction (tr ("&New View"), this); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); + setupShortcut("document-view-newview", newWindow); view->addAction (newWindow); mShowStatusBar = new QAction (tr ("Show Status Bar"), this); mShowStatusBar->setCheckable (true); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); + setupShortcut("document-view-statusbar", mShowStatusBar); mShowStatusBar->setChecked (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); @@ -133,6 +144,7 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); + setupShortcut("document-view-filters", filters); view->addAction (filters); } @@ -142,28 +154,34 @@ void CSVDoc::View::setupWorldMenu() QAction *regions = new QAction (tr ("Regions"), this); connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); + setupShortcut("document-world-regions", regions); world->addAction (regions); QAction *cells = new QAction (tr ("Cells"), this); connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView())); + setupShortcut("document-world-cells", cells); world->addAction (cells); QAction *referenceables = new QAction (tr ("Objects"), this); connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView())); + setupShortcut("document-world-referencables", referenceables); world->addAction (referenceables); QAction *references = new QAction (tr ("Instances"), this); connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView())); + setupShortcut("document-world-references", references); world->addAction (references); QAction *grid = new QAction (tr ("Pathgrid"), this); connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView())); + setupShortcut("document-world-pathgrid", grid); world->addAction (grid); world->addSeparator(); // items that don't represent single record lists follow here QAction *regionMap = new QAction (tr ("Region Map"), this); connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView())); + setupShortcut("document-world-regionmap", regionMap); world->addAction (regionMap); } @@ -173,30 +191,37 @@ void CSVDoc::View::setupMechanicsMenu() QAction *globals = new QAction (tr ("Globals"), this); connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); + setupShortcut("document-mechanics-globals", globals); mechanics->addAction (globals); QAction *gmsts = new QAction (tr ("Game settings"), this); connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); + setupShortcut("document-mechanics-gamesettings", gmsts); mechanics->addAction (gmsts); QAction *scripts = new QAction (tr ("Scripts"), this); connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); + setupShortcut("document-mechanics-scripts", scripts); mechanics->addAction (scripts); QAction *spells = new QAction (tr ("Spells"), this); connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); + setupShortcut("document-mechanics-spells", spells); mechanics->addAction (spells); QAction *enchantments = new QAction (tr ("Enchantments"), this); connect (enchantments, SIGNAL (triggered()), this, SLOT (addEnchantmentsSubView())); + setupShortcut("document-mechanics-enchantments", enchantments); mechanics->addAction (enchantments); QAction *effects = new QAction (tr ("Magic Effects"), this); connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView())); + setupShortcut("document-mechanics-magiceffects", effects); mechanics->addAction (effects); QAction *startScripts = new QAction (tr ("Start Scripts"), this); connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView())); + setupShortcut("document-mechanics-startscripts", startScripts); mechanics->addAction (startScripts); } @@ -206,42 +231,52 @@ void CSVDoc::View::setupCharacterMenu() QAction *skills = new QAction (tr ("Skills"), this); connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); + setupShortcut("document-character-skills", skills); characters->addAction (skills); QAction *classes = new QAction (tr ("Classes"), this); connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); + setupShortcut("document-character-classes", classes); characters->addAction (classes); QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); + setupShortcut("document-character-factions", factions); characters->addAction (factions); QAction *races = new QAction (tr ("Races"), this); connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); + setupShortcut("document-character-races", races); characters->addAction (races); QAction *birthsigns = new QAction (tr ("Birthsigns"), this); connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); + setupShortcut("document-character-birthsigns", birthsigns); characters->addAction (birthsigns); QAction *topics = new QAction (tr ("Topics"), this); connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView())); + setupShortcut("document-character-topics", topics); characters->addAction (topics); QAction *journals = new QAction (tr ("Journals"), this); connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView())); + setupShortcut("document-character-journals", journals); characters->addAction (journals); QAction *topicInfos = new QAction (tr ("Topic Infos"), this); connect (topicInfos, SIGNAL (triggered()), this, SLOT (addTopicInfosSubView())); + setupShortcut("document-character-topicinfos", topicInfos); characters->addAction (topicInfos); QAction *journalInfos = new QAction (tr ("Journal Infos"), this); connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView())); + setupShortcut("document-character-journalinfos", journalInfos); characters->addAction (journalInfos); QAction *bodyParts = new QAction (tr ("Body Parts"), this); connect (bodyParts, SIGNAL (triggered()), this, SLOT (addBodyPartsSubView())); + setupShortcut("document-character-bodyparts", bodyParts); characters->addAction (bodyParts); } @@ -251,36 +286,44 @@ void CSVDoc::View::setupAssetsMenu() QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); + setupShortcut("document-assets-sounds", sounds); assets->addAction (sounds); QAction *soundGens = new QAction (tr ("Sound Generators"), this); connect (soundGens, SIGNAL (triggered()), this, SLOT (addSoundGensSubView())); + setupShortcut("document-assets-soundgens", soundGens); assets->addAction (soundGens); assets->addSeparator(); // resources follow here QAction *meshes = new QAction (tr ("Meshes"), this); connect (meshes, SIGNAL (triggered()), this, SLOT (addMeshesSubView())); + setupShortcut("document-assets-meshes", meshes); assets->addAction (meshes); QAction *icons = new QAction (tr ("Icons"), this); connect (icons, SIGNAL (triggered()), this, SLOT (addIconsSubView())); + setupShortcut("document-assets-icons", icons); assets->addAction (icons); QAction *musics = new QAction (tr ("Music"), this); connect (musics, SIGNAL (triggered()), this, SLOT (addMusicsSubView())); + setupShortcut("document-assets-music", musics); assets->addAction (musics); QAction *soundsRes = new QAction (tr ("Sound Files"), this); connect (soundsRes, SIGNAL (triggered()), this, SLOT (addSoundsResSubView())); + setupShortcut("document-assets-soundres", soundsRes); assets->addAction (soundsRes); QAction *textures = new QAction (tr ("Textures"), this); connect (textures, SIGNAL (triggered()), this, SLOT (addTexturesSubView())); + setupShortcut("document-assets-textures", textures); assets->addAction (textures); QAction *videos = new QAction (tr ("Videos"), this); connect (videos, SIGNAL (triggered()), this, SLOT (addVideosSubView())); + setupShortcut("document-assets-videos", videos); assets->addAction (videos); } @@ -304,12 +347,16 @@ void CSVDoc::View::setupDebugMenu() QAction *runDebug = debug->addMenu (mGlobalDebugProfileMenu); runDebug->setText (tr ("Run OpenMW")); + setupShortcut("document-debug-run", runDebug); + mStopDebug = new QAction (tr ("Shutdown OpenMW"), this); connect (mStopDebug, SIGNAL (triggered()), this, SLOT (stop())); + setupShortcut("document-debug-shutdown", mStopDebug); debug->addAction (mStopDebug); QAction *runLog = new QAction (tr ("Run Log"), this); connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView())); + setupShortcut("document-debug-runlog", runLog); debug->addAction (runLog); } @@ -325,6 +372,12 @@ void CSVDoc::View::setupUi() setupDebugMenu(); } +void CSVDoc::View::setupShortcut(const char* name, QAction* action) +{ + CSMPrefs::Shortcut* shortcut = new CSMPrefs::Shortcut(name, this); + shortcut->associateAction(action); +} + void CSVDoc::View::updateTitle() { std::ostringstream stream; diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index d95499191..834407be0 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -84,6 +84,8 @@ namespace CSVDoc void setupUi(); + void setupShortcut(const char* name, QAction* action); + void updateActions(); void exitApplication(); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 65c7a89f4..db0637a24 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index b2e988dc9..a2458397f 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -1,7 +1,8 @@ #include "scenetoolbar.hpp" #include -#include + +#include "../../model/prefs/shortcut.hpp" #include "scenetool.hpp" @@ -25,9 +26,8 @@ CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) setLayout (mLayout); - /// \todo make shortcut configurable - QShortcut *focusScene = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); - connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest())); + CSMPrefs::Shortcut* focusSceneShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); + connect(focusSceneShortcut, SIGNAL(activated()), this, SIGNAL(focusSceneRequest())); } void CSVWidget::SceneToolbar::addTool (SceneTool *tool, SceneTool *insertPoint) From 3f7f75cc9d74103732cfd7dd00678c2a9ffce20a Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 00:44:34 -0400 Subject: [PATCH 30/46] Exclude keys not compatible with qt 4 --- apps/opencs/model/prefs/shortcutmanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 4d283f93f..e259398b5 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -598,6 +598,7 @@ namespace CSMPrefs std::make_pair((int)Qt::Key_ContrastAdjust , "ContrastAdjust"), std::make_pair((int)Qt::Key_LaunchG , "LaunchG"), std::make_pair((int)Qt::Key_LaunchH , "LaunchH"), +#if QT_VERSION >= QT_VERSION_CHECK(5,7,0) std::make_pair((int)Qt::Key_TouchpadToggle , "TouchpadToggle"), std::make_pair((int)Qt::Key_TouchpadOn , "TouchpadOn"), std::make_pair((int)Qt::Key_TouchpadOff , "TouchpadOff"), @@ -618,6 +619,7 @@ namespace CSMPrefs std::make_pair((int)Qt::Key_Find , "Find"), std::make_pair((int)Qt::Key_Undo , "Undo"), std::make_pair((int)Qt::Key_Redo , "Redo"), +#endif std::make_pair((int)Qt::Key_AltGr , "AltGr"), std::make_pair((int)Qt::Key_Multi_key , "Multi_key"), std::make_pair((int)Qt::Key_Kanji , "Kanji"), @@ -681,7 +683,9 @@ namespace CSMPrefs std::make_pair((int)Qt::Key_Sleep , "Sleep"), std::make_pair((int)Qt::Key_Play , "Play"), std::make_pair((int)Qt::Key_Zoom , "Zoom"), +#if QT_VERSION >= QT_VERSION_CHECK(5,7,0) std::make_pair((int)Qt::Key_Exit , "Exit"), +#endif std::make_pair((int)Qt::Key_Context1 , "Context1"), std::make_pair((int)Qt::Key_Context2 , "Context2"), std::make_pair((int)Qt::Key_Context3 , "Context3"), From b204758be17547c6197ef9b3f3a02dd9f1ea8eb0 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 01:53:21 -0400 Subject: [PATCH 31/46] More shortcuts. --- apps/opencs/model/prefs/shortcutsetting.cpp | 2 +- apps/opencs/model/prefs/state.cpp | 19 ++++++++++++++++ apps/opencs/view/tools/reporttable.cpp | 9 ++++++++ apps/opencs/view/world/nestedtable.cpp | 8 +++++-- apps/opencs/view/world/table.cpp | 24 +++++++++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index cd2c1fcf5..211aead55 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -93,7 +93,7 @@ namespace CSMPrefs const int MaxKeys = 4; // A limitation of QKeySequence // Modifiers are handled differently - const int Blacklist[] + const int Blacklist[] = { Qt::Key_Shift, Qt::Key_Control, diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 4b5ddffd1..89491e8dc 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -268,6 +268,25 @@ void CSMPrefs::State::declare() declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence()); declareShortcut ("document-debug-runlog", "Run Log", QKeySequence()); + declareSeparator (); + declareShortcut ("table-edit", "Edit record", QKeySequence()); + declareShortcut ("table-add", "Add row/record", QKeySequence(Qt::ControlModifier | Qt::Key_N)); + declareShortcut ("table-clone", "Clone record", QKeySequence()); + declareShortcut ("table-revert", "Revert record", QKeySequence()); + declareShortcut ("table-remove", "Remove record", QKeySequence(Qt::Key_Delete)); + declareShortcut ("table-moveup", "Move record up", QKeySequence()); + declareShortcut ("table-movedown", "Move record down", QKeySequence()); + declareShortcut ("table-view", "View record", QKeySequence()); + declareShortcut ("table-preview", "Preview record", QKeySequence()); + declareShortcut ("table-extendeddelete", "Extended record deletion", QKeySequence()); + declareShortcut ("table-extendedrevert", "Extended record revertion", QKeySequence()); + + declareSeparator (); + declareShortcut ("reporttable-show", "Show report", QKeySequence()); + declareShortcut ("reporttable-remove", "Remove report", QKeySequence(Qt::Key_Delete)); + declareShortcut ("reporttable-replace", "Replace report", QKeySequence()); + declareShortcut ("reporttable-refresh", "Refresh report", QKeySequence()); + declareSeparator (); declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index bfc002933..58feda7c9 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -15,6 +15,7 @@ #include "../../model/tools/reportmodel.hpp" #include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcut.hpp" #include "../../view/world/idtypedelegate.hpp" @@ -171,14 +172,20 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mShowAction = new QAction (tr ("Show"), this); connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); + CSMPrefs::Shortcut* showShortcut = new CSMPrefs::Shortcut("reporttable-show", this); + showShortcut->associateAction(mShowAction); mRemoveAction = new QAction (tr ("Remove from list"), this); connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection())); addAction (mRemoveAction); + CSMPrefs::Shortcut* removeShortcut = new CSMPrefs::Shortcut("reporttable-remove", this); + removeShortcut->associateAction(mRemoveAction); mReplaceAction = new QAction (tr ("Replace"), this); connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); addAction (mReplaceAction); + CSMPrefs::Shortcut* replaceShortcut = new CSMPrefs::Shortcut("reporttable-replace", this); + replaceShortcut->associateAction(mReplaceAction); if (mRefreshState) { @@ -186,6 +193,8 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mRefreshAction->setEnabled (!(mDocument.getState() & mRefreshState)); connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest())); addAction (mRefreshAction); + CSMPrefs::Shortcut* refreshShortcut = new CSMPrefs::Shortcut("reporttable-refresh", this); + refreshShortcut->associateAction(mRefreshAction); } mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index d791377b8..02bd93920 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -5,6 +5,8 @@ #include #include +#include "../../model/prefs/shortcut.hpp" + #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/commands.hpp" @@ -60,14 +62,16 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, if (!fixedRows) { mAddNewRowAction = new QAction (tr ("Add new row"), this); - connect(mAddNewRowAction, SIGNAL(triggered()), this, SLOT(addNewRowActionTriggered())); + CSMPrefs::Shortcut* addRowShortcut = new CSMPrefs::Shortcut("table-add", this); + addRowShortcut->associateAction(mAddNewRowAction); mRemoveRowAction = new QAction (tr ("Remove rows"), this); - connect(mRemoveRowAction, SIGNAL(triggered()), this, SLOT(removeRowActionTriggered())); + CSMPrefs::Shortcut* removeRowShortcut = new CSMPrefs::Shortcut("table-remove", this); + removeRowShortcut->associateAction(mRemoveRowAction); } mEditIdAction = new TableEditIdAction(*this, this); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 45e50dba7..07db5b477 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -21,6 +21,7 @@ #include "../../model/world/commanddispatcher.hpp" #include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcut.hpp" #include "tableeditidaction.hpp" #include "util.hpp" @@ -283,49 +284,72 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mEditAction = new QAction (tr ("Edit Record"), this); connect (mEditAction, SIGNAL (triggered()), this, SLOT (editRecord())); addAction (mEditAction); + CSMPrefs::Shortcut* editShortcut = new CSMPrefs::Shortcut("table-edit", this); + editShortcut->associateAction(mEditAction); if (createAndDelete) { mCreateAction = new QAction (tr ("Add Record"), this); connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest())); addAction (mCreateAction); + CSMPrefs::Shortcut* createShortcut = new CSMPrefs::Shortcut("table-add", this); + createShortcut->associateAction(mCreateAction); mCloneAction = new QAction (tr ("Clone Record"), this); connect(mCloneAction, SIGNAL (triggered()), this, SLOT (cloneRecord())); addAction(mCloneAction); + CSMPrefs::Shortcut* cloneShortcut = new CSMPrefs::Shortcut("table-clone", this); + cloneShortcut->associateAction(mCloneAction); } mRevertAction = new QAction (tr ("Revert Record"), this); connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert())); addAction (mRevertAction); + CSMPrefs::Shortcut* revertShortcut = new CSMPrefs::Shortcut("table-revert", this); + revertShortcut->associateAction(mRevertAction); mDeleteAction = new QAction (tr ("Delete Record"), this); connect (mDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeDelete())); addAction (mDeleteAction); + CSMPrefs::Shortcut* deleteShortcut = new CSMPrefs::Shortcut("table-remove", this); + deleteShortcut->associateAction(mDeleteAction); + mMoveUpAction = new QAction (tr ("Move Up"), this); connect (mMoveUpAction, SIGNAL (triggered()), this, SLOT (moveUpRecord())); addAction (mMoveUpAction); + CSMPrefs::Shortcut* moveUpShortcut = new CSMPrefs::Shortcut("table-moveup", this); + moveUpShortcut->associateAction(mMoveUpAction); mMoveDownAction = new QAction (tr ("Move Down"), this); connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord())); addAction (mMoveDownAction); + CSMPrefs::Shortcut* moveDownShortcut = new CSMPrefs::Shortcut("table-movedown", this); + moveDownShortcut->associateAction(mMoveDownAction); mViewAction = new QAction (tr ("View"), this); connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord())); addAction (mViewAction); + CSMPrefs::Shortcut* viewShortcut = new CSMPrefs::Shortcut("table-view", this); + viewShortcut->associateAction(mViewAction); mPreviewAction = new QAction (tr ("Preview"), this); connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord())); addAction (mPreviewAction); + CSMPrefs::Shortcut* previewShortcut = new CSMPrefs::Shortcut("table-preview", this); + previewShortcut->associateAction(mPreviewAction); mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this); connect (mExtendedDeleteAction, SIGNAL (triggered()), this, SLOT (executeExtendedDelete())); addAction (mExtendedDeleteAction); + CSMPrefs::Shortcut* extendedDeleteShortcut = new CSMPrefs::Shortcut("table-extendeddelete", this); + extendedDeleteShortcut->associateAction(mExtendedDeleteAction); mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this); connect (mExtendedRevertAction, SIGNAL (triggered()), this, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); + CSMPrefs::Shortcut* extendedRevertShortcut = new CSMPrefs::Shortcut("table-extendedrevert", this); + extendedRevertShortcut->associateAction(mExtendedRevertAction); mEditIdAction = new TableEditIdAction (*this, this); connect (mEditIdAction, SIGNAL (triggered()), this, SLOT (editCell())); From 12db6d21145b955a7f3c35f8f0eaefb689668daf Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 13:53:33 -0400 Subject: [PATCH 32/46] Add modifier setting. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/modifiersetting.cpp | 125 ++++++++++++++++++++ apps/opencs/model/prefs/modifiersetting.hpp | 41 +++++++ apps/opencs/model/prefs/shortcutsetting.cpp | 9 +- apps/opencs/model/prefs/shortcutsetting.hpp | 4 +- apps/opencs/model/prefs/state.cpp | 17 ++- apps/opencs/model/prefs/state.hpp | 3 + 7 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 apps/opencs/model/prefs/modifiersetting.cpp create mode 100644 apps/opencs/model/prefs/modifiersetting.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 266a9c250..be3fa858a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -113,7 +113,7 @@ opencs_units (view/prefs opencs_units (model/prefs state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut - shortcuteventhandler shortcutmanager shortcutsetting + shortcuteventhandler shortcutmanager shortcutsetting modifiersetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/modifiersetting.cpp b/apps/opencs/model/prefs/modifiersetting.cpp new file mode 100644 index 000000000..73c8343a3 --- /dev/null +++ b/apps/opencs/model/prefs/modifiersetting.cpp @@ -0,0 +1,125 @@ +#include "modifiersetting.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "state.hpp" +#include "shortcutmanager.hpp" + +namespace CSMPrefs +{ + ModifierSetting::ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, + const std::string& label) + : Setting(parent, values, mutex, key, label) + , mEditorActive(false) + { + } + + std::pair ModifierSetting::makeWidgets(QWidget* parent) + { + QKeySequence sequence; + int modifier = 0; + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); + + QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent); + QPushButton* widget = new QPushButton(text, parent); + + widget->setCheckable(true); + widget->installEventFilter(this); + mButton = widget; + + connect(widget, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool))); + + return std::make_pair(label, widget); + } + + bool ModifierSetting::eventFilter(QObject* target, QEvent* event) + { + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->isAutoRepeat()) + return true; + + int mod = keyEvent->modifiers(); + int key = keyEvent->key(); + + return handleEvent(target, mod, key); + } + else if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* mouseEvent = static_cast(event); + int mod = mouseEvent->modifiers(); + int button = mouseEvent->button(); + + return handleEvent(target, mod, button); + } + + return false; + } + + bool ModifierSetting::handleEvent(QObject* target, int mod, int value) + { + // For potential future exceptions + const int Blacklist[] = + { + 0 + }; + + const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int); + + if (!mEditorActive) + return false; + + // Handle blacklist + for (size_t i = 0; i < BlacklistSize; ++i) + { + if (value == Blacklist[i]) + return true; + } + + + // Update modifier + QKeySequence sequence; + int modifier = 0; + + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + modifier = value; + State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + + // Store + { + std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), value); + } + + getParent()->getState()->update(*this); + + // Update button + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); + + mButton->setText(text); + mButton->setChecked(false); + mEditorActive = false; + + return true; + } + + void ModifierSetting::buttonToggled(bool checked) + { + if (checked) + mButton->setText("Press keys or click here..."); + + mEditorActive = checked; + } +} diff --git a/apps/opencs/model/prefs/modifiersetting.hpp b/apps/opencs/model/prefs/modifiersetting.hpp new file mode 100644 index 000000000..b1394b6ea --- /dev/null +++ b/apps/opencs/model/prefs/modifiersetting.hpp @@ -0,0 +1,41 @@ +#ifndef CSM_PREFS_MODIFIERSETTING_H +#define CSM_PREFS_MODIFIERSETTING_H + +#include + +#include "setting.hpp" + +class QEvent; +class QPushButton; + +namespace CSMPrefs +{ + class ModifierSetting : public Setting + { + Q_OBJECT + + public: + + ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, + const std::string& label); + + virtual std::pair makeWidgets(QWidget* parent); + + protected: + + bool eventFilter(QObject* target, QEvent* event); + + private: + + bool handleEvent(QObject* target, int mod, int value); + + QPushButton* mButton; + bool mEditorActive; + + private slots: + + void buttonToggled(bool checked); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 211aead55..07f9c8052 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -14,9 +14,8 @@ namespace CSMPrefs { ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, - const std::string& label, const QKeySequence& default_) + const std::string& label) : Setting(parent, values, mutex, key, label) - , mDefault(default_) , mEditorActive(false) , mEditorPos(0) { @@ -30,7 +29,11 @@ namespace CSMPrefs std::pair ShortcutSetting::makeWidgets(QWidget* parent) { - QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(mDefault).c_str()); + QKeySequence sequence; + int modifier = 0; + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent); QPushButton* widget = new QPushButton(text, parent); diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp index 2a86e68dd..0521e2291 100644 --- a/apps/opencs/model/prefs/shortcutsetting.hpp +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -17,7 +17,7 @@ namespace CSMPrefs public: ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, - const std::string& label, const QKeySequence& default_); + const std::string& label); virtual std::pair makeWidgets(QWidget* parent); @@ -29,8 +29,6 @@ namespace CSMPrefs bool handleEvent(QObject* target, int mod, int value, bool active); - QKeySequence mDefault; - QPushButton* mButton; bool mEditorActive; diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 89491e8dc..8c5005156 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -12,6 +12,7 @@ #include "boolsetting.hpp" #include "coloursetting.hpp" #include "shortcutsetting.hpp" +#include "modifiersetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -292,6 +293,7 @@ void CSMPrefs::State::declare() declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); declareShortcut ("free-left", "Free camera left", QKeySequence(Qt::Key_A)); declareShortcut ("free-right", "Free camera right", QKeySequence(Qt::Key_D)); + declareModifier ("free-forward", "Free camera speed modifier"); declareShortcut ("free-roll-left", "Free camera roll left", QKeySequence(Qt::Key_Q)); declareShortcut ("free-roll-right", "Free camera roll right", QKeySequence(Qt::Key_E)); declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); @@ -301,6 +303,7 @@ void CSMPrefs::State::declare() declareShortcut ("orbit-down", "Orbit camera down", QKeySequence(Qt::Key_S)); declareShortcut ("orbit-left", "Orbit camera left", QKeySequence(Qt::Key_A)); declareShortcut ("orbit-right", "Orbit camera right", QKeySequence(Qt::Key_D)); + declareModifier ("orbit-up", "Orbit camera speed modifier"); declareShortcut ("orbit-roll-left", "Orbit camera roll left", QKeySequence(Qt::Key_Q)); declareShortcut ("orbit-roll-right", "Orbit camera roll right", QKeySequence(Qt::Key_E)); declareShortcut ("orbit-speed-mode", "Orbit camera speed mode toggle", QKeySequence(Qt::Key_F)); @@ -452,7 +455,19 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& getShortcutManager().setSequence(key, sequence, mod); CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, - key, label, sequence); + key, label); + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + +CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + CSMPrefs::ModifierSetting *setting = new CSMPrefs::ModifierSetting (&mCurrentCategory->second, &mSettings, &mMutex, + key, label); mCurrentCategory->second.addSetting (setting); return *setting; diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 23d9df387..d65dc7d00 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -27,6 +27,7 @@ namespace CSMPrefs class BoolSetting; class ColourSetting; class ShortcutSetting; + class ModifierSetting; /// \brief User settings state /// @@ -77,6 +78,8 @@ namespace CSMPrefs ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, const QKeySequence& default_, int modifier_=0); + ModifierSetting& declareModifier(const std::string& key, const std::string& label); + void declareSeparator(); void setDefault (const std::string& key, const std::string& default_); From b685c0ce6c2de36608850a756237ea696da63069 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 14:07:53 -0400 Subject: [PATCH 33/46] Add ability to clear shortcut/modifier setting with right click. --- apps/opencs/model/prefs/modifiersetting.cpp | 25 +++++++++++++++++++++ apps/opencs/model/prefs/shortcutsetting.cpp | 25 +++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/apps/opencs/model/prefs/modifiersetting.cpp b/apps/opencs/model/prefs/modifiersetting.cpp index 73c8343a3..12a4b5d80 100644 --- a/apps/opencs/model/prefs/modifiersetting.cpp +++ b/apps/opencs/model/prefs/modifiersetting.cpp @@ -76,7 +76,32 @@ namespace CSMPrefs const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int); if (!mEditorActive) + { + if (value == Qt::RightButton) + { + // Clear modifier + QKeySequence sequence; + int modifier = 0; + + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + modifier = 0; + State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + + // Store + { + std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), value); + } + + // Update button + mButton->setText(""); + } + return false; + } // Handle blacklist for (size_t i = 0; i < BlacklistSize; ++i) diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 07f9c8052..c98384695 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -108,7 +108,32 @@ namespace CSMPrefs const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int); if (!mEditorActive) + { + if (value == Qt::RightButton && !active) + { + // Clear sequence + QKeySequence sequence; + int modifier = 0; + + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + sequence = QKeySequence(0, 0, 0, 0); + State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + + // Store + { + std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), value); + } + + // Update button + mButton->setText(""); + } + return false; + } // Handle blacklist for (size_t i = 0; i < BlacklistSize; ++i) From 65201badf66540e6a10001e42d7abff471cc775f Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 19:15:24 -0400 Subject: [PATCH 34/46] Add custom page for key bindings. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/state.cpp | 76 +++++++++++-------- apps/opencs/model/prefs/state.hpp | 2 + apps/opencs/view/prefs/dialogue.cpp | 7 +- apps/opencs/view/prefs/keybindingpage.cpp | 89 +++++++++++++++++++++++ apps/opencs/view/prefs/keybindingpage.hpp | 35 +++++++++ 6 files changed, 176 insertions(+), 35 deletions(-) create mode 100644 apps/opencs/view/prefs/keybindingpage.cpp create mode 100644 apps/opencs/view/prefs/keybindingpage.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index be3fa858a..6e19c03b2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (view/tools ) opencs_units (view/prefs - dialogue pagebase page + dialogue pagebase page keybindingpage ) opencs_units (model/prefs diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 8c5005156..0b0f9d700 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -217,6 +217,7 @@ void CSMPrefs::State::declare() declareCategory ("Key Bindings"); + declareSubcategory ("Document"); declareShortcut ("document-file-newgame", "Create new game", QKeySequence()); declareShortcut ("document-file-newaddon", "Create new addon", QKeySequence()); declareShortcut ("document-file-open", "Open", QKeySequence()); @@ -269,12 +270,12 @@ void CSMPrefs::State::declare() declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence()); declareShortcut ("document-debug-runlog", "Run Log", QKeySequence()); - declareSeparator (); + declareSubcategory ("Table"); declareShortcut ("table-edit", "Edit record", QKeySequence()); declareShortcut ("table-add", "Add row/record", QKeySequence(Qt::ControlModifier | Qt::Key_N)); declareShortcut ("table-clone", "Clone record", QKeySequence()); declareShortcut ("table-revert", "Revert record", QKeySequence()); - declareShortcut ("table-remove", "Remove record", QKeySequence(Qt::Key_Delete)); + declareShortcut ("table-remove", "Remove row/record", QKeySequence(Qt::Key_Delete)); declareShortcut ("table-moveup", "Move record up", QKeySequence()); declareShortcut ("table-movedown", "Move record down", QKeySequence()); declareShortcut ("table-view", "View record", QKeySequence()); @@ -282,46 +283,46 @@ void CSMPrefs::State::declare() declareShortcut ("table-extendeddelete", "Extended record deletion", QKeySequence()); declareShortcut ("table-extendedrevert", "Extended record revertion", QKeySequence()); - declareSeparator (); + declareSubcategory ("Report Table"); declareShortcut ("reporttable-show", "Show report", QKeySequence()); declareShortcut ("reporttable-remove", "Remove report", QKeySequence(Qt::Key_Delete)); declareShortcut ("reporttable-replace", "Replace report", QKeySequence()); declareShortcut ("reporttable-refresh", "Refresh report", QKeySequence()); - declareSeparator (); - declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); - declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); - declareShortcut ("free-left", "Free camera left", QKeySequence(Qt::Key_A)); - declareShortcut ("free-right", "Free camera right", QKeySequence(Qt::Key_D)); - declareModifier ("free-forward", "Free camera speed modifier"); - declareShortcut ("free-roll-left", "Free camera roll left", QKeySequence(Qt::Key_Q)); - declareShortcut ("free-roll-right", "Free camera roll right", QKeySequence(Qt::Key_E)); - declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); - - declareSeparator (); - declareShortcut ("orbit-up", "Orbit camera up", QKeySequence(Qt::Key_W), Qt::Key_Shift); - declareShortcut ("orbit-down", "Orbit camera down", QKeySequence(Qt::Key_S)); - declareShortcut ("orbit-left", "Orbit camera left", QKeySequence(Qt::Key_A)); - declareShortcut ("orbit-right", "Orbit camera right", QKeySequence(Qt::Key_D)); - declareModifier ("orbit-up", "Orbit camera speed modifier"); - declareShortcut ("orbit-roll-left", "Orbit camera roll left", QKeySequence(Qt::Key_Q)); - declareShortcut ("orbit-roll-right", "Orbit camera roll right", QKeySequence(Qt::Key_E)); - declareShortcut ("orbit-speed-mode", "Orbit camera speed mode toggle", QKeySequence(Qt::Key_F)); - declareShortcut ("orbit-center-selection", "Centers the camera on the selected item", QKeySequence(Qt::Key_C)); - - declareSeparator (); + declareSubcategory ("1st/Free Camera"); + declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); + declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S)); + declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A)); + declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D)); + declareModifier ("free-forward", "Speed modifier"); + declareShortcut ("free-roll-left", "Roll left", QKeySequence(Qt::Key_Q)); + declareShortcut ("free-roll-right", "Roll right", QKeySequence(Qt::Key_E)); + declareShortcut ("free-speed-mode", "Speed mode toggle", QKeySequence(Qt::Key_F)); + + declareSubcategory ("Orbit Camera"); + declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W), Qt::Key_Shift); + declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S)); + declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A)); + declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D)); + declareModifier ("orbit-up", "Speed modifier"); + declareShortcut ("orbit-roll-left", "Roll left", QKeySequence(Qt::Key_Q)); + declareShortcut ("orbit-roll-right", "Roll right", QKeySequence(Qt::Key_E)); + declareShortcut ("orbit-speed-mode", "Speed mode toggle", QKeySequence(Qt::Key_F)); + declareShortcut ("orbit-center-selection", "Center on selected", QKeySequence(Qt::Key_C)); + + declareSubcategory ("Scene"); declareShortcut ("scene-navi-primary", "Camera rotation from mouse movement", QKeySequence(Qt::LeftButton)); declareShortcut ("scene-navi-secondary", "Camera translation from mouse movement", QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); - declareShortcut ("scene-edit-primary", "Scene primary edit button", QKeySequence(Qt::RightButton)); - declareShortcut ("scene-edit-secondary", "Scene secondary edit button", + declareShortcut ("scene-edit-primary", "Primary edit", QKeySequence(Qt::RightButton)); + declareShortcut ("scene-edit-secondary", "Secondary edit", QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); - declareShortcut ("scene-select-primary", "Scene primary select button", QKeySequence(Qt::MiddleButton)); - declareShortcut ("scene-select-secondary", "Scene secondary select button", + declareShortcut ("scene-select-primary", "Primary select", QKeySequence(Qt::MiddleButton)); + declareShortcut ("scene-select-secondary", "Secondary select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); - declareShortcut ("scene-edit-abort", "Scene editor abort key", QKeySequence(Qt::Key_Escape)); - declareShortcut ("scene-focus-toolbar", "Change focus in scene editor", QKeySequence(Qt::Key_T)); - declareShortcut ("scene-render-stats", "Displays debug rendering stats", QKeySequence(Qt::Key_F3)); + declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); + declareShortcut ("scene-focus-toolbar", "Toggle toolbar focus", QKeySequence(Qt::Key_T)); + declareShortcut ("scene-render-stats", "Debug rendering stats", QKeySequence(Qt::Key_F3)); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -484,6 +485,17 @@ void CSMPrefs::State::declareSeparator() mCurrentCategory->second.addSetting (setting); } +void CSMPrefs::State::declareSubcategory(const std::string& label) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + CSMPrefs::Setting *setting = + new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", label); + + mCurrentCategory->second.addSetting (setting); +} + void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_) { Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index d65dc7d00..64927f881 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -82,6 +82,8 @@ namespace CSMPrefs void declareSeparator(); + void declareSubcategory(const std::string& label); + void setDefault (const std::string& key, const std::string& default_); public: diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index f04092653..6848bcaba 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -11,6 +11,7 @@ #include "../../model/prefs/state.hpp" #include "page.hpp" +#include "keybindingpage.hpp" void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) { @@ -52,8 +53,10 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main) CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key) { // special case page code goes here - - return new Page (CSMPrefs::get()[key], mContent); + if (key == "Key Bindings") + return new KeyBindingPage(CSMPrefs::get()[key], mContent); + else + return new Page (CSMPrefs::get()[key], mContent); } CSVPrefs::Dialogue::Dialogue() diff --git a/apps/opencs/view/prefs/keybindingpage.cpp b/apps/opencs/view/prefs/keybindingpage.cpp new file mode 100644 index 000000000..63b196831 --- /dev/null +++ b/apps/opencs/view/prefs/keybindingpage.cpp @@ -0,0 +1,89 @@ +#include "keybindingpage.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "../../model/prefs/setting.hpp" +#include "../../model/prefs/category.hpp" + +namespace CSVPrefs +{ + KeyBindingPage::KeyBindingPage(CSMPrefs::Category& category, QWidget* parent) + : PageBase(category, parent) + , mStackedLayout(0) + , mPageLayout(0) + , mPageSelector(0) + { + // Need one widget for scroll area + QWidget* topWidget = new QWidget(); + QVBoxLayout* topLayout = new QVBoxLayout(topWidget); + + // Allows switching between "pages" + QWidget* stackedWidget = new QWidget(); + mStackedLayout = new QStackedLayout(stackedWidget); + + mPageSelector = new QComboBox(); + connect(mPageSelector, SIGNAL(currentIndexChanged(int)), mStackedLayout, SLOT(setCurrentIndex(int))); + + topLayout->addWidget(mPageSelector); + topLayout->addWidget(stackedWidget); + topLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + + // Add each option + for (CSMPrefs::Category::Iterator iter = category.begin(); iter!=category.end(); ++iter) + addSetting (*iter); + + setWidgetResizable(true); + setWidget(topWidget); + } + + void KeyBindingPage::addSetting(CSMPrefs::Setting *setting) + { + std::pair widgets = setting->makeWidgets (this); + + if (widgets.first) + { + // Label, Option widgets + assert(mPageLayout); + + int next = mPageLayout->rowCount(); + mPageLayout->addWidget(widgets.first, next, 0); + mPageLayout->addWidget(widgets.second, next, 1); + } + else if (widgets.second) + { + // Wide single widget + assert(mPageLayout); + + int next = mPageLayout->rowCount(); + mPageLayout->addWidget(widgets.second, next, 0, 1, 2); + } + else + { + if (setting->getLabel().empty()) + { + // Insert empty space + assert(mPageLayout); + + int next = mPageLayout->rowCount(); + mPageLayout->addWidget(new QWidget(), next, 0); + } + else + { + // Create new page + QWidget* pageWidget = new QWidget(); + mPageLayout = new QGridLayout(pageWidget); + mPageLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + + mStackedLayout->addWidget(pageWidget); + + mPageSelector->addItem(QString::fromUtf8(setting->getLabel().c_str())); + } + } + } +} diff --git a/apps/opencs/view/prefs/keybindingpage.hpp b/apps/opencs/view/prefs/keybindingpage.hpp new file mode 100644 index 000000000..8a0cb2952 --- /dev/null +++ b/apps/opencs/view/prefs/keybindingpage.hpp @@ -0,0 +1,35 @@ +#ifndef CSV_PREFS_KEYBINDINGPAGE_H +#define CSV_PREFS_KEYBINDINGPAGE_H + +#include "pagebase.hpp" + +class QComboBox; +class QGridLayout; +class QStackedLayout; + +namespace CSMPrefs +{ + class Setting; +} + +namespace CSVPrefs +{ + class KeyBindingPage : public PageBase + { + Q_OBJECT + + public: + + KeyBindingPage(CSMPrefs::Category& category, QWidget* parent); + + void addSetting(CSMPrefs::Setting* setting); + + private: + + QStackedLayout* mStackedLayout; + QGridLayout* mPageLayout; + QComboBox* mPageSelector; + }; +} + +#endif From 96a3c278fdecf43d56535c126f7c82b3cd7595ce Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Wed, 27 Jul 2016 21:40:53 -0400 Subject: [PATCH 35/46] Added shortcuts for loading a cell relative to the camera, Removed Ctl+V binding for "Verify" because that is associated with paste. --- apps/opencs/model/prefs/state.cpp | 7 ++- .../view/render/pagedworldspacewidget.cpp | 61 +++++++++++++++++++ .../view/render/pagedworldspacewidget.hpp | 12 ++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 0b0f9d700..1813bf4db 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -222,7 +222,7 @@ void CSMPrefs::State::declare() declareShortcut ("document-file-newaddon", "Create new addon", QKeySequence()); declareShortcut ("document-file-open", "Open", QKeySequence()); declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); - declareShortcut ("document-file-verify", "Verify", QKeySequence(Qt::ControlModifier | Qt::Key_V)); + declareShortcut ("document-file-verify", "Verify", QKeySequence()); declareShortcut ("document-file-merge", "Merge", QKeySequence()); declareShortcut ("document-file-errorlog", "Load error log", QKeySequence()); declareShortcut ("document-file-metadata", "Meta Data", QKeySequence()); @@ -320,6 +320,11 @@ void CSMPrefs::State::declare() declareShortcut ("scene-select-primary", "Primary select", QKeySequence(Qt::MiddleButton)); declareShortcut ("scene-select-secondary", "Secondary select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); + declareShortcut ("scene-load-cam-cell", "Load camera cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); + declareShortcut ("scene-load-cam-eastcell", "Load east cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); + declareShortcut ("scene-load-cam-northcell", "Load north cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); + declareShortcut ("scene-load-cam-westcell", "Load west cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4)); + declareShortcut ("scene-load-cam-southcell", "Load south cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2)); declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); declareShortcut ("scene-focus-toolbar", "Toggle toolbar focus", QKeySequence(Qt::Key_T)); declareShortcut ("scene-render-stats", "Debug rendering stats", QKeySequence(Qt::Key_F3)); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 397b86f0d..786beb530 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -8,6 +8,8 @@ #include +#include "../../model/prefs/shortcut.hpp" + #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" @@ -433,6 +435,24 @@ void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y) mSelection = newSelection; } +void CSVRender::PagedWorldspaceWidget::addCellToSceneFromCamera (int offsetX, int offsetY) +{ + const int CellSize = 8192; + + osg::Vec3f eye, center, up; + getCamera()->getViewMatrixAsLookAt(eye, center, up); + + int cellX = (int)std::floor(center.x() / CellSize) + offsetX; + int cellY = (int)std::floor(center.y() / CellSize) + offsetY; + + CSMWorld::CellCoordinates cellCoordinates(cellX, cellY); + + if (mCells.find(cellCoordinates) == mCells.end()) + { + addCellToScene(cellCoordinates); + } +} + CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true) @@ -446,6 +466,22 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc this, SLOT (cellRemoved (const QModelIndex&, int, int))); connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); + + // Shortcuts + CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this); + connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell())); + + CSMPrefs::Shortcut* loadCameraEastCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-eastcell", this); + connect(loadCameraEastCellShortcut, SIGNAL(activated()), this, SLOT(loadEastCell())); + + CSMPrefs::Shortcut* loadCameraNorthCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-northcell", this); + connect(loadCameraNorthCellShortcut, SIGNAL(activated()), this, SLOT(loadNorthCell())); + + CSMPrefs::Shortcut* loadCameraWestCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-westcell", this); + connect(loadCameraWestCellShortcut, SIGNAL(activated()), this, SLOT(loadWestCell())); + + CSMPrefs::Shortcut* loadCameraSouthCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-southcell", this); + connect(loadCameraSouthCellShortcut, SIGNAL(activated()), this, SLOT(loadSouthCell())); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -718,3 +754,28 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int if (adjustCells()) flagAsModified(); } + +void CSVRender::PagedWorldspaceWidget::loadCameraCell() +{ + addCellToSceneFromCamera(0, 0); +} + +void CSVRender::PagedWorldspaceWidget::loadEastCell() +{ + addCellToSceneFromCamera(1, 0); +} + +void CSVRender::PagedWorldspaceWidget::loadNorthCell() +{ + addCellToSceneFromCamera(0, 1); +} + +void CSVRender::PagedWorldspaceWidget::loadWestCell() +{ + addCellToSceneFromCamera(-1, 0); +} + +void CSVRender::PagedWorldspaceWidget::loadSouthCell() +{ + addCellToSceneFromCamera(0, -1); +} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 462580d49..b963c6144 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -74,6 +74,8 @@ namespace CSVRender /// \note Does not update the view or any cell marker void moveCellSelection (int x, int y); + void addCellToSceneFromCamera (int offsetX, int offsetY); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -152,6 +154,16 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + void loadCameraCell(); + + void loadEastCell(); + + void loadNorthCell(); + + void loadWestCell(); + + void loadSouthCell(); + }; } From 7f0d5bde2d42b1a45e89b88ac08ebf77b3b4d7eb Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 7 Jul 2016 17:27:08 +0200 Subject: [PATCH 36/46] make conf.py independant from cmake macros merged openmw-cs in, using per directory statics add requirements.txt for sphinx docs it is breath update gitignore and openmw-cs --- .gitignore | 17 +- CMakeLists.txt | 12 +- docs/CMakeLists.txt | 27 -- docs/cs-manual/Makefile | 216 ----------- docs/cs-manual/make.bat | 263 ------------- docs/cs-manual/source/conf.py | 358 ------------------ docs/requirements.txt | 3 + .../source/conf.py.in => source/conf.py} | 19 +- docs/{sphinx => }/source/index.rst | 7 +- .../_static/images/chapter-1/add-record.png | Bin .../_static/images/chapter-1/edit-record.png | Bin .../_static/images/chapter-1/new-project.png | Bin .../_static/images/chapter-1/objects.png | Bin .../images/chapter-1/opening-dialogue.png | Bin .../openmw-cs}/files-and-directories.rst | 0 .../source => source/openmw-cs}/foreword.rst | 0 .../source => source/openmw-cs}/index.rst | 5 - .../openmw-cs}/starting-dialog.rst | 0 .../source => source/openmw-cs}/tour.rst | 10 +- .../openmw.rst => source/openmw/index.rst} | 5 +- .../source => source/openmw}/mwbase.rst | 5 +- docs/sphinx/run_sphinx_build.sh.in | 7 - 22 files changed, 46 insertions(+), 908 deletions(-) delete mode 100644 docs/CMakeLists.txt delete mode 100644 docs/cs-manual/Makefile delete mode 100644 docs/cs-manual/make.bat delete mode 100644 docs/cs-manual/source/conf.py create mode 100644 docs/requirements.txt rename docs/{sphinx/source/conf.py.in => source/conf.py} (94%) rename docs/{sphinx => }/source/index.rst (77%) rename docs/{cs-manual/source => source/openmw-cs}/_static/images/chapter-1/add-record.png (100%) rename docs/{cs-manual/source => source/openmw-cs}/_static/images/chapter-1/edit-record.png (100%) rename docs/{cs-manual/source => source/openmw-cs}/_static/images/chapter-1/new-project.png (100%) rename docs/{cs-manual/source => source/openmw-cs}/_static/images/chapter-1/objects.png (100%) rename docs/{cs-manual/source => source/openmw-cs}/_static/images/chapter-1/opening-dialogue.png (100%) rename docs/{cs-manual/source => source/openmw-cs}/files-and-directories.rst (100%) rename docs/{cs-manual/source => source/openmw-cs}/foreword.rst (100%) rename docs/{cs-manual/source => source/openmw-cs}/index.rst (78%) rename docs/{cs-manual/source => source/openmw-cs}/starting-dialog.rst (100%) rename docs/{cs-manual/source => source/openmw-cs}/tour.rst (97%) rename docs/{sphinx/source/openmw.rst => source/openmw/index.rst} (59%) rename docs/{sphinx/source => source/openmw}/mwbase.rst (95%) delete mode 100644 docs/sphinx/run_sphinx_build.sh.in diff --git a/.gitignore b/.gitignore index b68d13cde..9a24b0107 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ prebuilt ## doxygen Doxygen -!docs/cs-manual/Makefile ## ides/editors *~ @@ -35,17 +34,15 @@ resources ## binaries /esmtool -/mwiniimport -/omwlauncher /openmw /opencs /niftest -bsatool -openmw-cs -openmw-essimporter -openmw-iniimporter -openmw-launcher -openmw-wizard +/bsatool +/openmw-cs +/openmw-essimporter +/openmw-iniimporter +/openmw-launcher +/openmw-wizard ## generated objects apps/openmw/config.hpp @@ -80,4 +77,4 @@ moc_*.cxx *.so gamecontrollerdb.txt openmw.appdata.xml - +venv/ diff --git a/CMakeLists.txt b/CMakeLists.txt index e5ecd1f62..8db1e1aa5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,14 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) +option(BUILD_DOCS "build documentation." OFF ) + +# what is necessary to build documentation +IF( BUILD_DOCS ) + # Builds the documentation. + FIND_PACKAGE( Sphinx REQUIRED ) + FIND_PACKAGE( Doxygen REQUIRED ) +ENDIF() # OS X deployment option(OPENMW_OSX_DEPLOYMENT OFF) @@ -829,7 +837,3 @@ if (DOXYGEN_FOUND) WORKING_DIRECTORY ${OpenMW_BINARY_DIR} COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) endif () - - -OPTION(WANT_DOCS "Build documentation." OFF ) -ADD_SUBDIRECTORY(docs) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt deleted file mode 100644 index c63d6dc18..000000000 --- a/docs/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -IF( WANT_DOCS ) - # Builds the documentation. - FIND_PACKAGE( Sphinx REQUIRED ) - FIND_PACKAGE( Doxygen REQUIRED ) - - SET( SPHINX_SOURCE_DIR ${CMAKE_SOURCE_DIR}/docs/sphinx ) - SET( DOCUMENTATION_DIR ${OpenMW_BINARY_DIR}/docs ) - - FILE(MAKE_DIRECTORY ${DOCUMENTATION_DIR}/_static) - FILE(MAKE_DIRECTORY ${DOCUMENTATION_DIR}/_templates) - - CONFIGURE_FILE( - ${SPHINX_SOURCE_DIR}/source/conf.py.in - ${DOCUMENTATION_DIR}/conf.py - @ONLY) - - CONFIGURE_FILE( - ${SPHINX_SOURCE_DIR}/run_sphinx_build.sh.in - ${DOCUMENTATION_DIR}/run_sphinx_build.sh - @ONLY) - - IF(UNIX) - EXECUTE_PROCESS(COMMAND chmod +x ${DOCUMENTATION_DIR}/run_sphinx_build.sh OUTPUT_QUIET) - EXECUTE_PROCESS(COMMAND ${DOCUMENTATION_DIR}/run_sphinx_build.sh OUTPUT_QUIET) - ENDIF(UNIX) - -ENDIF() diff --git a/docs/cs-manual/Makefile b/docs/cs-manual/Makefile deleted file mode 100644 index 9d62dc5ab..000000000 --- a/docs/cs-manual/Makefile +++ /dev/null @@ -1,216 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -.PHONY: clean -clean: - rm -rf $(BUILDDIR)/* - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenMWCSManual.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenMWCSManual.qhc" - -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenMWCSManual" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenMWCSManual" - @echo "# devhelp" - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -.PHONY: latexpdf -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: latexpdfja -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -.PHONY: info -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -.PHONY: gettext -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/cs-manual/make.bat b/docs/cs-manual/make.bat deleted file mode 100644 index 744d60007..000000000 --- a/docs/cs-manual/make.bat +++ /dev/null @@ -1,263 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -set I18NSPHINXOPTS=%SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - echo. coverage to run coverage check of the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -REM Check if sphinx-build is available and fallback to Python version if any -%SPHINXBUILD% 1>NUL 2>NUL -if errorlevel 9009 goto sphinx_python -goto sphinx_ok - -:sphinx_python - -set SPHINXBUILD=python -m sphinx.__init__ -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -:sphinx_ok - - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenMWCSManual.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenMWCSManual.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ -results in %BUILDDIR%/coverage/python.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/docs/cs-manual/source/conf.py b/docs/cs-manual/source/conf.py deleted file mode 100644 index 28931a4a0..000000000 --- a/docs/cs-manual/source/conf.py +++ /dev/null @@ -1,358 +0,0 @@ -# -*- coding: utf-8 -*- -# -# OpenMW CS Manual documentation build configuration file, created by -# sphinx-quickstart on Fri Feb 5 21:28:27 2016. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'OpenMW CS Manual' -copyright = u'2016, The OpenMW Project' -author = u'HiPhish' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'0.0' -# The full version, including alpha/beta/rc tags. -release = u'0.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Language to be used for generating the HTML full-text search index. -# Sphinx supports the following languages: -# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' -# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' -#html_search_language = 'en' - -# A dictionary with options for the search language support, empty by default. -# Now only 'ja' uses this config value -#html_search_options = {'type': 'default'} - -# The name of a javascript file (relative to the configuration directory) that -# implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'OpenMWCSManualdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', - -# Latex figure (float) alignment -#'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'OpenMWCSManual.tex', u'OpenMW CS Manual Documentation', - u'HiPhish', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'openmwcsmanual', u'OpenMW CS Manual Documentation', - [author], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'OpenMWCSManual', u'OpenMW CS Manual Documentation', - author, 'OpenMWCSManual', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# -- Options for Epub output ---------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project -epub_author = author -epub_publisher = author -epub_copyright = copyright - -# The basename for the epub file. It defaults to the project name. -#epub_basename = project - -# The HTML theme for the epub output. Since the default themes are not -# optimized for small screen space, using the same theme for HTML and epub -# output is usually not wise. This defaults to 'epub', a theme designed to save -# visual space. -#epub_theme = 'epub' - -# The language of the text. It defaults to the language option -# or 'en' if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# A sequence of (type, uri, title) tuples for the guide element of content.opf. -#epub_guide = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files that should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Choose between 'default' and 'includehidden'. -#epub_tocscope = 'default' - -# Fix unsupported image types using the Pillow. -#epub_fix_images = False - -# Scale large images. -#epub_max_image_width = 0 - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#epub_show_urls = 'inline' - -# If false, no index is generated. -#epub_use_index = True - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 000000000..6ee8d6987 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +breathe +parse_cmake +sphinx diff --git a/docs/sphinx/source/conf.py.in b/docs/source/conf.py similarity index 94% rename from docs/sphinx/source/conf.py.in rename to docs/source/conf.py index 218ef8b6d..12c6f91a7 100644 --- a/docs/sphinx/source/conf.py.in +++ b/docs/source/conf.py @@ -18,7 +18,8 @@ import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('@CMAKE_SOURCE_DIR@')) +project_root = os.path.abspath('../../') +sys.path.insert(0, project_root) # -- General configuration ------------------------------------------------ @@ -39,7 +40,7 @@ extensions = [ # Where breathe can find the source files breathe_projects_source = { - "openmw": ("@CMAKE_SOURCE_DIR@/apps/openmw", ["engine.hpp", + "openmw": (project_root+"/apps/openmw", ["engine.hpp", "mwbase/dialoguemanager.hpp", "mwbase/environment.hpp", "mwbase/inputmanager.hpp", "mwbase/journal.hpp", "mwbase/mechanicsmanager.hpp", "mwbase/scriptmanager.hpp", "mwbase/soundmanager.hpp", "mwbase/statemanager.hpp", @@ -62,18 +63,22 @@ master_doc = 'index' project = u'OpenMW' copyright = u'2016, OpenMW Team' + # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '@OPENMW_VERSION@' # The full version, including alpha/beta/rc tags. -release = '@OPENMW_VERSION@' + +from parse_cmake import parsing +cmake_raw = open(project_root+'/CMakeLists.txt', 'r').read() +cmake_data = parsing.parse(cmake_raw) +release = version = int(cmake_data[24][1][1].contents), int(cmake_data[25][1][1].contents), int(cmake_data[26][1][1].contents) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +#language = cpp # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -144,7 +149,9 @@ html_theme = 'default' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ['_static', + 'openmw-cs/_static' + ] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/docs/sphinx/source/index.rst b/docs/source/index.rst similarity index 77% rename from docs/sphinx/source/index.rst rename to docs/source/index.rst index 64c3c9796..32844146c 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/source/index.rst @@ -6,9 +6,10 @@ Components ---------- .. toctree:: - :maxdepth: 2 - - openmw + :maxdepth: 2 + + openmw/index + openmw-cs/index Indices and tables diff --git a/docs/cs-manual/source/_static/images/chapter-1/add-record.png b/docs/source/openmw-cs/_static/images/chapter-1/add-record.png similarity index 100% rename from docs/cs-manual/source/_static/images/chapter-1/add-record.png rename to docs/source/openmw-cs/_static/images/chapter-1/add-record.png diff --git a/docs/cs-manual/source/_static/images/chapter-1/edit-record.png b/docs/source/openmw-cs/_static/images/chapter-1/edit-record.png similarity index 100% rename from docs/cs-manual/source/_static/images/chapter-1/edit-record.png rename to docs/source/openmw-cs/_static/images/chapter-1/edit-record.png diff --git a/docs/cs-manual/source/_static/images/chapter-1/new-project.png b/docs/source/openmw-cs/_static/images/chapter-1/new-project.png similarity index 100% rename from docs/cs-manual/source/_static/images/chapter-1/new-project.png rename to docs/source/openmw-cs/_static/images/chapter-1/new-project.png diff --git a/docs/cs-manual/source/_static/images/chapter-1/objects.png b/docs/source/openmw-cs/_static/images/chapter-1/objects.png similarity index 100% rename from docs/cs-manual/source/_static/images/chapter-1/objects.png rename to docs/source/openmw-cs/_static/images/chapter-1/objects.png diff --git a/docs/cs-manual/source/_static/images/chapter-1/opening-dialogue.png b/docs/source/openmw-cs/_static/images/chapter-1/opening-dialogue.png similarity index 100% rename from docs/cs-manual/source/_static/images/chapter-1/opening-dialogue.png rename to docs/source/openmw-cs/_static/images/chapter-1/opening-dialogue.png diff --git a/docs/cs-manual/source/files-and-directories.rst b/docs/source/openmw-cs/files-and-directories.rst similarity index 100% rename from docs/cs-manual/source/files-and-directories.rst rename to docs/source/openmw-cs/files-and-directories.rst diff --git a/docs/cs-manual/source/foreword.rst b/docs/source/openmw-cs/foreword.rst similarity index 100% rename from docs/cs-manual/source/foreword.rst rename to docs/source/openmw-cs/foreword.rst diff --git a/docs/cs-manual/source/index.rst b/docs/source/openmw-cs/index.rst similarity index 78% rename from docs/cs-manual/source/index.rst rename to docs/source/openmw-cs/index.rst index ce50b8c95..dcd28081a 100644 --- a/docs/cs-manual/source/index.rst +++ b/docs/source/openmw-cs/index.rst @@ -1,8 +1,3 @@ -.. OpenMW CS Manual documentation master file, created by - sphinx-quickstart on Fri Feb 5 21:28:27 2016. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - ##################### OpenMW CS user manual ##################### diff --git a/docs/cs-manual/source/starting-dialog.rst b/docs/source/openmw-cs/starting-dialog.rst similarity index 100% rename from docs/cs-manual/source/starting-dialog.rst rename to docs/source/openmw-cs/starting-dialog.rst diff --git a/docs/cs-manual/source/tour.rst b/docs/source/openmw-cs/tour.rst similarity index 97% rename from docs/cs-manual/source/tour.rst rename to docs/source/openmw-cs/tour.rst index 0e92fe6fa..3ddeac4fa 100644 --- a/docs/cs-manual/source/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -24,7 +24,7 @@ We will start by launching OpenMW CS, the location of the program depends on your operating system. You will be presented with a dialogue with three options: create a new game, create a new addon, edit a content file. -.. figure:: ./_static/images/chapter-1/opening-dialogue.png +.. figure:: _static/images/chapter-1/opening-dialogue.png :alt: Opening dialogue with three option and setting button (the wrench) The first option is for creating an entirely new game, that's not what we want. @@ -37,7 +37,7 @@ optionally a number of other addons we want to depend on. The name of the project is arbitrary, it will be used to identify the addon later in the OpenMW launcher. -.. figure:: ./_static/images/chapter-1/new-project.png +.. figure:: _static/images/chapter-1/new-project.png :alt: Creation dialogue for a new project, pick content modules and name Choose Morrowind as your content file and enter `Ring of Night Vision` as the @@ -47,7 +47,7 @@ to, but for this mod the base game is enough. Once the addon has been created you will be presented with a table. If you see a blank window rather than a table choose *World* → *Objects* from the menu. -.. figure:: ./_static/images/chapter-1/objects.png +.. figure:: _static/images/chapter-1/objects.png :alt: The table showing all objet records in the game. Let's talk about the interface for a second. Every window in OpenMW CS has @@ -83,7 +83,7 @@ We need to enter an *ID* (short for *identifier*) and pick the type. The identifier is a unique name by which the ring can later be identified; I have chosen `ring_night_vision`. For the type choose *Clothing*. -.. figure:: ./_static/images/chapter-1/add-record.png +.. figure:: _static/images/chapter-1/add-record.png :alt: Enter the ID and type of the new ring The table should jump right to our newly created record, if not read further @@ -101,7 +101,7 @@ instead of using the context menu; the default is double-clicking while holding down the shift key. -.. figure:: ./_static/images/chapter-1/edit-record.png +.. figure:: _static/images/chapter-1/edit-record.png :alt: Edit the properties of the record in a separate panel You can set the name, weight and coin value as you like, I chose `Ring of Night diff --git a/docs/sphinx/source/openmw.rst b/docs/source/openmw/index.rst similarity index 59% rename from docs/sphinx/source/openmw.rst rename to docs/source/openmw/index.rst index 2da7caa5f..ce4e42f1f 100644 --- a/docs/sphinx/source/openmw.rst +++ b/docs/source/openmw/index.rst @@ -1,5 +1,6 @@ -openmw -====== +########################### +OpenMW Source Documentation +########################### .. toctree:: :maxdepth: 2 diff --git a/docs/sphinx/source/mwbase.rst b/docs/source/openmw/mwbase.rst similarity index 95% rename from docs/sphinx/source/mwbase.rst rename to docs/source/openmw/mwbase.rst index 4044fbc97..182ed66f6 100644 --- a/docs/sphinx/source/mwbase.rst +++ b/docs/source/openmw/mwbase.rst @@ -1,5 +1,6 @@ -openmw/mwbase -============= +######## +./mwbase +######## .. autodoxygenfile:: mwbase/dialoguemanager.hpp :project: openmw diff --git a/docs/sphinx/run_sphinx_build.sh.in b/docs/sphinx/run_sphinx_build.sh.in deleted file mode 100644 index ddd4dc2bb..000000000 --- a/docs/sphinx/run_sphinx_build.sh.in +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -echo "Creating Sphinx documentation in: @SPHINX_DESTINATION@" - -LD_LIBRARY_PATH="@CMAKE_INSTALL_PREFIX@/lib:$LD_LIBRARY_PATH" - -@SPHINX_EXECUTABLE@ -b html -c @CMAKE_CURRENT_BINARY_DIR@/ @SPHINX_SOURCE_DIR@/source @DOCUMENTATION_DIR@/html -@SPHINX_EXECUTABLE@ -b man -c @CMAKE_CURRENT_BINARY_DIR@/ @SPHINX_SOURCE_DIR@/source @DOCUMENTATION_DIR@/man \ No newline at end of file From 3475b83e9083cab393d2256cf68a7473a8778e68 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 29 Jul 2016 15:00:35 -0400 Subject: [PATCH 37/46] Clean up modifier/shortcut class and handle focus out event, Improve shortcut labels, Adjust menu titles and remove menu navigation (can conflict with shortcuts) --- apps/opencs/model/prefs/modifiersetting.cpp | 59 ++++---- apps/opencs/model/prefs/modifiersetting.hpp | 3 + apps/opencs/model/prefs/shortcutsetting.cpp | 105 +++++++------ apps/opencs/model/prefs/shortcutsetting.hpp | 7 +- apps/opencs/model/prefs/state.cpp | 156 ++++++++++---------- apps/opencs/view/doc/view.cpp | 38 ++--- 6 files changed, 187 insertions(+), 181 deletions(-) diff --git a/apps/opencs/model/prefs/modifiersetting.cpp b/apps/opencs/model/prefs/modifiersetting.cpp index 12a4b5d80..bbdad163d 100644 --- a/apps/opencs/model/prefs/modifiersetting.cpp +++ b/apps/opencs/model/prefs/modifiersetting.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -61,6 +60,10 @@ namespace CSMPrefs return handleEvent(target, mod, button); } + else if (event->type() == QEvent::FocusOut) + { + resetState(); + } return false; } @@ -80,24 +83,10 @@ namespace CSMPrefs if (value == Qt::RightButton) { // Clear modifier - QKeySequence sequence; int modifier = 0; + storeValue(modifier); - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); - - modifier = 0; - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); - - // Store - { - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); - - QMutexLocker lock(getMutex()); - getValues().setString(getKey(), getParent()->getKey(), value); - } - - // Update button - mButton->setText(""); + resetState(); } return false; @@ -112,32 +101,44 @@ namespace CSMPrefs // Update modifier - QKeySequence sequence; - int modifier = 0; + int modifier = value; + storeValue(modifier); - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + resetState(); - modifier = value; + return true; + } + + void ModifierSetting::storeValue(int modifier) + { + QKeySequence sequence; + int ignored; + State::get().getShortcutManager().getSequence(getKey(), sequence, ignored); State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); - // Store - { - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + // Convert to string and assign + std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + { QMutexLocker lock(getMutex()); getValues().setString(getKey(), getParent()->getKey(), value); } getParent()->getState()->update(*this); + } - // Update button - QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); - - mButton->setText(text); + void ModifierSetting::resetState() + { mButton->setChecked(false); mEditorActive = false; - return true; + // Button text + QKeySequence sequence; + int modifier = 0; + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); + mButton->setText(text); } void ModifierSetting::buttonToggled(bool checked) diff --git a/apps/opencs/model/prefs/modifiersetting.hpp b/apps/opencs/model/prefs/modifiersetting.hpp index b1394b6ea..95983f66d 100644 --- a/apps/opencs/model/prefs/modifiersetting.hpp +++ b/apps/opencs/model/prefs/modifiersetting.hpp @@ -29,6 +29,9 @@ namespace CSMPrefs bool handleEvent(QObject* target, int mod, int value); + void storeValue(int modifier); + void resetState(); + QPushButton* mButton; bool mEditorActive; diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index c98384695..82ecd7c81 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -13,14 +12,14 @@ namespace CSMPrefs { + const int ShortcutSetting::MaxKeys; + ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, const std::string& label) : Setting(parent, values, mutex, key, label) , mEditorActive(false) , mEditorPos(0) { - const int MaxKeys = 4; // A limitation of QKeySequence - for (int i = 0; i < MaxKeys; ++i) { mEditorKeys[i] = 0; @@ -30,8 +29,8 @@ namespace CSMPrefs std::pair ShortcutSetting::makeWidgets(QWidget* parent) { QKeySequence sequence; - int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + int ignored = 0; + State::get().getShortcutManager().getSequence(getKey(), sequence, ignored); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); @@ -87,14 +86,16 @@ namespace CSMPrefs return handleEvent(target, mod, key, false); } + else if (event->type() == QEvent::FocusOut) + { + resetState(); + } return false; } bool ShortcutSetting::handleEvent(QObject* target, int mod, int value, bool active) { - const int MaxKeys = 4; // A limitation of QKeySequence - // Modifiers are handled differently const int Blacklist[] = { @@ -112,24 +113,10 @@ namespace CSMPrefs if (value == Qt::RightButton && !active) { // Clear sequence - QKeySequence sequence; - int modifier = 0; - - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); - - sequence = QKeySequence(0, 0, 0, 0); - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); - - // Store - { - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); - - QMutexLocker lock(getMutex()); - getValues().setString(getKey(), getParent()->getKey(), value); - } + QKeySequence sequence = QKeySequence(0, 0, 0, 0); + storeValue(sequence); - // Update button - mButton->setText(""); + resetState(); } return false; @@ -145,37 +132,10 @@ namespace CSMPrefs if (!active || mEditorPos >= MaxKeys) { // Update key - QKeySequence sequence; - int modifier = 0; + QKeySequence sequence = QKeySequence(mEditorKeys[0], mEditorKeys[1], mEditorKeys[2], mEditorKeys[3]); + storeValue(sequence); - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); - - sequence = QKeySequence(mEditorKeys[0], mEditorKeys[1], mEditorKeys[2], mEditorKeys[3]); - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); - - // Store - { - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); - - QMutexLocker lock(getMutex()); - getValues().setString(getKey(), getParent()->getKey(), value); - } - - getParent()->getState()->update(*this); - - // Update button - QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); - - mButton->setText(text); - mButton->setChecked(false); - mEditorActive = false; - - // Reset - mEditorPos = 0; - for (int i = 0; i < MaxKeys; ++i) - { - mEditorKeys[i] = 0; - } + resetState(); } else { @@ -194,6 +154,43 @@ namespace CSMPrefs return true; } + void ShortcutSetting::storeValue(const QKeySequence& sequence) + { + QKeySequence ignored; + int modifier; + State::get().getShortcutManager().getSequence(getKey(), ignored, modifier); + State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + + // Convert to string and assign + std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + + { + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), value); + } + + getParent()->getState()->update(*this); + } + + void ShortcutSetting::resetState() + { + mButton->setChecked(false); + mEditorActive = false; + mEditorPos = 0; + for (int i = 0; i < MaxKeys; ++i) + { + mEditorKeys[i] = 0; + } + + // Button text + QKeySequence sequence; + int modifier = 0; + State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + + QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); + mButton->setText(text); + } + void ShortcutSetting::buttonToggled(bool checked) { if (checked) diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp index 0521e2291..bb38b580a 100644 --- a/apps/opencs/model/prefs/shortcutsetting.hpp +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -29,11 +29,16 @@ namespace CSMPrefs bool handleEvent(QObject* target, int mod, int value, bool active); + void storeValue(const QKeySequence& sequence); + void resetState(); + + static const int MaxKeys = 4; + QPushButton* mButton; bool mEditorActive; int mEditorPos; - int mEditorKeys[4]; + int mEditorKeys[MaxKeys]; private slots: diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 1813bf4db..ac562eaaf 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -218,116 +218,116 @@ void CSMPrefs::State::declare() declareCategory ("Key Bindings"); declareSubcategory ("Document"); - declareShortcut ("document-file-newgame", "Create new game", QKeySequence()); - declareShortcut ("document-file-newaddon", "Create new addon", QKeySequence()); + declareShortcut ("document-file-newgame", "New Game", QKeySequence()); + declareShortcut ("document-file-newaddon", "New Addon", QKeySequence()); declareShortcut ("document-file-open", "Open", QKeySequence()); declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); declareShortcut ("document-file-verify", "Verify", QKeySequence()); declareShortcut ("document-file-merge", "Merge", QKeySequence()); - declareShortcut ("document-file-errorlog", "Load error log", QKeySequence()); + declareShortcut ("document-file-errorlog", "Open Load Error Log", QKeySequence()); declareShortcut ("document-file-metadata", "Meta Data", QKeySequence()); - declareShortcut ("document-file-close", "Close", QKeySequence()); - declareShortcut ("document-file-exit", "Exit", QKeySequence()); + declareShortcut ("document-file-close", "Close Document", QKeySequence()); + declareShortcut ("document-file-exit", "Exit Application", QKeySequence()); declareShortcut ("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z)); declareShortcut ("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z)); - declareShortcut ("document-edit-preferences", "Show Preferences", QKeySequence()); - declareShortcut ("document-edit-search", "Show Search", QKeySequence()); + declareShortcut ("document-edit-preferences", "Open Preferences", QKeySequence()); + declareShortcut ("document-edit-search", "Search", QKeySequence()); declareShortcut ("document-view-newview", "New View", QKeySequence()); - declareShortcut ("document-view-statusbar", "Show Status Bar", QKeySequence()); - declareShortcut ("document-view-filters", "Show Filters", QKeySequence()); - declareShortcut ("document-world-regions", "Show Regions", QKeySequence()); - declareShortcut ("document-world-cells", "Show Cells", QKeySequence()); - declareShortcut ("document-world-referencables", "Show Referencables", QKeySequence()); - declareShortcut ("document-world-references", "Show References", QKeySequence()); - declareShortcut ("document-world-pathgrid", "Show Pathgrids", QKeySequence()); - declareShortcut ("document-world-regionmap", "Show Region Map", QKeySequence()); - declareShortcut ("document-mechanics-globals", "Show Globals", QKeySequence()); - declareShortcut ("document-mechanics-gamesettings", "Show Game Settings", QKeySequence()); - declareShortcut ("document-mechanics-scripts", "Show Scripts", QKeySequence()); - declareShortcut ("document-mechanics-spells", "Show Spells", QKeySequence()); - declareShortcut ("document-mechanics-enchantments", "Show Enchantments", QKeySequence()); - declareShortcut ("document-mechanics-magiceffects", "Show Magic Effects", QKeySequence()); - declareShortcut ("document-mechanics-startscripts", "Show Start Scripts", QKeySequence()); - declareShortcut ("document-character-skills", "Show Skills", QKeySequence()); - declareShortcut ("document-character-classes", "Show Classes", QKeySequence()); - declareShortcut ("document-character-factions", "Show Factions", QKeySequence()); - declareShortcut ("document-character-races", "Show Races", QKeySequence()); - declareShortcut ("document-character-birthsigns", "Show Birthsigns", QKeySequence()); - declareShortcut ("document-character-topics", "Show Topics", QKeySequence()); - declareShortcut ("document-character-journals", "Show Journals", QKeySequence()); - declareShortcut ("document-character-topicinfos", "Show Topic Infos", QKeySequence()); - declareShortcut ("document-character-journalinfos", "Show Journal Infos", QKeySequence()); - declareShortcut ("document-character-bodyparts", "Show Body Parts", QKeySequence()); - declareShortcut ("document-assets-sounds", "Show Sound Assets", QKeySequence()); - declareShortcut ("document-assets-soundgens", "Show Sound Generators", QKeySequence()); - declareShortcut ("document-assets-meshes", "Show Mesh Assets", QKeySequence()); - declareShortcut ("document-assets-icons", "Show Icon Assets", QKeySequence()); - declareShortcut ("document-assets-music", "Show Music Assets", QKeySequence()); - declareShortcut ("document-assets-soundres", "Show Sound Files", QKeySequence()); - declareShortcut ("document-assets-textures", "TShow exture Assets", QKeySequence()); - declareShortcut ("document-assets-videos", "Show Video Assets", QKeySequence()); + declareShortcut ("document-view-statusbar", "Toggle Status Bar", QKeySequence()); + declareShortcut ("document-view-filters", "Open Filter List", QKeySequence()); + declareShortcut ("document-world-regions", "Open Region List", QKeySequence()); + declareShortcut ("document-world-cells", "Open Cell List", QKeySequence()); + declareShortcut ("document-world-referencables", "Open Object List", QKeySequence()); + declareShortcut ("document-world-references", "Open Instance List", QKeySequence()); + declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence()); + declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence()); + declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence()); + declareShortcut ("document-mechanics-gamesettings", "Open Game Settings", QKeySequence()); + declareShortcut ("document-mechanics-scripts", "Open Script List", QKeySequence()); + declareShortcut ("document-mechanics-spells", "Open Spell List", QKeySequence()); + declareShortcut ("document-mechanics-enchantments", "Open Enchantment List", QKeySequence()); + declareShortcut ("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence()); + declareShortcut ("document-mechanics-startscripts", "Open Start Script List", QKeySequence()); + declareShortcut ("document-character-skills", "Open Skill List", QKeySequence()); + declareShortcut ("document-character-classes", "Open Class List", QKeySequence()); + declareShortcut ("document-character-factions", "Open Faction List", QKeySequence()); + declareShortcut ("document-character-races", "Open Race List", QKeySequence()); + declareShortcut ("document-character-birthsigns", "Open Birthsign List", QKeySequence()); + declareShortcut ("document-character-topics", "Open Topic List", QKeySequence()); + declareShortcut ("document-character-journals", "Open Journal List", QKeySequence()); + declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence()); + declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence()); + declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence()); + declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence()); + declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence()); + declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence()); + declareShortcut ("document-assets-icons", "Open Icon Asset List", QKeySequence()); + declareShortcut ("document-assets-music", "Open Music Asset List", QKeySequence()); + declareShortcut ("document-assets-soundres", "Open Sound File List", QKeySequence()); + declareShortcut ("document-assets-textures", "Open Texture Asset List", QKeySequence()); + declareShortcut ("document-assets-videos", "Open Video Asset List", QKeySequence()); declareShortcut ("document-debug-run", "Run Debug", QKeySequence()); declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence()); - declareShortcut ("document-debug-runlog", "Run Log", QKeySequence()); + declareShortcut ("document-debug-runlog", "Open Run Log", QKeySequence()); declareSubcategory ("Table"); - declareShortcut ("table-edit", "Edit record", QKeySequence()); - declareShortcut ("table-add", "Add row/record", QKeySequence(Qt::ControlModifier | Qt::Key_N)); - declareShortcut ("table-clone", "Clone record", QKeySequence()); - declareShortcut ("table-revert", "Revert record", QKeySequence()); - declareShortcut ("table-remove", "Remove row/record", QKeySequence(Qt::Key_Delete)); - declareShortcut ("table-moveup", "Move record up", QKeySequence()); - declareShortcut ("table-movedown", "Move record down", QKeySequence()); - declareShortcut ("table-view", "View record", QKeySequence()); - declareShortcut ("table-preview", "Preview record", QKeySequence()); - declareShortcut ("table-extendeddelete", "Extended record deletion", QKeySequence()); - declareShortcut ("table-extendedrevert", "Extended record revertion", QKeySequence()); + declareShortcut ("table-edit", "Edit Record", QKeySequence()); + declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ControlModifier | Qt::Key_N)); + declareShortcut ("table-clone", "Clone Record", QKeySequence()); + declareShortcut ("table-revert", "Revert Record", QKeySequence()); + declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); + declareShortcut ("table-moveup", "Move Record Up", QKeySequence()); + declareShortcut ("table-movedown", "Move Record Down", QKeySequence()); + declareShortcut ("table-view", "View Record", QKeySequence()); + declareShortcut ("table-preview", "Preview Record", QKeySequence()); + declareShortcut ("table-extendeddelete", "Extended Record Deletion", QKeySequence()); + declareShortcut ("table-extendedrevert", "Extended Record Revertion", QKeySequence()); declareSubcategory ("Report Table"); - declareShortcut ("reporttable-show", "Show report", QKeySequence()); - declareShortcut ("reporttable-remove", "Remove report", QKeySequence(Qt::Key_Delete)); - declareShortcut ("reporttable-replace", "Replace report", QKeySequence()); - declareShortcut ("reporttable-refresh", "Refresh report", QKeySequence()); + declareShortcut ("reporttable-show", "Show Report", QKeySequence()); + declareShortcut ("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete)); + declareShortcut ("reporttable-replace", "Replace Report", QKeySequence()); + declareShortcut ("reporttable-refresh", "Refresh Report", QKeySequence()); declareSubcategory ("1st/Free Camera"); declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S)); declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A)); declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D)); - declareModifier ("free-forward", "Speed modifier"); - declareShortcut ("free-roll-left", "Roll left", QKeySequence(Qt::Key_Q)); - declareShortcut ("free-roll-right", "Roll right", QKeySequence(Qt::Key_E)); - declareShortcut ("free-speed-mode", "Speed mode toggle", QKeySequence(Qt::Key_F)); + declareModifier ("free-forward", "Speed Modifier"); + declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); + declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); + declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); declareSubcategory ("Orbit Camera"); declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W), Qt::Key_Shift); declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S)); declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A)); declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D)); - declareModifier ("orbit-up", "Speed modifier"); - declareShortcut ("orbit-roll-left", "Roll left", QKeySequence(Qt::Key_Q)); - declareShortcut ("orbit-roll-right", "Roll right", QKeySequence(Qt::Key_E)); - declareShortcut ("orbit-speed-mode", "Speed mode toggle", QKeySequence(Qt::Key_F)); - declareShortcut ("orbit-center-selection", "Center on selected", QKeySequence(Qt::Key_C)); + declareModifier ("orbit-up", "Speed Modifier"); + declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); + declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); + declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); + declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); declareSubcategory ("Scene"); - declareShortcut ("scene-navi-primary", "Camera rotation from mouse movement", QKeySequence(Qt::LeftButton)); - declareShortcut ("scene-navi-secondary", "Camera translation from mouse movement", + declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); + declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement", QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); - declareShortcut ("scene-edit-primary", "Primary edit", QKeySequence(Qt::RightButton)); - declareShortcut ("scene-edit-secondary", "Secondary edit", + declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton)); + declareShortcut ("scene-edit-secondary", "Secondary Edit", QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); - declareShortcut ("scene-select-primary", "Primary select", QKeySequence(Qt::MiddleButton)); - declareShortcut ("scene-select-secondary", "Secondary select", + declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); + declareShortcut ("scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); - declareShortcut ("scene-load-cam-cell", "Load camera cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); - declareShortcut ("scene-load-cam-eastcell", "Load east cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); - declareShortcut ("scene-load-cam-northcell", "Load north cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); - declareShortcut ("scene-load-cam-westcell", "Load west cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4)); - declareShortcut ("scene-load-cam-southcell", "Load south cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2)); + declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); + declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); + declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); + declareShortcut ("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4)); + declareShortcut ("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2)); declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); - declareShortcut ("scene-focus-toolbar", "Toggle toolbar focus", QKeySequence(Qt::Key_T)); - declareShortcut ("scene-render-stats", "Debug rendering stats", QKeySequence(Qt::Key_F3)); + declareShortcut ("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T)); + declareShortcut ("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3)); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index df7146404..ff49a90fd 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -45,7 +45,7 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) void CSVDoc::View::setupFileMenu() { - QMenu *file = menuBar()->addMenu (tr ("&File")); + QMenu *file = menuBar()->addMenu (tr ("File")); QAction *newGame = new QAction (tr ("New Game"), this); connect (newGame, SIGNAL (triggered()), this, SIGNAL (newGameRequest())); @@ -58,17 +58,17 @@ void CSVDoc::View::setupFileMenu() setupShortcut("document-file-newaddon", newAddon); file->addAction (newAddon); - QAction *open = new QAction (tr ("&Open"), this); + QAction *open = new QAction (tr ("Open"), this); connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); setupShortcut("document-file-open", open); file->addAction (open); - mSave = new QAction (tr ("&Save"), this); + mSave = new QAction (tr ("Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); setupShortcut("document-file-save", mSave); file->addAction (mSave); - mVerify = new QAction (tr ("&Verify"), this); + mVerify = new QAction (tr ("Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); setupShortcut("document-file-verify", mVerify); file->addAction (mVerify); @@ -78,7 +78,7 @@ void CSVDoc::View::setupFileMenu() setupShortcut("document-file-merge", mMerge); file->addAction (mMerge); - QAction *loadErrors = new QAction (tr ("Load Error Log"), this); + QAction *loadErrors = new QAction (tr ("Open Load Error Log"), this); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); setupShortcut("document-file-errorlog", loadErrors); file->addAction (loadErrors); @@ -88,12 +88,12 @@ void CSVDoc::View::setupFileMenu() setupShortcut("document-file-metadata", meta); file->addAction (meta); - QAction *close = new QAction (tr ("&Close"), this); + QAction *close = new QAction (tr ("Close Document"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); setupShortcut("document-file-close", close); file->addAction(close); - QAction *exit = new QAction (tr ("&Exit"), this); + QAction *exit = new QAction (tr ("Exit Application"), this); connect (exit, SIGNAL (triggered()), this, SLOT (exit())); connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); setupShortcut("document-file-exit", exit); @@ -103,17 +103,17 @@ void CSVDoc::View::setupFileMenu() void CSVDoc::View::setupEditMenu() { - QMenu *edit = menuBar()->addMenu (tr ("&Edit")); + QMenu *edit = menuBar()->addMenu (tr ("Edit")); - mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo")); + mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo")); setupShortcut("document-edit-undo", mUndo); edit->addAction (mUndo); - mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); + mRedo= mDocument->getUndoStack().createRedoAction (this, tr("Redo")); setupShortcut("document-edit-redo", mRedo); edit->addAction (mRedo); - QAction *userSettings = new QAction (tr ("&Preferences"), this); + QAction *userSettings = new QAction (tr ("Preferences"), this); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); setupShortcut("document-edit-preferences", userSettings); edit->addAction (userSettings); @@ -126,14 +126,14 @@ void CSVDoc::View::setupEditMenu() void CSVDoc::View::setupViewMenu() { - QMenu *view = menuBar()->addMenu (tr ("&View")); + QMenu *view = menuBar()->addMenu (tr ("View")); - QAction *newWindow = new QAction (tr ("&New View"), this); + QAction *newWindow = new QAction (tr ("New View"), this); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); setupShortcut("document-view-newview", newWindow); view->addAction (newWindow); - mShowStatusBar = new QAction (tr ("Show Status Bar"), this); + mShowStatusBar = new QAction (tr ("Toggle Status Bar"), this); mShowStatusBar->setCheckable (true); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); setupShortcut("document-view-statusbar", mShowStatusBar); @@ -150,7 +150,7 @@ void CSVDoc::View::setupViewMenu() void CSVDoc::View::setupWorldMenu() { - QMenu *world = menuBar()->addMenu (tr ("&World")); + QMenu *world = menuBar()->addMenu (tr ("World")); QAction *regions = new QAction (tr ("Regions"), this); connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); @@ -187,14 +187,14 @@ void CSVDoc::View::setupWorldMenu() void CSVDoc::View::setupMechanicsMenu() { - QMenu *mechanics = menuBar()->addMenu (tr ("&Mechanics")); + QMenu *mechanics = menuBar()->addMenu (tr ("Mechanics")); QAction *globals = new QAction (tr ("Globals"), this); connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); setupShortcut("document-mechanics-globals", globals); mechanics->addAction (globals); - QAction *gmsts = new QAction (tr ("Game settings"), this); + QAction *gmsts = new QAction (tr ("Game Settings"), this); connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); setupShortcut("document-mechanics-gamesettings", gmsts); mechanics->addAction (gmsts); @@ -282,7 +282,7 @@ void CSVDoc::View::setupCharacterMenu() void CSVDoc::View::setupAssetsMenu() { - QMenu *assets = menuBar()->addMenu (tr ("&Assets")); + QMenu *assets = menuBar()->addMenu (tr ("Assets")); QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); @@ -354,7 +354,7 @@ void CSVDoc::View::setupDebugMenu() setupShortcut("document-debug-shutdown", mStopDebug); debug->addAction (mStopDebug); - QAction *runLog = new QAction (tr ("Run Log"), this); + QAction *runLog = new QAction (tr ("Open Run Log"), this); connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView())); setupShortcut("document-debug-runlog", runLog); debug->addAction (runLog); From d7a83d80a2f0f01657976d550a21aeae45a5dd1c Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 29 Jul 2016 15:00:58 -0400 Subject: [PATCH 38/46] Change some key binding defaults. --- apps/opencs/model/prefs/state.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index ac562eaaf..f9c84011e 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -218,20 +218,20 @@ void CSMPrefs::State::declare() declareCategory ("Key Bindings"); declareSubcategory ("Document"); - declareShortcut ("document-file-newgame", "New Game", QKeySequence()); + declareShortcut ("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N)); declareShortcut ("document-file-newaddon", "New Addon", QKeySequence()); - declareShortcut ("document-file-open", "Open", QKeySequence()); + declareShortcut ("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O)); declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); declareShortcut ("document-file-verify", "Verify", QKeySequence()); declareShortcut ("document-file-merge", "Merge", QKeySequence()); declareShortcut ("document-file-errorlog", "Open Load Error Log", QKeySequence()); declareShortcut ("document-file-metadata", "Meta Data", QKeySequence()); - declareShortcut ("document-file-close", "Close Document", QKeySequence()); - declareShortcut ("document-file-exit", "Exit Application", QKeySequence()); + declareShortcut ("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W)); + declareShortcut ("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q)); declareShortcut ("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z)); declareShortcut ("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z)); declareShortcut ("document-edit-preferences", "Open Preferences", QKeySequence()); - declareShortcut ("document-edit-search", "Search", QKeySequence()); + declareShortcut ("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F)); declareShortcut ("document-view-newview", "New View", QKeySequence()); declareShortcut ("document-view-statusbar", "Toggle Status Bar", QKeySequence()); declareShortcut ("document-view-filters", "Open Filter List", QKeySequence()); @@ -272,8 +272,8 @@ void CSMPrefs::State::declare() declareSubcategory ("Table"); declareShortcut ("table-edit", "Edit Record", QKeySequence()); - declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ControlModifier | Qt::Key_N)); - declareShortcut ("table-clone", "Clone Record", QKeySequence()); + declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A)); + declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D)); declareShortcut ("table-revert", "Revert Record", QKeySequence()); declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); declareShortcut ("table-moveup", "Move Record Up", QKeySequence()); From 2f97d6cffbecf1ccf519546ec091bf30ab305782 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 29 Jul 2016 16:02:46 -0400 Subject: [PATCH 39/46] Move tool tip processing to ShortcutManager, Process cell arrow tooltip, Fix cell arrows not being added when cell is added --- apps/opencs/model/prefs/shortcutmanager.cpp | 68 +++++++++++++++++++ apps/opencs/model/prefs/shortcutmanager.hpp | 4 ++ apps/opencs/view/render/cellarrow.cpp | 18 +++-- .../view/render/pagedworldspacewidget.cpp | 5 +- apps/opencs/view/widget/pushbutton.cpp | 62 +---------------- apps/opencs/view/widget/pushbutton.hpp | 1 - 6 files changed, 91 insertions(+), 67 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index e259398b5..37eec0415 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -255,6 +255,74 @@ namespace CSMPrefs } } + QString ShortcutManager::processToolTip(const QString& toolTip) const + { + const QChar SequenceStart = '{'; + const QChar SequenceEnd = '}'; + const QString ModifierSequence = QString::fromUtf8(":mod"); + + QStringList substrings; + + int prevIndex = 0; + int startIndex = toolTip.indexOf(SequenceStart); + int endIndex = (startIndex != -1) ? toolTip.indexOf(SequenceEnd, startIndex) : -1; + + // Process every valid shortcut escape sequence + while (startIndex != -1 && endIndex != -1) + { + int count = startIndex - prevIndex; + if (count > 0) + { + substrings.push_back(toolTip.mid(prevIndex, count)); + } + + // Find sequence name + startIndex += 1; // '{' character + count = endIndex - startIndex; + if (count > 0) + { + // Check if looking for modifier + int separatorIndex = toolTip.indexOf(ModifierSequence, startIndex); + if (separatorIndex != -1 && separatorIndex < endIndex) + { + count = separatorIndex - startIndex; + + QString settingName = toolTip.mid(startIndex, count); + + QKeySequence ignored; + int modifier = 0; + getSequence(settingName.toUtf8().data(), ignored, modifier); + + QString value = QString::fromUtf8(convertToString(modifier).c_str()); + substrings.push_back(value); + } + else + { + QString settingName = toolTip.mid(startIndex, count); + + QKeySequence sequence; + int ignored = 0; + getSequence(settingName.toUtf8().data(), sequence, ignored); + + QString value = QString::fromUtf8(convertToString(sequence).c_str()); + substrings.push_back(value); + } + + prevIndex = endIndex + 1; // '}' character + } + + startIndex = toolTip.indexOf(SequenceStart, endIndex); + endIndex = (startIndex != -1) ? toolTip.indexOf(SequenceEnd, startIndex) : -1; + } + + if (prevIndex < toolTip.size()) + { + substrings.push_back(toolTip.mid(prevIndex)); + } + + return substrings.join(""); + } + const std::pair ShortcutManager::QtKeys[] = { std::make_pair((int)Qt::Key_Space , "Space"), diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index 26bdc4255..bb081a82a 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace CSMPrefs { @@ -39,6 +40,9 @@ namespace CSMPrefs void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const; + /// Replaces "{sequence-name}" or "{sequence-name:mod}" with the appropriate text + QString processToolTip(const QString& toolTip) const; + private: /// Key Sequence, Modifier (for secondary signal) diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index 6d8fa1c6c..b8c89c83d 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -7,6 +7,9 @@ #include #include +#include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcutmanager.hpp" + #include "mask.hpp" CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) @@ -35,14 +38,19 @@ QString CSVRender::CellArrowTag::getToolTip (bool hideBasics) const text += "

                        " "Modify which cells are shown" - "

                        • Primary-Edit: Add cell in given direction
                        • " - "
                        • Secondary-Edit: Add cell and remove old cell
                        • " - "
                        • Shift Primary-Edit: Add cells in given direction
                        • " - "
                        • Shift Secondary-Edit: Add cells and remove old cells
                        • " + "
                          • {scene-edit-primary}: Add cell in given direction
                          • " + "
                          • {scene-edit-secondary}: Add cell and remove old cell
                          • " + "
                          • {scene-select-primary}: Add cells in given direction
                          • " + "
                          • {scene-select-secondary}: Add cells and remove old cells
                          • " + "
                          • {scene-load-cam-cell}: Load cell where camera is located
                          • " + "
                          • {scene-load-cam-eastcell}: Load cell to east
                          • " + "
                          • {scene-load-cam-northcell}: Load cell to north
                          • " + "
                          • {scene-load-cam-westcell}: Load cell to west
                          • " + "
                          • {scene-load-cam-southcell}: Load cell to south
                          • " "
                          "; } - return text; + return CSMPrefs::State::get().getShortcutManager().processToolTip(text); } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 786beb530..ab2e252af 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -447,9 +447,12 @@ void CSVRender::PagedWorldspaceWidget::addCellToSceneFromCamera (int offsetX, in CSMWorld::CellCoordinates cellCoordinates(cellX, cellY); - if (mCells.find(cellCoordinates) == mCells.end()) + if (!mSelection.has(cellCoordinates)) { addCellToScene(cellCoordinates); + mSelection.add(cellCoordinates); + + adjustCells(); } } diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 100f3bd43..c4e6a4144 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -4,69 +4,11 @@ #include #include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcutmanager.hpp" void CSVWidget::PushButton::processShortcuts() { - const QChar SequenceStart = '{'; - const QChar SequenceEnd = '}'; - const QString ModifierSequence = QString::fromUtf8(":mod"); - - const QChar SettingSeparator = ';'; - - QStringList substrings; - - int prevIndex = 0; - int startIndex = mToolTip.indexOf(SequenceStart); - int endIndex = (startIndex != -1) ? mToolTip.indexOf(SequenceEnd, startIndex) : -1; - - // Process every valid shortcut escape sequence - while (startIndex != -1 && endIndex != -1) - { - int count = startIndex - prevIndex; - if (count > 0) - { - substrings.push_back(mToolTip.mid(prevIndex, count)); - } - - // Find sequence name - count = endIndex - startIndex - 1; - if (count > 0) - { - // Check if looking for modifier - int separatorIndex = mToolTip.indexOf(ModifierSequence, startIndex); - if (separatorIndex != -1 && separatorIndex < endIndex) - { - count = separatorIndex - startIndex - 1; - - QString settingName = mToolTip.mid(startIndex+1, count); - QString value = QString::fromUtf8( - CSMPrefs::State::get()["Key Bindings"][settingName.toUtf8().data()].toString().c_str()); - - substrings.push_back(value.right(value.size() - value.indexOf(SettingSeparator) - 1)); - } - else - { - QString settingName = mToolTip.mid(startIndex+1, count); - QString value = QString::fromUtf8( - CSMPrefs::State::get()["Key Bindings"][settingName.toUtf8().data()].toString().c_str()); - - // Don't want modifier - substrings.push_back(value.left(value.indexOf(SettingSeparator))); - } - - prevIndex = endIndex + 1; - } - - startIndex = mToolTip.indexOf(SequenceStart, endIndex); - endIndex = (startIndex != -1) ? mToolTip.indexOf(SequenceEnd, startIndex) : -1; - } - - if (prevIndex < mToolTip.size()) - { - substrings.push_back(mToolTip.mid(prevIndex)); - } - - mProcessedToolTip = substrings.join(""); + mProcessedToolTip = CSMPrefs::State::get().getShortcutManager().processToolTip(mToolTip); } void CSVWidget::PushButton::setExtendedToolTip() diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 65df1b7e3..bdbdc9c4d 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -33,7 +33,6 @@ namespace CSVWidget private: - // Uses {, :, and } as escape sequences for looking up shortcut settings void processShortcuts(); void setExtendedToolTip(); From 1cce085fa2d830e3e578aa668baadac90ed837cd Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 29 Jul 2016 16:35:43 -0400 Subject: [PATCH 40/46] Remove unused headers. --- apps/opencs/model/prefs/shortcutmanager.cpp | 3 --- apps/opencs/model/prefs/state.cpp | 2 -- apps/opencs/view/prefs/keybindingpage.cpp | 1 - 3 files changed, 6 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 37eec0415..5a3514a5e 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -1,11 +1,8 @@ #include "shortcutmanager.hpp" #include -#include #include -#include -#include #include #include "shortcut.hpp" diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index f9c84011e..64a01bf27 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include "intsetting.hpp" #include "doublesetting.hpp" #include "boolsetting.hpp" diff --git a/apps/opencs/view/prefs/keybindingpage.cpp b/apps/opencs/view/prefs/keybindingpage.cpp index 63b196831..143665f4a 100644 --- a/apps/opencs/view/prefs/keybindingpage.cpp +++ b/apps/opencs/view/prefs/keybindingpage.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include From bc7ae70f0bee9fa4d0a8e27b97f2459ec7550d3f Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sat, 30 Jul 2016 09:53:45 -0400 Subject: [PATCH 41/46] Change scene controls to more closely match blender as requested in the forums. --- apps/opencs/model/prefs/state.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 64a01bf27..f6b6da94c 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -309,15 +309,15 @@ void CSMPrefs::State::declare() declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); declareSubcategory ("Scene"); - declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); + declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::MiddleButton)); declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement", - QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); - declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton)); + QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton)); + declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::LeftButton)); declareShortcut ("scene-edit-secondary", "Secondary Edit", - QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); - declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); + QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton)); + declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::RightButton)); declareShortcut ("scene-select-secondary", "Secondary Select", - QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); + QKeySequence(Qt::ShiftModifier | (int)Qt::RightButton)); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); From faea33b888f3aab7c0cd7d865be062d6b9cc7972 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 31 Jul 2016 05:54:13 -0400 Subject: [PATCH 42/46] Revert "Change scene controls to more closely match blender as requested" This reverts commit bc7ae70f0bee9fa4d0a8e27b97f2459ec7550d3f. --- apps/opencs/model/prefs/state.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index f6b6da94c..64a01bf27 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -309,15 +309,15 @@ void CSMPrefs::State::declare() declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); declareSubcategory ("Scene"); - declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::MiddleButton)); + declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement", - QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton)); - declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::LeftButton)); + QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); + declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton)); declareShortcut ("scene-edit-secondary", "Secondary Edit", - QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton)); - declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::RightButton)); + QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); + declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); declareShortcut ("scene-select-secondary", "Secondary Select", - QKeySequence(Qt::ShiftModifier | (int)Qt::RightButton)); + QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); From bf2ab4ed45fc87c97b46f3005ad096adc1c7af38 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 31 Jul 2016 16:07:17 -0400 Subject: [PATCH 43/46] Change the way modifiers are handled so they can be shared. --- apps/opencs/model/prefs/modifiersetting.cpp | 13 ++-- apps/opencs/model/prefs/shortcut.cpp | 34 ++++++++- apps/opencs/model/prefs/shortcut.hpp | 6 +- apps/opencs/model/prefs/shortcutmanager.cpp | 74 +++++++++++++------- apps/opencs/model/prefs/shortcutmanager.hpp | 16 +++-- apps/opencs/model/prefs/shortcutsetting.cpp | 13 ++-- apps/opencs/model/prefs/state.cpp | 62 +++++++++------- apps/opencs/model/prefs/state.hpp | 4 +- apps/opencs/view/render/cameracontroller.cpp | 7 +- apps/opencs/view/render/worldspacewidget.cpp | 4 +- 10 files changed, 144 insertions(+), 89 deletions(-) diff --git a/apps/opencs/model/prefs/modifiersetting.cpp b/apps/opencs/model/prefs/modifiersetting.cpp index bbdad163d..d8bf84342 100644 --- a/apps/opencs/model/prefs/modifiersetting.cpp +++ b/apps/opencs/model/prefs/modifiersetting.cpp @@ -21,9 +21,8 @@ namespace CSMPrefs std::pair ModifierSetting::makeWidgets(QWidget* parent) { - QKeySequence sequence; int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().getModifier(getKey(), modifier); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); @@ -111,13 +110,10 @@ namespace CSMPrefs void ModifierSetting::storeValue(int modifier) { - QKeySequence sequence; - int ignored; - State::get().getShortcutManager().getSequence(getKey(), sequence, ignored); - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().setModifier(getKey(), modifier); // Convert to string and assign - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + std::string value = State::get().getShortcutManager().convertToString(modifier); { QMutexLocker lock(getMutex()); @@ -133,9 +129,8 @@ namespace CSMPrefs mEditorActive = false; // Button text - QKeySequence sequence; int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().getModifier(getKey(), modifier); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); mButton->setText(text); diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index 90ec987ff..27077ac83 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -14,6 +14,7 @@ namespace CSMPrefs : QObject(parent) , mEnabled(true) , mName(name) + , mModName("") , mSecondaryMode(SM_Ignore) , mModifier(0) , mCurrentPos(0) @@ -25,13 +26,34 @@ namespace CSMPrefs assert (parent); State::get().getShortcutManager().addShortcut(this); - State::get().getShortcutManager().getSequence(name, mSequence, mModifier); + State::get().getShortcutManager().getSequence(name, mSequence); } - Shortcut::Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent) + Shortcut::Shortcut(const std::string& name, const std::string& modName, QWidget* parent) : QObject(parent) , mEnabled(true) , mName(name) + , mModName(modName) + , mSecondaryMode(SM_Ignore) + , mModifier(0) + , mCurrentPos(0) + , mLastPos(0) + , mActivationStatus(AS_Inactive) + , mModifierStatus(false) + , mAction(0) + { + assert (parent); + + State::get().getShortcutManager().addShortcut(this); + State::get().getShortcutManager().getSequence(name, mSequence); + State::get().getShortcutManager().getModifier(modName, mModifier); + } + + Shortcut::Shortcut(const std::string& name, const std::string& modName, SecondaryMode secMode, QWidget* parent) + : QObject(parent) + , mEnabled(true) + , mName(name) + , mModName(modName) , mSecondaryMode(secMode) , mModifier(0) , mCurrentPos(0) @@ -43,7 +65,8 @@ namespace CSMPrefs assert (parent); State::get().getShortcutManager().addShortcut(this); - State::get().getShortcutManager().getSequence(name, mSequence, mModifier); + State::get().getShortcutManager().getSequence(name, mSequence); + State::get().getShortcutManager().getModifier(modName, mModifier); } Shortcut::~Shortcut() @@ -61,6 +84,11 @@ namespace CSMPrefs return mName; } + const std::string& Shortcut::getModifierName() const + { + return mModName; + } + Shortcut::SecondaryMode Shortcut::getSecondaryMode() const { return mSecondaryMode; diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index fa68e6f19..7a90a1d08 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -34,13 +34,16 @@ namespace CSMPrefs }; Shortcut(const std::string& name, QWidget* parent); - Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent); + Shortcut(const std::string& name, const std::string& modName, QWidget* parent); + Shortcut(const std::string& name, const std::string& modName, SecondaryMode secMode, QWidget* parent); ~Shortcut(); bool isEnabled() const; const std::string& getName() const; + const std::string& getModifierName() const; + SecondaryMode getSecondaryMode() const; const QKeySequence& getSequence() const; @@ -82,6 +85,7 @@ namespace CSMPrefs bool mEnabled; std::string mName; + std::string mModName; SecondaryMode mSecondaryMode; QKeySequence mSequence; int mModifier; diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 5a3514a5e..6ae778fff 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -19,6 +19,7 @@ namespace CSMPrefs void ShortcutManager::addShortcut(Shortcut* shortcut) { mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut)); + mShortcuts.insert(std::make_pair(shortcut->getModifierName(), shortcut)); mEventHandler->addShortcut(shortcut); } @@ -41,13 +42,12 @@ namespace CSMPrefs mEventHandler->removeShortcut(shortcut); } - bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence, int& modifier) const + bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence) const { SequenceMap::const_iterator item = mSequences.find(name); if (item != mSequences.end()) { - sequence = item->second.first; - modifier = item->second.second; + sequence = item->second; return true; } @@ -55,17 +55,17 @@ namespace CSMPrefs return false; } - void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence, int modifier) + void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence) { // Add to map/modify SequenceMap::iterator item = mSequences.find(name); if (item != mSequences.end()) { - item->second = std::make_pair(sequence, modifier); + item->second = sequence; } else { - mSequences.insert(std::make_pair(name, std::make_pair(sequence, modifier))); + mSequences.insert(std::make_pair(name, sequence)); } // Change active shortcuts @@ -74,6 +74,40 @@ namespace CSMPrefs for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) { it->second->setSequence(sequence); + } + } + + bool ShortcutManager::getModifier(const std::string& name, int& modifier) const + { + ModifierMap::const_iterator item = mModifiers.find(name); + if (item != mModifiers.end()) + { + modifier = item->second; + + return true; + } + else + return false; + } + + void ShortcutManager::setModifier(const std::string& name, int modifier) + { + // Add to map/modify + ModifierMap::iterator item = mModifiers.find(name); + if (item != mModifiers.end()) + { + item->second = modifier; + } + else + { + mModifiers.insert(std::make_pair(name, modifier)); + } + + // Change active shortcuts + std::pair rangeS = mShortcuts.equal_range(name); + + for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) + { it->second->setModifier(modifier); } } @@ -256,7 +290,6 @@ namespace CSMPrefs { const QChar SequenceStart = '{'; const QChar SequenceEnd = '}'; - const QString ModifierSequence = QString::fromUtf8(":mod"); QStringList substrings; @@ -278,30 +311,19 @@ namespace CSMPrefs count = endIndex - startIndex; if (count > 0) { - // Check if looking for modifier - int separatorIndex = toolTip.indexOf(ModifierSequence, startIndex); - if (separatorIndex != -1 && separatorIndex < endIndex) - { - count = separatorIndex - startIndex; + QString settingName = toolTip.mid(startIndex, count); - QString settingName = toolTip.mid(startIndex, count); + QKeySequence sequence; + int modifier; - QKeySequence ignored; - int modifier = 0; - getSequence(settingName.toUtf8().data(), ignored, modifier); - - QString value = QString::fromUtf8(convertToString(modifier).c_str()); + if (getSequence(settingName.toUtf8().data(), sequence)) + { + QString value = QString::fromUtf8(convertToString(sequence).c_str()); substrings.push_back(value); } - else + else if (getModifier(settingName.toUtf8().data(), modifier)) { - QString settingName = toolTip.mid(startIndex, count); - - QKeySequence sequence; - int ignored = 0; - getSequence(settingName.toUtf8().data(), sequence, ignored); - - QString value = QString::fromUtf8(convertToString(sequence).c_str()); + QString value = QString::fromUtf8(convertToString(modifier).c_str()); substrings.push_back(value); } diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index bb081a82a..99f01a5df 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -27,8 +27,11 @@ namespace CSMPrefs /// The shortcut class will do this automatically void removeShortcut(Shortcut* shortcut); - bool getSequence(const std::string& name, QKeySequence& sequence, int& modifier) const; - void setSequence(const std::string& name, const QKeySequence& sequence, int modifier); + bool getSequence(const std::string& name, QKeySequence& sequence) const; + void setSequence(const std::string& name, const QKeySequence& sequence); + + bool getModifier(const std::string& name, int& modifier) const; + void setModifier(const std::string& name, int modifier); std::string convertToString(const QKeySequence& sequence) const; std::string convertToString(int modifier) const; @@ -40,22 +43,21 @@ namespace CSMPrefs void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const; - /// Replaces "{sequence-name}" or "{sequence-name:mod}" with the appropriate text + /// Replaces "{sequence-name}" or "{modifier-name}" with the appropriate text QString processToolTip(const QString& toolTip) const; private: - /// Key Sequence, Modifier (for secondary signal) - typedef std::pair SequenceData; - // Need a multimap in case multiple shortcuts share the same name typedef std::multimap ShortcutMap; - typedef std::map SequenceMap; + typedef std::map SequenceMap; + typedef std::map ModifierMap; typedef std::map NameMap; typedef std::map KeyMap; ShortcutMap mShortcuts; SequenceMap mSequences; + ModifierMap mModifiers; NameMap mNames; KeyMap mKeys; diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 82ecd7c81..726566fdd 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -29,8 +29,7 @@ namespace CSMPrefs std::pair ShortcutSetting::makeWidgets(QWidget* parent) { QKeySequence sequence; - int ignored = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, ignored); + State::get().getShortcutManager().getSequence(getKey(), sequence); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); @@ -156,13 +155,10 @@ namespace CSMPrefs void ShortcutSetting::storeValue(const QKeySequence& sequence) { - QKeySequence ignored; - int modifier; - State::get().getShortcutManager().getSequence(getKey(), ignored, modifier); - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().setSequence(getKey(), sequence); // Convert to string and assign - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + std::string value = State::get().getShortcutManager().convertToString(sequence); { QMutexLocker lock(getMutex()); @@ -184,8 +180,7 @@ namespace CSMPrefs // Button text QKeySequence sequence; - int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().getSequence(getKey(), sequence); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); mButton->setText(text); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 64a01bf27..718d9a107 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -287,27 +287,6 @@ void CSMPrefs::State::declare() declareShortcut ("reporttable-replace", "Replace Report", QKeySequence()); declareShortcut ("reporttable-refresh", "Refresh Report", QKeySequence()); - declareSubcategory ("1st/Free Camera"); - declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); - declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S)); - declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A)); - declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D)); - declareModifier ("free-forward", "Speed Modifier"); - declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); - declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); - declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); - - declareSubcategory ("Orbit Camera"); - declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W), Qt::Key_Shift); - declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S)); - declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A)); - declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D)); - declareModifier ("orbit-up", "Speed Modifier"); - declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); - declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); - declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); - declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); - declareSubcategory ("Scene"); declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement", @@ -318,6 +297,7 @@ void CSMPrefs::State::declare() declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); declareShortcut ("scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); + declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); @@ -326,6 +306,25 @@ void CSMPrefs::State::declare() declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); declareShortcut ("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T)); declareShortcut ("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3)); + + declareSubcategory ("1st/Free Camera"); + declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W)); + declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S)); + declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A)); + declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D)); + declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); + declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); + declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); + + declareSubcategory ("Orbit Camera"); + declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W)); + declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S)); + declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A)); + declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D)); + declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); + declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); + declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); + declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -443,20 +442,19 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, } CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_, int modifier_) + const QKeySequence& default_) { if (mCurrentCategory==mCategories.end()) throw std::logic_error ("no category for setting"); - std::string seqStr = getShortcutManager().convertToString(default_, modifier_); + std::string seqStr = getShortcutManager().convertToString(default_); setDefault (key, seqStr); // Setup with actual data QKeySequence sequence; - int mod; - getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence, mod); - getShortcutManager().setSequence(key, sequence, mod); + getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence); + getShortcutManager().setSequence(key, sequence); CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label); @@ -465,11 +463,21 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& return *setting; } -CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label) +CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label, + int default_) { if (mCurrentCategory==mCategories.end()) throw std::logic_error ("no category for setting"); + std::string modStr = getShortcutManager().convertToString(default_); + setDefault (key, modStr); + + // Setup with actual data + int modifier; + + getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), modifier); + getShortcutManager().setModifier(key, modifier); + CSMPrefs::ModifierSetting *setting = new CSMPrefs::ModifierSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label); mCurrentCategory->second.addSetting (setting); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 64927f881..1e46c68ee 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -76,9 +76,9 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_, int modifier_=0); + const QKeySequence& default_); - ModifierSetting& declareModifier(const std::string& key, const std::string& label); + ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_); void declareSeparator(); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 6df7c0478..7e3570657 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -189,8 +189,8 @@ namespace CSVRender addShortcut(naviSecondaryShortcut); - CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", CSMPrefs::Shortcut::SM_Detach, - widget); + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", "scene-speed-modifier", + CSMPrefs::Shortcut::SM_Detach, widget); forwardShortcut->enable(false); connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); connect(forwardShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); @@ -476,7 +476,8 @@ namespace CSVRender addShortcut(naviSecondaryShortcut); - CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", CSMPrefs::Shortcut::SM_Detach, widget); + CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", "scene-speed-modifier", + CSMPrefs::Shortcut::SM_Detach, widget); upShortcut->enable(false); connect(upShortcut, SIGNAL(activated(bool)), this, SLOT(up(bool))); connect(upShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index dda665c31..2dfa66a12 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -168,7 +168,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
                        • Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)
                        • " "
                        • Strafing (also vertically) by holding {scene-navi-secondary}
                        • " "
                        • Mouse wheel moves the camera forward/backward
                        • " - "
                        • Hold {free-forward:mod} to speed up movement
                        • " + "
                        • Hold {scene-speed-modifier} to speed up movement
                        • " "
                        "); tool->addButton (":scenetoolbar/free-camera", "free", "Free Camera" @@ -188,7 +188,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
                      • Roll camera with {orbit-roll-left} and {orbit-roll-right} keys
                      • " "
                      • Strafing (also vertically) by holding {scene-navi-secondary} (includes relocation of the centre point)
                      • " "
                      • Mouse wheel moves camera away or towards centre point but can not pass through it
                      • " - "
                      • Hold {orbit-up:mod} to speed up movement
                      • " + "
                      • Hold {scene-speed-modifier} to speed up movement
                      • " "
                      ", tool), "orbit"); From f73d60cc73db7edd9d42d49729edf5a52163e72f Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 31 Jul 2016 16:28:03 -0400 Subject: [PATCH 44/46] Make scene controls use configurable speed modifier. --- apps/opencs/view/render/worldspacewidget.cpp | 14 +++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 2dfa66a12..dd2ec1bdd 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -44,6 +44,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg , mDragging (false) , mDragX(0) , mDragY(0) + , mSpeedMode(false) , mDragFactor(0) , mDragWheelFactor(0) , mDragShiftFactor(0) @@ -97,8 +98,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg CSMPrefs::get()["Tooltips"].update(); // Shortcuts - CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", this); + CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", "scene-speed-modifier", + CSMPrefs::Shortcut::SM_Detach, this); connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool))); + connect(primaryEditShortcut, SIGNAL(secondary(bool)), this, SLOT(speedMode(bool))); CSMPrefs::Shortcut* secondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this); connect(secondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool))); @@ -602,7 +605,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) double factor = mDragFactor; - if (event->modifiers() & Qt::ShiftModifier) + if (mSpeedMode) factor *= mDragShiftFactor; EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -656,7 +659,7 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { double factor = mDragWheelFactor; - if (event->modifiers() & Qt::ShiftModifier) + if (mSpeedMode) factor *= mDragShiftFactor; EditMode& editMode = dynamic_cast (*mEditMode->getCurrent()); @@ -706,6 +709,11 @@ void CSVRender::WorldspaceWidget::secondarySelect(bool activate) handleInteraction(InteractionType_SecondarySelect, activate); } +void CSVRender::WorldspaceWidget::speedMode(bool activate) +{ + mSpeedMode = activate; +} + void CSVRender::WorldspaceWidget::handleInteraction(InteractionType type, bool activate) { if (activate) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index f3c31f896..b30d7de8a 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -59,6 +59,7 @@ namespace CSVRender bool mDragging; int mDragX; int mDragY; + bool mSpeedMode; double mDragFactor; double mDragWheelFactor; double mDragShiftFactor; @@ -208,6 +209,8 @@ namespace CSVRender EditMode *getEditMode(); + bool getSpeedMode(); + private: void dragEnterEvent(QDragEnterEvent *event); @@ -269,6 +272,8 @@ namespace CSVRender void secondarySelect(bool activate); + void speedMode(bool activate); + protected slots: void elementSelectionChanged(); From 14165352f6734541a2a73d0070dabbe1564bbec2 Mon Sep 17 00:00:00 2001 From: Internecine Date: Mon, 1 Aug 2016 13:16:42 +1200 Subject: [PATCH 45/46] Added exception handlers when trying to retreive enchantment and magic effect data. --- apps/openmw/mwgui/tooltips.cpp | 28 +++++++++++++++++----------- apps/openmw/mwrender/animation.cpp | 22 ++++++++++++++++++++-- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index cb3d0d0a1..2c540807d 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -395,15 +395,22 @@ namespace MWGui const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); if (info.enchant != "") { - enchant = store.get().find(info.enchant); - if (enchant->mData.mType == ESM::Enchantment::CastOnce) - text += "\n#{sItemCastOnce}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) - text += "\n#{sItemCastWhenStrikes}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) - text += "\n#{sItemCastWhenUsed}"; - else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) - text += "\n#{sItemCastConstant}"; + try + { + enchant = store.get().find(info.enchant); + if (enchant->mData.mType == ESM::Enchantment::CastOnce) + text += "\n#{sItemCastOnce}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) + text += "\n#{sItemCastWhenStrikes}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) + text += "\n#{sItemCastWhenUsed}"; + else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) + text += "\n#{sItemCastConstant}"; + } + catch (const std::runtime_error& ex) + { + + } } // this the maximum width of the tooltip before it starts word-wrapping @@ -472,9 +479,8 @@ namespace MWGui totalSize.width = std::max(totalSize.width, coord.width); } - if (info.enchant != "") + if (enchant) { - assert(enchant); MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget("", MyGUI::IntCoord(padding.left, totalSize.height, 300-padding.left, 300-totalSize.height), MyGUI::Align::Stretch); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ddff61ac7..032fc0a35 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1143,10 +1143,28 @@ namespace MWRender std::string enchantmentName = item.getClass().getEnchantment(item); if (enchantmentName.empty()) return result; - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); + + const ESM::Enchantment* enchantment = NULL; + try + { + enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); + } + catch (const std::runtime_error& ex) + { + return result; + } assert (enchantment->mEffects.mList.size()); - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + + const ESM::MagicEffect* magicEffect = NULL; + try + { + magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( enchantment->mEffects.mList.front().mEffectID); + } + catch (const std::runtime_error& ex) + { + return result; + } result.x() = magicEffect->mData.mRed / 255.f; result.y() = magicEffect->mData.mGreen / 255.f; result.z() = magicEffect->mData.mBlue / 255.f; From 90735d226d0766ea6b698d016510265765e9dc2a Mon Sep 17 00:00:00 2001 From: Internecine Date: Tue, 2 Aug 2016 11:43:41 +1200 Subject: [PATCH 46/46] Replaced Store::find usage with Store::search to remove exception handlers. --- apps/openmw/mwgui/tooltips.cpp | 8 ++------ apps/openmw/mwrender/animation.cpp | 22 ++++++---------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2c540807d..9e26cb0f9 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -395,9 +395,9 @@ namespace MWGui const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); if (info.enchant != "") { - try + enchant = store.get().search(info.enchant); + if (enchant) { - enchant = store.get().find(info.enchant); if (enchant->mData.mType == ESM::Enchantment::CastOnce) text += "\n#{sItemCastOnce}"; else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) @@ -407,10 +407,6 @@ namespace MWGui else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) text += "\n#{sItemCastConstant}"; } - catch (const std::runtime_error& ex) - { - - } } // this the maximum width of the tooltip before it starts word-wrapping diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 032fc0a35..fa7542060 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1144,27 +1144,17 @@ namespace MWRender if (enchantmentName.empty()) return result; - const ESM::Enchantment* enchantment = NULL; - try - { - enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); - } - catch (const std::runtime_error& ex) - { + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().search(enchantmentName); + if (!enchantment) return result; - } + assert (enchantment->mEffects.mList.size()); - const ESM::MagicEffect* magicEffect = NULL; - try - { - magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().search( enchantment->mEffects.mList.front().mEffectID); - } - catch (const std::runtime_error& ex) - { + if (!magicEffect) return result; - } + result.x() = magicEffect->mData.mRed / 255.f; result.y() = magicEffect->mData.mGreen / 255.f; result.z() = magicEffect->mData.mBlue / 255.f;