summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacobPalecki <[email protected]>2020-09-08 16:00:05 -0700
committerGitHub <[email protected]>2020-09-08 16:00:05 -0700
commite5461fa84e65d78823d0022339fa2d8864f7e63c (patch)
treeb486ef524c93bfeb29a86403114b6805bf9decf1
parentMerge pull request #19 from JacobPalecki/gainOffset (diff)
parentSave show last mouse value (diff)
downloadrawaccel-e5461fa84e65d78823d0022339fa2d8864f7e63c.tar.xz
rawaccel-e5461fa84e65d78823d0022339fa2d8864f7e63c.zip
Merge pull request #20 from JacobPalecki/GUI
GUI: Add By Component & Anisotropy; Remove Logarithm and Sigmoid; Delete Console; Some Refactoring
-rw-r--r--common/accel-logarithmic.hpp25
-rw-r--r--common/accel-sigmoid.hpp29
-rw-r--r--common/common.vcxitems2
-rw-r--r--common/rawaccel-settings.h2
-rw-r--r--common/rawaccel.hpp8
-rw-r--r--console/console.cpp19
-rw-r--r--console/console.vcxproj100
-rw-r--r--console/external/clipp.h7027
-rw-r--r--console/parse.hpp126
-rw-r--r--grapher/Constants/Constants.cs104
-rw-r--r--grapher/Form1.Designer.cs794
-rw-r--r--grapher/Form1.cs220
-rw-r--r--grapher/Layouts/ClassicLayout.cs14
-rw-r--r--grapher/Layouts/DefaultLayout.cs16
-rw-r--r--grapher/Layouts/LayoutBase.cs102
-rw-r--r--grapher/Layouts/LinearLayout.cs14
-rw-r--r--grapher/Layouts/LogLayout.cs21
-rw-r--r--grapher/Layouts/NaturalGainLayout.cs14
-rw-r--r--grapher/Layouts/NaturalLayout.cs14
-rw-r--r--grapher/Layouts/OffLayout.cs15
-rw-r--r--grapher/Layouts/OptionLayout.cs41
-rw-r--r--grapher/Layouts/PowerLayout.cs14
-rw-r--r--grapher/Layouts/SigmoidGainLayout.cs14
-rw-r--r--grapher/Layouts/SigmoidLayout.cs21
-rw-r--r--grapher/Models/AccelGUI.cs170
-rw-r--r--grapher/Models/AccelGUIFactory.cs303
-rw-r--r--grapher/Models/Calculations/AccelCalculator.cs28
-rw-r--r--grapher/Models/Calculations/AccelChartData.cs14
-rw-r--r--grapher/Models/Calculations/AccelData.cs15
-rw-r--r--grapher/Models/Charts/AccelCharts.cs99
-rw-r--r--grapher/Models/Charts/ChartXY.cs88
-rw-r--r--grapher/Models/Charts/EstimatedPoints.cs13
-rw-r--r--grapher/Models/Fields/Field.cs93
-rw-r--r--grapher/Models/Fields/FieldXY.cs88
-rw-r--r--grapher/Models/Mouse/MouseWatcher.cs20
-rw-r--r--grapher/Models/Mouse/PointData.cs16
-rw-r--r--grapher/Models/Options/AccelOptionSet.cs117
-rw-r--r--grapher/Models/Options/AccelOptions.cs91
-rw-r--r--grapher/Models/Options/AccelTypeOptions.cs281
-rw-r--r--grapher/Models/Options/ActiveValueLabel.cs71
-rw-r--r--grapher/Models/Options/ActiveValueLabelXY.cs95
-rw-r--r--grapher/Models/Options/ApplyOptions.cs255
-rw-r--r--grapher/Models/Options/CapOptions.cs146
-rw-r--r--grapher/Models/Options/IOption.cs23
-rw-r--r--grapher/Models/Options/OffsetOptions.cs78
-rw-r--r--grapher/Models/Options/Option.cs99
-rw-r--r--grapher/Models/Options/OptionBase.cs33
-rw-r--r--grapher/Models/Options/OptionXY.cs84
-rw-r--r--grapher/Models/Serialized/DriverSettings.cs18
-rw-r--r--grapher/Models/Serialized/GUISettings.cs17
-rw-r--r--grapher/Models/Serialized/RawAccelSettings.cs25
-rw-r--r--grapher/Models/Serialized/SettingsManager.cs25
-rw-r--r--grapher/Program.cs3
-rw-r--r--grapher/grapher.csproj11
-rw-r--r--rawaccel.sln7
-rw-r--r--wrapper/wrapper.cpp2
56 files changed, 2867 insertions, 8317 deletions
diff --git a/common/accel-logarithmic.hpp b/common/accel-logarithmic.hpp
deleted file mode 100644
index 1ab0e53..0000000
--- a/common/accel-logarithmic.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-#include "accel-base.hpp"
-
-namespace rawaccel {
-
- /// <summary> Struct to hold logarithmic acceleration implementation. </summary>
- struct logarithmic_impl {
- double accel;
-
- logarithmic_impl(const accel_args& args) : accel(args.accel) {}
-
- inline double operator()(double speed) const {
- //f(x) = log(m*x+1)
- return log(accel * speed + 1);
- }
-
- // incorrect but this style is slated for removal
- inline double legacy_offset(double speed) const { return operator()(speed); }
- };
-
- using accel_logarithmic = additive_accel<logarithmic_impl>;
-}
diff --git a/common/accel-sigmoid.hpp b/common/accel-sigmoid.hpp
deleted file mode 100644
index 239bd9d..0000000
--- a/common/accel-sigmoid.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-#include "accel-base.hpp"
-
-namespace rawaccel {
-
- /// <summary> Struct to hold sigmoid (s-shaped) acceleration implementation. </summary>
- struct sigmoid_impl {
- double rate;
- double limit;
- double midpoint;
-
- sigmoid_impl(const accel_args& args) :
- rate(args.accel), limit(args.limit - 1), midpoint(args.midpoint)
- {}
-
- inline double operator()(double speed) const {
- //f(x) = k/(1+e^(-m(x-c)))
- return limit / (exp(-rate * (speed - midpoint)) + 1);
- }
-
- inline double legacy_offset(double speed) const { return operator()(speed); }
- };
-
- using accel_sigmoid = additive_accel<sigmoid_impl>;
-
-}
diff --git a/common/common.vcxitems b/common/common.vcxitems
index 52d4f8a..2913080 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -17,12 +17,10 @@
<ClInclude Include="$(MSBuildThisFileDirectory)accel-base.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-classic.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-linear.hpp" />
- <ClInclude Include="$(MSBuildThisFileDirectory)accel-logarithmic.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-natural.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-naturalgain.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-noaccel.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-power.hpp" />
- <ClInclude Include="$(MSBuildThisFileDirectory)accel-sigmoid.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-sigmoidgain.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-error.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-io.hpp" />
diff --git a/common/rawaccel-settings.h b/common/rawaccel-settings.h
index b9ff946..12f136d 100644
--- a/common/rawaccel-settings.h
+++ b/common/rawaccel-settings.h
@@ -6,7 +6,7 @@
namespace rawaccel {
enum class accel_mode {
- linear, classic, natural, logarithmic, sigmoid, naturalgain, sigmoidgain, power, noaccel
+ linear, classic, natural, naturalgain, sigmoidgain, power, noaccel
};
struct settings {
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp
index d3a2a03..08ac322 100644
--- a/common/rawaccel.hpp
+++ b/common/rawaccel.hpp
@@ -10,10 +10,8 @@
#include "accel-classic.hpp"
#include "accel-natural.hpp"
#include "accel-naturalgain.hpp"
-#include "accel-logarithmic.hpp"
-#include "accel-sigmoid.hpp"
-#include "accel-sigmoidgain.hpp"
#include "accel-power.hpp"
+#include "accel-sigmoidgain.hpp"
#include "accel-noaccel.hpp"
namespace rawaccel {
@@ -83,8 +81,6 @@ namespace rawaccel {
case accel_mode::linear: return vis(var.u.linear);
case accel_mode::classic: return vis(var.u.classic);
case accel_mode::natural: return vis(var.u.natural);
- case accel_mode::logarithmic: return vis(var.u.logarithmic);
- case accel_mode::sigmoid: return vis(var.u.sigmoid);
case accel_mode::naturalgain: return vis(var.u.naturalgain);
case accel_mode::sigmoidgain: return vis(var.u.sigmoidgain);
case accel_mode::power: return vis(var.u.power);
@@ -99,8 +95,6 @@ namespace rawaccel {
accel_linear linear;
accel_classic classic;
accel_natural natural;
- accel_logarithmic logarithmic;
- accel_sigmoid sigmoid;
accel_naturalgain naturalgain;
accel_sigmoidgain sigmoidgain;
accel_power power;
diff --git a/console/console.cpp b/console/console.cpp
deleted file mode 100644
index f86dfc2..0000000
--- a/console/console.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <iostream>
-
-#include <rawaccel-io.hpp>
-
-#include "parse.hpp"
-
-namespace ra = rawaccel;
-
-int main(int argc, char** argv) {
- try {
- ra::write(ra::parse(argc, argv));
- }
- catch (const std::system_error& e) {
- std::cerr << e.what() << " (" << e.code() << ")\n";
- }
- catch (const std::exception& e) {
- std::cerr << e.what() << '\n';
- }
-}
diff --git a/console/console.vcxproj b/console/console.vcxproj
deleted file mode 100644
index 0f87d94..0000000
--- a/console/console.vcxproj
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>16.0</VCProjectVersion>
- <ProjectGuid>{AB7B3759-B85F-4067-8935-FB4539B41869}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>console</RootNamespace>
- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- <Import Project="..\common\common.vcxitems" Label="Shared" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- <TargetName>rawaccel</TargetName>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- <TargetName>rawaccel</TargetName>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level4</WarningLevel>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <LanguageStandard>stdcpplatest</LanguageStandard>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(SolutionDir)\external</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level4</WarningLevel>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <LanguageStandard>stdcpplatest</LanguageStandard>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(SolutionDir)\external</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup>
- <ClCompile Include="console.cpp" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="parse.hpp" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project> \ No newline at end of file
diff --git a/console/external/clipp.h b/console/external/clipp.h
deleted file mode 100644
index cca1554..0000000
--- a/console/external/clipp.h
+++ /dev/null
@@ -1,7027 +0,0 @@
-/*****************************************************************************
- * ___ _ _ ___ ___
- * | _|| | | | | _ \ _ \ CLIPP - command line interfaces for modern C++
- * | |_ | |_ | | | _/ _/ version 1.2.3
- * |___||___||_| |_| |_| https://github.com/muellan/clipp
- *
- * Licensed under the MIT License <http://opensource.org/licenses/MIT>.
- * Copyright (c) 2017-2018 André Müller <[email protected]>
- *
- * ---------------------------------------------------------------------------
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- *****************************************************************************/
-
-#ifndef AM_CLIPP_H__
-#define AM_CLIPP_H__
-
-#include <cstring>
-#include <string>
-#include <cstdlib>
-#include <cstring>
-#include <cctype>
-#include <memory>
-#include <vector>
-#include <limits>
-#include <stack>
-#include <algorithm>
-#include <sstream>
-#include <utility>
-#include <iterator>
-#include <functional>
-
-
-/*************************************************************************//**
- *
- * @brief primary namespace
- *
- *****************************************************************************/
-namespace clipp {
-
-
-
-/*****************************************************************************
- *
- * basic constants and datatype definitions
- *
- *****************************************************************************/
-using arg_index = int;
-
-using arg_string = std::string;
-using doc_string = std::string;
-
-using arg_list = std::vector<arg_string>;
-
-
-
-/*************************************************************************//**
- *
- * @brief tristate
- *
- *****************************************************************************/
-enum class tri : char { no, yes, either };
-
-inline constexpr bool operator == (tri t, bool b) noexcept {
- return b ? t != tri::no : t != tri::yes;
-}
-inline constexpr bool operator == (bool b, tri t) noexcept { return (t == b); }
-inline constexpr bool operator != (tri t, bool b) noexcept { return !(t == b); }
-inline constexpr bool operator != (bool b, tri t) noexcept { return !(t == b); }
-
-
-
-/*************************************************************************//**
- *
- * @brief (start,size) index range
- *
- *****************************************************************************/
-class subrange {
-public:
- using size_type = arg_string::size_type;
-
- /** @brief default: no match */
- explicit constexpr
- subrange() noexcept :
- at_{arg_string::npos}, length_{0}
- {}
-
- /** @brief match length & position within subject string */
- explicit constexpr
- subrange(size_type pos, size_type len) noexcept :
- at_{pos}, length_{len}
- {}
-
- /** @brief position of the match within the subject string */
- constexpr size_type at() const noexcept { return at_; }
- /** @brief length of the matching subsequence */
- constexpr size_type length() const noexcept { return length_; }
-
- /** @brief returns true, if query string is a prefix of the subject string */
- constexpr bool prefix() const noexcept {
- return at_ == 0;
- }
-
- /** @brief returns true, if query is a substring of the query string */
- constexpr explicit operator bool () const noexcept {
- return at_ != arg_string::npos;
- }
-
-private:
- size_type at_;
- size_type length_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief match predicates
- *
- *****************************************************************************/
-using match_predicate = std::function<bool(const arg_string&)>;
-using match_function = std::function<subrange(const arg_string&)>;
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief type traits (NOT FOR DIRECT USE IN CLIENT CODE!)
- * no interface guarantees; might be changed or removed in the future
- *
- *****************************************************************************/
-namespace traits {
-
-/*************************************************************************//**
- *
- * @brief function (class) signature type trait
- *
- *****************************************************************************/
-template<class Fn, class Ret, class... Args>
-constexpr auto
-check_is_callable(int) -> decltype(
- std::declval<Fn>()(std::declval<Args>()...),
- std::integral_constant<bool,
- std::is_same<Ret, std::invoke_result_t<Fn, Args...>>::value>{} );
-
-template<class,class,class...>
-constexpr auto
-check_is_callable(long) -> std::false_type;
-
-template<class Fn, class Ret>
-constexpr auto
-check_is_callable_without_arg(int) -> decltype(
- std::declval<Fn>()(),
- std::integral_constant<bool,
- std::is_same<Ret, std::invoke_result_t<Fn>>::value>{} );
-
-template<class,class>
-constexpr auto
-check_is_callable_without_arg(long) -> std::false_type;
-
-
-
-template<class Fn, class... Args>
-constexpr auto
-check_is_void_callable(int) -> decltype(
- std::declval<Fn>()(std::declval<Args>()...), std::true_type{});
-
-template<class,class,class...>
-constexpr auto
-check_is_void_callable(long) -> std::false_type;
-
-template<class Fn>
-constexpr auto
-check_is_void_callable_without_arg(int) -> decltype(
- std::declval<Fn>()(), std::true_type{});
-
-template<class>
-constexpr auto
-check_is_void_callable_without_arg(long) -> std::false_type;
-
-
-
-template<class Fn, class Ret>
-struct is_callable;
-
-
-template<class Fn, class Ret, class... Args>
-struct is_callable<Fn, Ret(Args...)> :
- decltype(check_is_callable<Fn,Ret,Args...>(0))
-{};
-
-template<class Fn, class Ret>
-struct is_callable<Fn,Ret()> :
- decltype(check_is_callable_without_arg<Fn,Ret>(0))
-{};
-
-
-template<class Fn, class... Args>
-struct is_callable<Fn, void(Args...)> :
- decltype(check_is_void_callable<Fn,Args...>(0))
-{};
-
-template<class Fn>
-struct is_callable<Fn,void()> :
- decltype(check_is_void_callable_without_arg<Fn>(0))
-{};
-
-
-
-/*************************************************************************//**
- *
- * @brief input range type trait
- *
- *****************************************************************************/
-template<class T>
-constexpr auto
-check_is_input_range(int) -> decltype(
- begin(std::declval<T>()), end(std::declval<T>()),
- std::true_type{});
-
-template<class T>
-constexpr auto
-check_is_input_range(char) -> decltype(
- std::begin(std::declval<T>()), std::end(std::declval<T>()),
- std::true_type{});
-
-template<class>
-constexpr auto
-check_is_input_range(long) -> std::false_type;
-
-template<class T>
-struct is_input_range :
- decltype(check_is_input_range<T>(0))
-{};
-
-
-
-/*************************************************************************//**
- *
- * @brief size() member type trait
- *
- *****************************************************************************/
-template<class T>
-constexpr auto
-check_has_size_getter(int) ->
- decltype(std::declval<T>().size(), std::true_type{});
-
-template<class>
-constexpr auto
-check_has_size_getter(long) -> std::false_type;
-
-template<class T>
-struct has_size_getter :
- decltype(check_has_size_getter<T>(0))
-{};
-
-} // namespace traits
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!)
- * no interface guarantees; might be changed or removed in the future
- *
- *****************************************************************************/
-namespace detail {
-
-
-/*************************************************************************//**
- * @brief forwards string to first non-whitespace char;
- * std string -> unsigned conv yields max value, but we want 0;
- * also checks for nullptr
- *****************************************************************************/
-inline bool
-fwd_to_unsigned_int(const char*& s)
-{
- if(!s) return false;
- for(; std::isspace(*s); ++s);
- if(!s[0] || s[0] == '-') return false;
- if(s[0] == '-') return false;
- return true;
-}
-
-
-/*************************************************************************//**
- *
- * @brief value limits clamping
- *
- *****************************************************************************/
-template<class T, class V, bool = (sizeof(V) > sizeof(T))>
-struct limits_clamped {
- static T from(const V& v) {
- if(v >= V(std::numeric_limits<T>::max())) {
- return std::numeric_limits<T>::max();
- }
- if(v <= V(std::numeric_limits<T>::lowest())) {
- return std::numeric_limits<T>::lowest();
- }
- return T(v);
- }
-};
-
-template<class T, class V>
-struct limits_clamped<T,V,false> {
- static T from(const V& v) { return T(v); }
-};
-
-
-/*************************************************************************//**
- *
- * @brief returns value of v as a T, clamped at T's maximum
- *
- *****************************************************************************/
-template<class T, class V>
-inline T clamped_on_limits(const V& v) {
- return limits_clamped<T,V>::from(v);
-}
-
-
-
-
-/*************************************************************************//**
- *
- * @brief type conversion helpers
- *
- *****************************************************************************/
-template<class T>
-struct make {
- static inline T from(const char* s) {
- if(!s) return false;
- //a conversion from const char* to / must exist
- return static_cast<T>(s);
- }
-};
-
-template<>
-struct make<bool> {
- static inline bool from(const char* s) {
- if(!s) return false;
- return static_cast<bool>(s);
- }
-};
-
-template<>
-struct make<unsigned char> {
- static inline unsigned char from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits<unsigned char>(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make<unsigned short int> {
- static inline unsigned short int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits<unsigned short int>(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make<unsigned int> {
- static inline unsigned int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits<unsigned int>(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make<unsigned long int> {
- static inline unsigned long int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits<unsigned long int>(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make<unsigned long long int> {
- static inline unsigned long long int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits<unsigned long long int>(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make<char> {
- static inline char from(const char* s) {
- //parse as single character?
- const auto n = std::strlen(s);
- if(n == 1) return s[0];
- //parse as integer
- return clamped_on_limits<char>(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make<short int> {
- static inline short int from(const char* s) {
- return clamped_on_limits<short int>(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make<int> {
- static inline int from(const char* s) {
- return clamped_on_limits<int>(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make<long int> {
- static inline long int from(const char* s) {
- return clamped_on_limits<long int>(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make<long long int> {
- static inline long long int from(const char* s) {
- return (std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make<float> {
- static inline float from(const char* s) {
- return (std::strtof(s,nullptr));
- }
-};
-
-template<>
-struct make<double> {
- static inline double from(const char* s) {
- return (std::strtod(s,nullptr));
- }
-};
-
-template<>
-struct make<long double> {
- static inline long double from(const char* s) {
- return (std::strtold(s,nullptr));
- }
-};
-
-template<>
-struct make<std::string> {
- static inline std::string from(const char* s) {
- return std::string(s);
- }
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief assigns boolean constant to one or multiple target objects
- *
- *****************************************************************************/
-template<class T, class V = T>
-class assign_value
-{
-public:
- template<class X>
- explicit constexpr
- assign_value(T& target, X&& value) noexcept :
- t_{std::addressof(target)}, v_{std::forward<X>(value)}
- {}
-
- void operator () () const {
- if(t_) *t_ = v_;
- }
-
-private:
- T* t_;
- V v_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief flips bools
- *
- *****************************************************************************/
-class flip_bool
-{
-public:
- explicit constexpr
- flip_bool(bool& target) noexcept :
- b_{&target}
- {}
-
- void operator () () const {
- if(b_) *b_ = !*b_;
- }
-
-private:
- bool* b_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief increments using operator ++
- *
- *****************************************************************************/
-template<class T>
-class increment
-{
-public:
- explicit constexpr
- increment(T& target) noexcept : t_{std::addressof(target)} {}
-
- void operator () () const {
- if(t_) ++(*t_);
- }
-
-private:
- T* t_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief decrements using operator --
- *
- *****************************************************************************/
-template<class T>
-class decrement
-{
-public:
- explicit constexpr
- decrement(T& target) noexcept : t_{std::addressof(target)} {}
-
- void operator () () const {
- if(t_) --(*t_);
- }
-
-private:
- T* t_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief increments by a fixed amount using operator +=
- *
- *****************************************************************************/
-template<class T>
-class increment_by
-{
-public:
- explicit constexpr
- increment_by(T& target, T by) noexcept :
- t_{std::addressof(target)}, by_{std::move(by)}
- {}
-
- void operator () () const {
- if(t_) (*t_) += by_;
- }
-
-private:
- T* t_;
- T by_;
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a value from a string and assigns it to an object
- *
- *****************************************************************************/
-template<class T>
-class map_arg_to
-{
-public:
- explicit constexpr
- map_arg_to(T& target) noexcept : t_{std::addressof(target)} {}
-
- void operator () (const char* s) const {
- if(t_ && s) *t_ = detail::make<T>::from(s);
- }
-
-private:
- T* t_;
-};
-
-
-//-------------------------------------------------------------------
-/**
- * @brief specialization for vectors: append element
- */
-template<class T>
-class map_arg_to<std::vector<T>>
-{
-public:
- map_arg_to(std::vector<T>& target): t_{std::addressof(target)} {}
-
- void operator () (const char* s) const {
- if(t_ && s) t_->push_back(detail::make<T>::from(s));
- }
-
-private:
- std::vector<T>* t_;
-};
-
-
-//-------------------------------------------------------------------
-/**
- * @brief specialization for bools:
- * set to true regardless of string content
- */
-template<>
-class map_arg_to<bool>
-{
-public:
- map_arg_to(bool& target): t_{&target} {}
-
- void operator () (const char* s) const {
- if(t_ && s) *t_ = true;
- }
-
-private:
- bool* t_;
-};
-
-
-} // namespace detail
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief string matching and processing tools
- *
- *****************************************************************************/
-
-namespace str {
-
-
-/*************************************************************************//**
- *
- * @brief converts string to value of target type 'T'
- *
- *****************************************************************************/
-template<class T>
-T make(const arg_string& s)
-{
- return detail::make<T>::from(s);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief removes trailing whitespace from string
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline void
-trimr(std::basic_string<C,T,A>& s)
-{
- if(s.empty()) return;
-
- s.erase(
- std::find_if_not(s.rbegin(), s.rend(),
- [](char c) { return std::isspace(c);} ).base(),
- s.end() );
-}
-
-
-/*************************************************************************//**
- *
- * @brief removes leading whitespace from string
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline void
-triml(std::basic_string<C,T,A>& s)
-{
- if(s.empty()) return;
-
- s.erase(
- s.begin(),
- std::find_if_not(s.begin(), s.end(),
- [](char c) { return std::isspace(c);})
- );
-}
-
-
-/*************************************************************************//**
- *
- * @brief removes leading and trailing whitespace from string
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline void
-trim(std::basic_string<C,T,A>& s)
-{
- triml(s);
- trimr(s);
-}
-
-
-/*************************************************************************//**
- *
- * @brief removes all whitespaces from string
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline void
-remove_ws(std::basic_string<C,T,A>& s)
-{
- if(s.empty()) return;
-
- s.erase(std::remove_if(s.begin(), s.end(),
- [](char c) { return std::isspace(c); }),
- s.end() );
-}
-
-
-/*************************************************************************//**
- *
- * @brief returns true, if the 'prefix' argument
- * is a prefix of the 'subject' argument
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline bool
-has_prefix(const std::basic_string<C,T,A>& subject,
- const std::basic_string<C,T,A>& prefix)
-{
- if(prefix.size() > subject.size()) return false;
- return subject.find(prefix) == 0;
-}
-
-
-/*************************************************************************//**
- *
- * @brief returns true, if the 'postfix' argument
- * is a postfix of the 'subject' argument
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline bool
-has_postfix(const std::basic_string<C,T,A>& subject,
- const std::basic_string<C,T,A>& postfix)
-{
- if(postfix.size() > subject.size()) return false;
- return (subject.size() - postfix.size()) == subject.find(postfix);
-}
-
-
-
-/*************************************************************************//**
-*
-* @brief returns longest common prefix of several
-* sequential random access containers
-*
-* @details InputRange require begin and end (member functions or overloads)
-* the elements of InputRange require a size() member
-*
-*****************************************************************************/
-template<class InputRange>
-auto
-longest_common_prefix(const InputRange& strs)
- -> typename std::decay<decltype(*begin(strs))>::type
-{
- static_assert(traits::is_input_range<InputRange>(),
- "parameter must satisfy the InputRange concept");
-
- static_assert(traits::has_size_getter<
- typename std::decay<decltype(*begin(strs))>::type>(),
- "elements of input range must have a ::size() member function");
-
- using std::begin;
- using std::end;
-
- using item_t = typename std::decay<decltype(*begin(strs))>::type;
- using str_size_t = typename std::decay<decltype(begin(strs)->size())>::type;
-
- const auto n = size_t(distance(begin(strs), end(strs)));
- if(n < 1) return item_t("");
- if(n == 1) return *begin(strs);
-
- //length of shortest string
- auto m = std::min_element(begin(strs), end(strs),
- [](const item_t& a, const item_t& b) {
- return a.size() < b.size(); })->size();
-
- //check each character until we find a mismatch
- for(str_size_t i = 0; i < m; ++i) {
- for(str_size_t j = 1; j < n; ++j) {
- if(strs[j][i] != strs[j-1][i])
- return strs[0].substr(0, i);
- }
- }
- return strs[0].substr(0, m);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns longest substring range that could be found in 'arg'
- *
- * @param arg string to be searched in
- * @param substrings range of candidate substrings
- *
- *****************************************************************************/
-template<class C, class T, class A, class InputRange>
-subrange
-longest_substring_match(const std::basic_string<C,T,A>& arg,
- const InputRange& substrings)
-{
- using string_t = std::basic_string<C,T,A>;
-
- static_assert(traits::is_input_range<InputRange>(),
- "parameter must satisfy the InputRange concept");
-
- static_assert(std::is_same<string_t,
- typename std::decay<decltype(*begin(substrings))>::type>(),
- "substrings must have same type as 'arg'");
-
- auto i = string_t::npos;
- auto n = string_t::size_type(0);
- for(const auto& s : substrings) {
- auto j = arg.find(s);
- if(j != string_t::npos && s.size() > n) {
- i = j;
- n = s.size();
- }
- }
- return subrange{i,n};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns longest prefix range that could be found in 'arg'
- *
- * @param arg string to be searched in
- * @param prefixes range of candidate prefix strings
- *
- *****************************************************************************/
-template<class C, class T, class A, class InputRange>
-subrange
-longest_prefix_match(const std::basic_string<C,T,A>& arg,
- const InputRange& prefixes)
-{
- using string_t = std::basic_string<C,T,A>;
- using s_size_t = typename string_t::size_type;
-
- static_assert(traits::is_input_range<InputRange>(),
- "parameter must satisfy the InputRange concept");
-
- static_assert(std::is_same<string_t,
- typename std::decay<decltype(*begin(prefixes))>::type>(),
- "prefixes must have same type as 'arg'");
-
- auto i = string_t::npos;
- auto n = s_size_t(0);
- for(const auto& s : prefixes) {
- auto j = arg.find(s);
- if(j == 0 && s.size() > n) {
- i = 0;
- n = s.size();
- }
- }
- return subrange{i,n};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns the first occurrence of 'query' within 'subject'
- *
- *****************************************************************************/
-template<class C, class T, class A>
-inline subrange
-substring_match(const std::basic_string<C,T,A>& subject,
- const std::basic_string<C,T,A>& query)
-{
- if(subject.empty() && query.empty()) return subrange(0,0);
- if(subject.empty() || query.empty()) return subrange{};
- auto i = subject.find(query);
- if(i == std::basic_string<C,T,A>::npos) return subrange{};
- return subrange{i,query.size()};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns first substring match (pos,len) within the input string
- * that represents a number
- * (with at maximum one decimal point and digit separators)
- *
- *****************************************************************************/
-template<class C, class T, class A>
-subrange
-first_number_match(std::basic_string<C,T,A> s,
- C digitSeparator = C(','),
- C decimalPoint = C('.'),
- C exponential = C('e'))
-{
- using string_t = std::basic_string<C,T,A>;
- str::trim(s);
- if(s.empty()) return subrange{};
-
- //auto i = s.find_first_of("0123456789+-");
- //if(i == string_t::npos) {
- // i = s.find(decimalPoint);
- // if(i == string_t::npos) return subrange{};
- //}
- //bool point = false;
-
- // overwritten to match numbers without leading 0,
- // also commented out call to sanitize_args in parse
- auto i = s.find_first_of("0123456789+-.");
- if (i == string_t::npos) return subrange{};
- bool point = s[i] == decimalPoint;
-
- bool sep = false;
- auto exp = string_t::npos;
- auto j = i + 1;
- for(; j < s.size(); ++j) {
- if(s[j] == digitSeparator) {
- if(!sep) sep = true; else break;
- }
- else {
- sep = false;
- if(s[j] == decimalPoint) {
- //only one decimal point before exponent allowed
- if(!point && exp == string_t::npos) point = true; else break;
- }
- else if(std::tolower(s[j]) == std::tolower(exponential)) {
- //only one exponent separator allowed
- if(exp == string_t::npos) exp = j; else break;
- }
- else if(exp != string_t::npos && (exp+1) == j) {
- //only sign or digit after exponent separator
- if(s[j] != '+' && s[j] != '-' && !std::isdigit(s[j])) break;
- }
- else if(!std::isdigit(s[j])) {
- break;
- }
- }
- }
-
- //if length == 1 then must be a digit
- if(j-i == 1 && !std::isdigit(s[i])) return subrange{};
-
- return subrange{i,j-i};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns first substring match (pos,len)
- * that represents an integer (with optional digit separators)
- *
- *****************************************************************************/
-template<class C, class T, class A>
-subrange
-first_integer_match(std::basic_string<C,T,A> s,
- C digitSeparator = C(','))
-{
- using string_t = std::basic_string<C,T,A>;
- str::trim(s);
- if(s.empty()) return subrange{};
-
- auto i = s.find_first_of("0123456789+-");
- if(i == string_t::npos) return subrange{};
-
- bool sep = false;
- auto j = i + 1;
- for(; j < s.size(); ++j) {
- if(s[j] == digitSeparator) {
- if(!sep) sep = true; else break;
- }
- else {
- sep = false;
- if(!std::isdigit(s[j])) break;
- }
- }
-
- //if length == 1 then must be a digit
- if(j-i == 1 && !std::isdigit(s[i])) return subrange{};
-
- return subrange{i,j-i};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns true if candidate string represents a number
- *
- *****************************************************************************/
-template<class C, class T, class A>
-bool represents_number(const std::basic_string<C,T,A>& candidate,
- C digitSeparator = C(','),
- C decimalPoint = C('.'),
- C exponential = C('e'))
-{
- const auto match = str::first_number_match(candidate, digitSeparator,
- decimalPoint, exponential);
-
- return (match && match.length() == candidate.size());
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns true if candidate string represents an integer
- *
- *****************************************************************************/
-template<class C, class T, class A>
-bool represents_integer(const std::basic_string<C,T,A>& candidate,
- C digitSeparator = C(','))
-{
- const auto match = str::first_integer_match(candidate, digitSeparator);
- return (match && match.length() == candidate.size());
-}
-
-} // namespace str
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes function object with a const char* parameter
- * that assigns a value to a ref-captured object
- *
- *****************************************************************************/
-template<class T, class V>
-inline detail::assign_value<T,V>
-set(T& target, V value) {
- return detail::assign_value<T>{target, std::move(value)};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes parameter-less function object
- * that assigns value(s) to a ref-captured object;
- * value(s) are obtained by converting the const char* argument to
- * the captured object types;
- * bools are always set to true if the argument is not nullptr
- *
- *****************************************************************************/
-template<class T>
-inline detail::map_arg_to<T>
-set(T& target) {
- return detail::map_arg_to<T>{target};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes function object that sets a bool to true
- *
- *****************************************************************************/
-inline detail::assign_value<bool>
-set(bool& target) {
- return detail::assign_value<bool>{target,true};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that sets a bool to false
- *
- *****************************************************************************/
-inline detail::assign_value<bool>
-unset(bool& target) {
- return detail::assign_value<bool>{target,false};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that flips the value of a ref-captured bool
- *
- *****************************************************************************/
-inline detail::flip_bool
-flip(bool& b) {
- return detail::flip_bool(b);
-}
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes function object that increments using operator ++
- *
- *****************************************************************************/
-template<class T>
-inline detail::increment<T>
-increment(T& target) {
- return detail::increment<T>{target};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that decrements using operator --
- *
- *****************************************************************************/
-template<class T>
-inline detail::increment_by<T>
-increment(T& target, T by) {
- return detail::increment_by<T>{target, std::move(by)};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that increments by a fixed amount using operator +=
- *
- *****************************************************************************/
-template<class T>
-inline detail::decrement<T>
-decrement(T& target) {
- return detail::decrement<T>{target};
-}
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!)
- *
- *****************************************************************************/
-namespace detail {
-
-
-/*************************************************************************//**
- *
- * @brief mixin that provides action definition and execution
- *
- *****************************************************************************/
-template<class Derived>
-class action_provider
-{
-private:
- //---------------------------------------------------------------
- using simple_action = std::function<void()>;
- using arg_action = std::function<void(const char*)>;
- using index_action = std::function<void(int)>;
-
- //-----------------------------------------------------
- class simple_action_adapter {
- public:
- simple_action_adapter() = default;
- simple_action_adapter(const simple_action& a): action_(a) {}
- simple_action_adapter(simple_action&& a): action_(std::move(a)) {}
- void operator() (const char*) const { action_(); }
- void operator() (int) const { action_(); }
- private:
- simple_action action_;
- };
-
-
-public:
- //---------------------------------------------------------------
- /** @brief adds an action that has an operator() that is callable
- * with a 'const char*' argument */
- Derived&
- call(arg_action a) {
- argActions_.push_back(std::move(a));
- return *static_cast<Derived*>(this);
- }
-
- /** @brief adds an action that has an operator()() */
- Derived&
- call(simple_action a) {
- argActions_.push_back(simple_action_adapter(std::move(a)));
- return *static_cast<Derived*>(this);
- }
-
- /** @brief adds an action that has an operator() that is callable
- * with a 'const char*' argument */
- Derived& operator () (arg_action a) { return call(std::move(a)); }
-
- /** @brief adds an action that has an operator()() */
- Derived& operator () (simple_action a) { return call(std::move(a)); }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will set the value of 't' from
- * a 'const char*' arg */
- template<class Target>
- Derived&
- set(Target& t) {
- static_assert(!std::is_pointer<Target>::value,
- "parameter target type must not be a pointer");
-
- return call(clipp::set(t));
- }
-
- /** @brief adds an action that will set the value of 't' to 'v' */
- template<class Target, class Value>
- Derived&
- set(Target& t, Value&& v) {
- return call(clipp::set(t, std::forward<Value>(v)));
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a parameter
- * matches an argument for the 2nd, 3rd, 4th, ... time
- */
- Derived&
- if_repeated(simple_action a) {
- repeatActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast<Derived*>(this);
- }
- /** @brief adds an action that will be called with the argument's
- * index if a parameter matches an argument for
- * the 2nd, 3rd, 4th, ... time
- */
- Derived&
- if_repeated(index_action a) {
- repeatActions_.push_back(std::move(a));
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a required parameter
- * is missing
- */
- Derived&
- if_missing(simple_action a) {
- missingActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast<Derived*>(this);
- }
- /** @brief adds an action that will be called if a required parameter
- * is missing; the action will get called with the index of
- * the command line argument where the missing event occurred first
- */
- Derived&
- if_missing(index_action a) {
- missingActions_.push_back(std::move(a));
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a parameter
- * was matched, but was unreachable in the current scope
- */
- Derived&
- if_blocked(simple_action a) {
- blockedActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast<Derived*>(this);
- }
- /** @brief adds an action that will be called if a parameter
- * was matched, but was unreachable in the current scope;
- * the action will be called with the index of
- * the command line argument where the problem occurred
- */
- Derived&
- if_blocked(index_action a) {
- blockedActions_.push_back(std::move(a));
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a parameter match
- * was in conflict with a different alternative parameter
- */
- Derived&
- if_conflicted(simple_action a) {
- conflictActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast<Derived*>(this);
- }
- /** @brief adds an action that will be called if a parameter match
- * was in conflict with a different alternative parameter;
- * the action will be called with the index of
- * the command line argument where the problem occurred
- */
- Derived&
- if_conflicted(index_action a) {
- conflictActions_.push_back(std::move(a));
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds targets = either objects whose values should be
- * set by command line arguments or actions that should
- * be called in case of a match */
- template<class T, class... Ts>
- Derived&
- target(T&& t, Ts&&... ts) {
- target(std::forward<T>(t));
- target(std::forward<Ts>(ts)...);
- return *static_cast<Derived*>(this);
- }
-
- /** @brief adds action that should be called in case of a match */
- template<class T, class = typename std::enable_if<
- !std::is_fundamental<typename std::decay<T>::type>() &&
- (traits::is_callable<T,void()>() ||
- traits::is_callable<T,void(const char*)>() )
- >::type>
- Derived&
- target(T&& t) {
- call(std::forward<T>(t));
- return *static_cast<Derived*>(this);
- }
-
- /** @brief adds object whose value should be set by command line arguments
- */
- template<class T, class = typename std::enable_if<
- std::is_fundamental<typename std::decay<T>::type>() ||
- (!traits::is_callable<T,void()>() &&
- !traits::is_callable<T,void(const char*)>() )
- >::type>
- Derived&
- target(T& t) {
- set(t);
- return *static_cast<Derived*>(this);
- }
-
- //TODO remove ugly empty param list overload
- Derived&
- target() {
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds target, see member function 'target' */
- template<class Target>
- inline friend Derived&
- operator << (Target&& t, Derived& p) {
- p.target(std::forward<Target>(t));
- return p;
- }
- /** @brief adds target, see member function 'target' */
- template<class Target>
- inline friend Derived&&
- operator << (Target&& t, Derived&& p) {
- p.target(std::forward<Target>(t));
- return std::move(p);
- }
-
- //-----------------------------------------------------
- /** @brief adds target, see member function 'target' */
- template<class Target>
- inline friend Derived&
- operator >> (Derived& p, Target&& t) {
- p.target(std::forward<Target>(t));
- return p;
- }
- /** @brief adds target, see member function 'target' */
- template<class Target>
- inline friend Derived&&
- operator >> (Derived&& p, Target&& t) {
- p.target(std::forward<Target>(t));
- return std::move(p);
- }
-
-
- //---------------------------------------------------------------
- /** @brief executes all argument actions */
- void execute_actions(const arg_string& arg) const {
- int i = 0;
- for(const auto& a : argActions_) {
- ++i;
- a(arg.c_str());
- }
- }
-
- /** @brief executes repeat actions */
- void notify_repeated(arg_index idx) const {
- for(const auto& a : repeatActions_) a(idx);
- }
- /** @brief executes missing error actions */
- void notify_missing(arg_index idx) const {
- for(const auto& a : missingActions_) a(idx);
- }
- /** @brief executes blocked error actions */
- void notify_blocked(arg_index idx) const {
- for(const auto& a : blockedActions_) a(idx);
- }
- /** @brief executes conflict error actions */
- void notify_conflict(arg_index idx) const {
- for(const auto& a : conflictActions_) a(idx);
- }
-
-private:
- //---------------------------------------------------------------
- std::vector<arg_action> argActions_;
- std::vector<index_action> repeatActions_;
- std::vector<index_action> missingActions_;
- std::vector<index_action> blockedActions_;
- std::vector<index_action> conflictActions_;
-};
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief mixin that provides basic common settings of parameters and groups
- *
- *****************************************************************************/
-template<class Derived>
-class token
-{
-public:
- //---------------------------------------------------------------
- using doc_string = clipp::doc_string;
-
-
- //---------------------------------------------------------------
- /** @brief returns documentation string */
- const doc_string& doc() const noexcept {
- return doc_;
- }
-
- /** @brief sets documentations string */
- Derived& doc(const doc_string& txt) {
- doc_ = txt;
- return *static_cast<Derived*>(this);
- }
-
- /** @brief sets documentations string */
- Derived& doc(doc_string&& txt) {
- doc_ = std::move(txt);
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if a group/parameter is repeatable */
- bool repeatable() const noexcept {
- return repeatable_;
- }
-
- /** @brief sets repeatability of group/parameter */
- Derived& repeatable(bool yes) noexcept {
- repeatable_ = yes;
- return *static_cast<Derived*>(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if a group/parameter is blocking/positional */
- bool blocking() const noexcept {
- return blocking_;
- }
-
- /** @brief determines, if a group/parameter is blocking/positional */
- Derived& blocking(bool yes) noexcept {
- blocking_ = yes;
- return *static_cast<Derived*>(this);
- }
-
-
-private:
- //---------------------------------------------------------------
- doc_string doc_;
- bool repeatable_ = false;
- bool blocking_ = false;
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief sets documentation strings on a token
- *
- *****************************************************************************/
-template<class T>
-inline T&
-operator % (doc_string docstr, token<T>& p)
-{
- return p.doc(std::move(docstr));
-}
-//---------------------------------------------------------
-template<class T>
-inline T&&
-operator % (doc_string docstr, token<T>&& p)
-{
- return std::move(p.doc(std::move(docstr)));
-}
-
-//---------------------------------------------------------
-template<class T>
-inline T&
-operator % (token<T>& p, doc_string docstr)
-{
- return p.doc(std::move(docstr));
-}
-//---------------------------------------------------------
-template<class T>
-inline T&&
-operator % (token<T>&& p, doc_string docstr)
-{
- return std::move(p.doc(std::move(docstr)));
-}
-
-
-
-
-/*************************************************************************//**
- *
- * @brief sets documentation strings on a token
- *
- *****************************************************************************/
-template<class T>
-inline T&
-doc(doc_string docstr, token<T>& p)
-{
- return p.doc(std::move(docstr));
-}
-//---------------------------------------------------------
-template<class T>
-inline T&&
-doc(doc_string docstr, token<T>&& p)
-{
- return std::move(p.doc(std::move(docstr)));
-}
-
-
-
-} // namespace detail
-
-
-
-/*************************************************************************//**
- *
- * @brief contains parameter matching functions and function classes
- *
- *****************************************************************************/
-namespace match {
-
-
-/*************************************************************************//**
- *
- * @brief predicate that is always true
- *
- *****************************************************************************/
-inline bool
-any(const arg_string&) { return true; }
-
-/*************************************************************************//**
- *
- * @brief predicate that is always false
- *
- *****************************************************************************/
-inline bool
-none(const arg_string&) { return false; }
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the argument string is non-empty string
- *
- *****************************************************************************/
-inline bool
-nonempty(const arg_string& s) {
- return !s.empty();
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the argument is a non-empty
- * string that consists only of alphanumeric characters
- *
- *****************************************************************************/
-inline bool
-alphanumeric(const arg_string& s) {
- if(s.empty()) return false;
- return std::all_of(s.begin(), s.end(), [](char c) {return std::isalnum(c); });
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the argument is a non-empty
- * string that consists only of alphabetic characters
- *
- *****************************************************************************/
-inline bool
-alphabetic(const arg_string& s) {
- return std::all_of(s.begin(), s.end(), [](char c) {return std::isalpha(c); });
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns false if the argument string is
- * equal to any string from the exclusion list
- *
- *****************************************************************************/
-class none_of
-{
-public:
- none_of(arg_list strs):
- excluded_{std::move(strs)}
- {}
-
- template<class... Strings>
- none_of(arg_string str, Strings&&... strs):
- excluded_{std::move(str), std::forward<Strings>(strs)...}
- {}
-
- template<class... Strings>
- none_of(const char* str, Strings&&... strs):
- excluded_{arg_string(str), std::forward<Strings>(strs)...}
- {}
-
- bool operator () (const arg_string& arg) const {
- return (std::find(begin(excluded_), end(excluded_), arg)
- == end(excluded_));
- }
-
-private:
- arg_list excluded_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns the first substring match within the input
- * string that rmeepresents a number
- * (with at maximum one decimal point and digit separators)
- *
- *****************************************************************************/
-class numbers
-{
-public:
- explicit
- numbers(char decimalPoint = '.',
- char digitSeparator = ' ',
- char exponentSeparator = 'e')
- :
- decpoint_{decimalPoint}, separator_{digitSeparator},
- exp_{exponentSeparator}
- {}
-
- subrange operator () (const arg_string& s) const {
- return str::first_number_match(s, separator_, decpoint_, exp_);
- }
-
-private:
- char decpoint_;
- char separator_;
- char exp_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string represents an integer
- * (with optional digit separators)
- *
- *****************************************************************************/
-class integers {
-public:
- explicit
- integers(char digitSeparator = ' '): separator_{digitSeparator} {}
-
- subrange operator () (const arg_string& s) const {
- return str::first_integer_match(s, separator_);
- }
-
-private:
- char separator_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string represents
- * a non-negative integer (with optional digit separators)
- *
- *****************************************************************************/
-class positive_integers {
-public:
- explicit
- positive_integers(char digitSeparator = ' ') : separator_{ digitSeparator } {}
- subrange operator () (const arg_string& s) const {
- auto match = str::first_integer_match(s, separator_);
- if(!match) return subrange{};
- if(s[match.at()] == '-') return subrange{};
- return match;
- }
-
-private:
- char separator_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string
- * contains a given substring
- *
- *****************************************************************************/
-class substring
-{
-public:
- explicit
- substring(arg_string str): str_{std::move(str)} {}
-
- subrange operator () (const arg_string& s) const {
- return str::substring_match(s, str_);
- }
-
-private:
- arg_string str_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string starts
- * with a given prefix
- *
- *****************************************************************************/
-class prefix {
-public:
- explicit
- prefix(arg_string p): prefix_{std::move(p)} {}
-
- bool operator () (const arg_string& s) const {
- return s.find(prefix_) == 0;
- }
-
-private:
- arg_string prefix_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string does not start
- * with a given prefix
- *
- *****************************************************************************/
-class prefix_not {
-public:
- explicit
- prefix_not(arg_string p): prefix_{std::move(p)} {}
-
- bool operator () (const arg_string& s) const {
- return s.find(prefix_) != 0;
- }
-
-private:
- arg_string prefix_;
-};
-
-
-/** @brief alias for prefix_not */
-using noprefix = prefix_not;
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the length of the input string
- * is wihtin a given interval
- *
- *****************************************************************************/
-class length {
-public:
- explicit
- length(std::size_t exact):
- min_{exact}, max_{exact}
- {}
-
- explicit
- length(std::size_t min, std::size_t max):
- min_{min}, max_{max}
- {}
-
- bool operator () (const arg_string& s) const {
- return s.size() >= min_ && s.size() <= max_;
- }
-
-private:
- std::size_t min_;
- std::size_t max_;
-};
-
-
-/*************************************************************************//**
- *
- * @brief makes function object that returns true if the input string has a
- * given minimum length
- *
- *****************************************************************************/
-inline length min_length(std::size_t min)
-{
- return length{min, arg_string::npos-1};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that returns true if the input string is
- * not longer than a given maximum length
- *
- *****************************************************************************/
-inline length max_length(std::size_t max)
-{
- return length{0, max};
-}
-
-
-} // namespace match
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief command line parameter that can match one or many arguments.
- *
- *****************************************************************************/
-class parameter :
- public detail::token<parameter>,
- public detail::action_provider<parameter>
-{
- /** @brief adapts a 'match_predicate' to the 'match_function' interface */
- class predicate_adapter {
- public:
- explicit
- predicate_adapter(match_predicate pred): match_{std::move(pred)} {}
-
- subrange operator () (const arg_string& arg) const {
- return match_(arg) ? subrange{0,arg.size()} : subrange{};
- }
-
- private:
- match_predicate match_;
- };
-
-public:
- //---------------------------------------------------------------
- /** @brief makes default parameter, that will match nothing */
- parameter():
- flags_{},
- matcher_{predicate_adapter{match::none}},
- label_{}, required_{false}, greedy_{false}
- {}
-
- /** @brief makes "flag" parameter */
- template<class... Strings>
- explicit
- parameter(arg_string str, Strings&&... strs):
- flags_{},
- matcher_{predicate_adapter{match::none}},
- label_{}, required_{false}, greedy_{false}
- {
- add_flags(std::move(str), std::forward<Strings>(strs)...);
- }
-
- /** @brief makes "flag" parameter from range of strings */
- explicit
- parameter(const arg_list& flaglist):
- flags_{},
- matcher_{predicate_adapter{match::none}},
- label_{}, required_{false}, greedy_{false}
- {
- add_flags(flaglist);
- }
-
- //-----------------------------------------------------
- /** @brief makes "value" parameter with custom match predicate
- * (= yes/no matcher)
- */
- explicit
- parameter(match_predicate filter):
- flags_{},
- matcher_{predicate_adapter{std::move(filter)}},
- label_{}, required_{false}, greedy_{false}
- {}
-
- /** @brief makes "value" parameter with custom match function
- * (= partial matcher)
- */
- explicit
- parameter(match_function filter):
- flags_{},
- matcher_{std::move(filter)},
- label_{}, required_{false}, greedy_{false}
- {}
-
-
- //---------------------------------------------------------------
- /** @brief returns if a parameter is required */
- bool
- required() const noexcept {
- return required_;
- }
-
- /** @brief determines if a parameter is required */
- parameter&
- required(bool yes) noexcept {
- required_ = yes;
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if a parameter should match greedily */
- bool
- greedy() const noexcept {
- return greedy_;
- }
-
- /** @brief determines if a parameter should match greedily */
- parameter&
- greedy(bool yes) noexcept {
- greedy_ = yes;
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns parameter label;
- * will be used for documentation, if flags are empty
- */
- const doc_string&
- label() const {
- return label_;
- }
-
- /** @brief sets parameter label;
- * will be used for documentation, if flags are empty
- */
- parameter&
- label(const doc_string& lbl) {
- label_ = lbl;
- return *this;
- }
-
- /** @brief sets parameter label;
- * will be used for documentation, if flags are empty
- */
- parameter&
- label(doc_string&& lbl) {
- label_ = lbl;
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns either longest matching prefix of 'arg' in any
- * of the flags or the result of the custom match operation
- */
- subrange
- match(const arg_string& arg) const
- {
- if(flags_.empty()) {
- return matcher_(arg);
- }
- else {
- //empty flags are not allowed
- if(arg.empty()) return subrange{};
-
- if(std::find(flags_.begin(), flags_.end(), arg) != flags_.end()) {
- return subrange{0,arg.size()};
- }
- return str::longest_prefix_match(arg, flags_);
- }
- }
-
-
- //---------------------------------------------------------------
- /** @brief access range of flag strings */
- const arg_list&
- flags() const noexcept {
- return flags_;
- }
-
- /** @brief access custom match operation */
- const match_function&
- matcher() const noexcept {
- return matcher_;
- }
-
-
- //---------------------------------------------------------------
- /** @brief prepend prefix to each flag */
- inline friend parameter&
- with_prefix(const arg_string& prefix, parameter& p)
- {
- if(prefix.empty() || p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.find(prefix) != 0) f.insert(0, prefix);
- }
- return p;
- }
-
-
- /** @brief prepend prefix to each flag
- */
- inline friend parameter&
- with_prefixes_short_long(
- const arg_string& shortpfx, const arg_string& longpfx,
- parameter& p)
- {
- if(shortpfx.empty() && longpfx.empty()) return p;
- if(p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.size() == 1) {
- if(f.find(shortpfx) != 0) f.insert(0, shortpfx);
- } else {
- if(f.find(longpfx) != 0) f.insert(0, longpfx);
- }
- }
- return p;
- }
-
-
- //---------------------------------------------------------------
- /** @brief prepend suffix to each flag */
- inline friend parameter&
- with_suffix(const arg_string& suffix, parameter& p)
- {
- if(suffix.empty() || p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.find(suffix) + suffix.size() != f.size()) {
- f.insert(f.end(), suffix.begin(), suffix.end());
- }
- }
- return p;
- }
-
-
- /** @brief prepend suffix to each flag
- */
- inline friend parameter&
- with_suffixes_short_long(
- const arg_string& shortsfx, const arg_string& longsfx,
- parameter& p)
- {
- if(shortsfx.empty() && longsfx.empty()) return p;
- if(p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.size() == 1) {
- if(f.find(shortsfx) + shortsfx.size() != f.size()) {
- f.insert(f.end(), shortsfx.begin(), shortsfx.end());
- }
- } else {
- if(f.find(longsfx) + longsfx.size() != f.size()) {
- f.insert(f.end(), longsfx.begin(), longsfx.end());
- }
- }
- }
- return p;
- }
-
-private:
- //---------------------------------------------------------------
- void add_flags(arg_string str) {
- //empty flags are not allowed
- str::remove_ws(str);
- if(!str.empty()) flags_.push_back(std::move(str));
- }
-
- //---------------------------------------------------------------
- void add_flags(const arg_list& strs) {
- if(strs.empty()) return;
- flags_.reserve(flags_.size() + strs.size());
- for(const auto& s : strs) add_flags(s);
- }
-
- template<class String1, class String2, class... Strings>
- void
- add_flags(String1&& s1, String2&& s2, Strings&&... ss) {
- flags_.reserve(2 + sizeof...(ss));
- add_flags(std::forward<String1>(s1));
- add_flags(std::forward<String2>(s2), std::forward<Strings>(ss)...);
- }
-
- arg_list flags_;
- match_function matcher_;
- doc_string label_;
- bool required_ = false;
- bool greedy_ = false;
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required non-blocking exact match parameter
- *
- *****************************************************************************/
-template<class String, class... Strings>
-inline parameter
-command(String&& flag, Strings&&... flags)
-{
- return parameter{std::forward<String>(flag), std::forward<Strings>(flags)...}
- .required(true).blocking(true).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required non-blocking exact match parameter
- *
- *****************************************************************************/
-template<class String, class... Strings>
-inline parameter
-required(String&& flag, Strings&&... flags)
-{
- return parameter{std::forward<String>(flag), std::forward<Strings>(flags)...}
- .required(true).blocking(false).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, non-blocking exact match parameter
- *
- *****************************************************************************/
-template<class String, class... Strings>
-inline parameter
-option(String&& flag, Strings&&... flags)
-{
- return parameter{std::forward<String>(flag), std::forward<Strings>(flags)...}
- .required(false).blocking(false).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking, repeatable value parameter;
- * matches any non-empty string
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-value(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::nonempty}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(false);
-}
-
-template<class Filter, class... Targets, class = typename std::enable_if<
- traits::is_callable<Filter,bool(const char*)>::value ||
- traits::is_callable<Filter,subrange(const char*)>::value>::type>
-inline parameter
-value(Filter&& filter, doc_string label, Targets&&... tgts)
-{
- return parameter{std::forward<Filter>(filter)}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking, repeatable value parameter;
- * matches any non-empty string
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-values(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::nonempty}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(true);
-}
-
-template<class Filter, class... Targets, class = typename std::enable_if<
- traits::is_callable<Filter,bool(const char*)>::value ||
- traits::is_callable<Filter,subrange(const char*)>::value>::type>
-inline parameter
-values(Filter&& filter, doc_string label, Targets&&... tgts)
-{
- return parameter{std::forward<Filter>(filter)}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking value parameter;
- * matches any non-empty string
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_value(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::nonempty}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(false);
-}
-
-template<class Filter, class... Targets, class = typename std::enable_if<
- traits::is_callable<Filter,bool(const char*)>::value ||
- traits::is_callable<Filter,subrange(const char*)>::value>::type>
-inline parameter
-opt_value(Filter&& filter, doc_string label, Targets&&... tgts)
-{
- return parameter{std::forward<Filter>(filter)}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking, repeatable value parameter;
- * matches any non-empty string
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_values(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::nonempty}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-template<class Filter, class... Targets, class = typename std::enable_if<
- traits::is_callable<Filter,bool(const char*)>::value ||
- traits::is_callable<Filter,subrange(const char*)>::value>::type>
-inline parameter
-opt_values(Filter&& filter, doc_string label, Targets&&... tgts)
-{
- return parameter{std::forward<Filter>(filter)}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking value parameter;
- * matches any string consisting of alphanumeric characters
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-word(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::alphanumeric}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking, repeatable value parameter;
- * matches any string consisting of alphanumeric characters
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-words(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::alphanumeric}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking value parameter;
- * matches any string consisting of alphanumeric characters
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_word(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::alphanumeric}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking, repeatable value parameter;
- * matches any string consisting of alphanumeric characters
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_words(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::alphanumeric}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking value parameter;
- * matches any string that represents a number
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-number(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::numbers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking, repeatable value parameter;
- * matches any string that represents a number
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-numbers(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::numbers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking value parameter;
- * matches any string that represents a number
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_number(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::numbers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking, repeatable value parameter;
- * matches any string that represents a number
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_numbers(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::numbers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking value parameter;
- * matches any string that represents an integer
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-integer(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::integers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes required, blocking, repeatable value parameter;
- * matches any string that represents an integer
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-integers(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::integers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(true).blocking(true).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking value parameter;
- * matches any string that represents an integer
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_integer(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::integers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes optional, blocking, repeatable value parameter;
- * matches any string that represents an integer
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-opt_integers(const doc_string& label, Targets&&... tgts)
-{
- return parameter{match::integers{}}
- .label(label)
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes catch-all value parameter
- *
- *****************************************************************************/
-template<class... Targets>
-inline parameter
-any_other(Targets&&... tgts)
-{
- return parameter{match::any}
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes catch-all value parameter with custom filter
- *
- *****************************************************************************/
-template<class Filter, class... Targets, class = typename std::enable_if<
- traits::is_callable<Filter,bool(const char*)>::value ||
- traits::is_callable<Filter,subrange(const char*)>::value>::type>
-inline parameter
-any(Filter&& filter, Targets&&... tgts)
-{
- return parameter{std::forward<Filter>(filter)}
- .target(std::forward<Targets>(tgts)...)
- .required(false).blocking(false).repeatable(true);
-}
-
-
-
-
-/*************************************************************************//**
- *
- * @brief group of parameters and/or other groups;
- * can be configured to act as a group of alternatives (exclusive match)
- *
- *****************************************************************************/
-class group :
- public detail::token<group>
-{
- //---------------------------------------------------------------
- /**
- * @brief tagged union type that either stores a parameter or a group
- * and provides a common interface to them
- * could be replaced by std::variant in the future
- *
- * Note to future self: do NOT try again to do this with
- * dynamic polymorphism; there are a couple of
- * nasty problems associated with it and the implementation
- * becomes bloated and needlessly complicated.
- */
- template<class Param, class Group>
- struct child_t {
- enum class type : char {param, group};
- public:
-
- explicit
- child_t(const Param& v) : m_{v}, type_{type::param} {}
- child_t( Param&& v) noexcept : m_{std::move(v)}, type_{type::param} {}
-
- explicit
- child_t(const Group& g) : m_{g}, type_{type::group} {}
- child_t( Group&& g) noexcept : m_{std::move(g)}, type_{type::group} {}
-
- child_t(const child_t& src): type_{src.type_} {
- switch(type_) {
- default:
- case type::param: new(&m_)data{src.m_.param}; break;
- case type::group: new(&m_)data{src.m_.group}; break;
- }
- }
-
- child_t(child_t&& src) noexcept : type_{src.type_} {
- switch(type_) {
- default:
- case type::param: new(&m_)data{std::move(src.m_.param)}; break;
- case type::group: new(&m_)data{std::move(src.m_.group)}; break;
- }
- }
-
- child_t& operator = (const child_t& src) {
- destroy_content();
- type_ = src.type_;
- switch(type_) {
- default:
- case type::param: new(&m_)data{src.m_.param}; break;
- case type::group: new(&m_)data{src.m_.group}; break;
- }
- return *this;
- }
-
- child_t& operator = (child_t&& src) noexcept {
- destroy_content();
- type_ = src.type_;
- switch(type_) {
- default:
- case type::param: new(&m_)data{std::move(src.m_.param)}; break;
- case type::group: new(&m_)data{std::move(src.m_.group)}; break;
- }
- return *this;
- }
-
- ~child_t() {
- destroy_content();
- }
-
- const doc_string&
- doc() const noexcept {
- switch(type_) {
- default:
- case type::param: return m_.param.doc();
- case type::group: return m_.group.doc();
- }
- }
-
- bool blocking() const noexcept {
- switch(type_) {
- case type::param: return m_.param.blocking();
- case type::group: return m_.group.blocking();
- default: return false;
- }
- }
- bool repeatable() const noexcept {
- switch(type_) {
- case type::param: return m_.param.repeatable();
- case type::group: return m_.group.repeatable();
- default: return false;
- }
- }
- bool required() const noexcept {
- switch(type_) {
- case type::param: return m_.param.required();
- case type::group:
- return (m_.group.exclusive() && m_.group.all_required() ) ||
- (!m_.group.exclusive() && m_.group.any_required() );
- default: return false;
- }
- }
- bool exclusive() const noexcept {
- switch(type_) {
- case type::group: return m_.group.exclusive();
- case type::param:
- default: return false;
- }
- }
- std::size_t param_count() const noexcept {
- switch(type_) {
- case type::group: return m_.group.param_count();
- case type::param:
- default: return std::size_t(1);
- }
- }
- std::size_t depth() const noexcept {
- switch(type_) {
- case type::group: return m_.group.depth();
- case type::param:
- default: return std::size_t(0);
- }
- }
-
- void execute_actions(const arg_string& arg) const {
- switch(type_) {
- default:
- case type::group: return;
- case type::param: m_.param.execute_actions(arg); break;
- }
-
- }
-
- void notify_repeated(arg_index idx) const {
- switch(type_) {
- default:
- case type::group: return;
- case type::param: m_.param.notify_repeated(idx); break;
- }
- }
- void notify_missing(arg_index idx) const {
- switch(type_) {
- default:
- case type::group: return;
- case type::param: m_.param.notify_missing(idx); break;
- }
- }
- void notify_blocked(arg_index idx) const {
- switch(type_) {
- default:
- case type::group: return;
- case type::param: m_.param.notify_blocked(idx); break;
- }
- }
- void notify_conflict(arg_index idx) const {
- switch(type_) {
- default:
- case type::group: return;
- case type::param: m_.param.notify_conflict(idx); break;
- }
- }
-
- bool is_param() const noexcept { return type_ == type::param; }
- bool is_group() const noexcept { return type_ == type::group; }
-
- Param& as_param() noexcept { return m_.param; }
- Group& as_group() noexcept { return m_.group; }
-
- const Param& as_param() const noexcept { return m_.param; }
- const Group& as_group() const noexcept { return m_.group; }
-
- private:
- void destroy_content() {
- switch(type_) {
- default:
- case type::param: m_.param.~Param(); break;
- case type::group: m_.group.~Group(); break;
- }
- }
-
- union data {
- data() {}
-
- data(const Param& v) : param{v} {}
- data( Param&& v) noexcept : param{std::move(v)} {}
-
- data(const Group& g) : group{g} {}
- data( Group&& g) noexcept : group{std::move(g)} {}
- ~data() {}
-
- Param param;
- Group group;
- };
-
- data m_;
- type type_;
- };
-
-
-public:
- //---------------------------------------------------------------
- using child = child_t<parameter,group>;
- using value_type = child;
-
-private:
- using children_store = std::vector<child>;
-
-public:
- using const_iterator = children_store::const_iterator;
- using iterator = children_store::iterator;
- using size_type = children_store::size_type;
-
-
- //---------------------------------------------------------------
- /**
- * @brief recursively iterates over all nodes
- */
- class depth_first_traverser
- {
- public:
- //-----------------------------------------------------
- struct context {
- context() = default;
- context(const group& p):
- parent{&p}, cur{p.begin()}, end{p.end()}
- {}
- const group* parent = nullptr;
- const_iterator cur;
- const_iterator end;
- };
- using context_list = std::vector<context>;
-
- //-----------------------------------------------------
- class memento {
- friend class depth_first_traverser;
- int level_;
- context context_;
- public:
- int level() const noexcept { return level_; }
- const child* param() const noexcept { return &(*context_.cur); }
- };
-
- depth_first_traverser() = default;
-
- explicit
- depth_first_traverser(const group& cur): stack_{} {
- if(!cur.empty()) stack_.emplace_back(cur);
- }
-
- explicit operator bool() const noexcept {
- return !stack_.empty();
- }
-
- int level() const noexcept {
- return int(stack_.size());
- }
-
- bool is_first_in_parent() const noexcept {
- if(stack_.empty()) return false;
- return (stack_.back().cur == stack_.back().parent->begin());
- }
-
- bool is_last_in_parent() const noexcept {
- if(stack_.empty()) return false;
- return (stack_.back().cur+1 == stack_.back().end);
- }
-
- bool is_last_in_path() const noexcept {
- if(stack_.empty()) return false;
- for(const auto& t : stack_) {
- if(t.cur+1 != t.end) return false;
- }
- const auto& top = stack_.back();
- //if we have to descend into group on next ++ => not last in path
- if(top.cur->is_group()) return false;
- return true;
- }
-
- /** @brief inside a group of alternatives >= minlevel */
- bool is_alternative(int minlevel = 0) const noexcept {
- if(stack_.empty()) return false;
- if(minlevel > 0) minlevel -= 1;
- if(minlevel >= int(stack_.size())) return false;
- return std::any_of(stack_.begin() + minlevel, stack_.end(),
- [](const context& c) { return c.parent->exclusive(); });
- }
-
- /** @brief repeatable or inside a repeatable group >= minlevel */
- bool is_repeatable(int minlevel = 0) const noexcept {
- if(stack_.empty()) return false;
- if(stack_.back().cur->repeatable()) return true;
- if(minlevel > 0) minlevel -= 1;
- if(minlevel >= int(stack_.size())) return false;
- return std::any_of(stack_.begin() + minlevel, stack_.end(),
- [](const context& c) { return c.parent->repeatable(); });
- }
-
- /** @brief inside a particular group */
- bool is_inside(const group* g) const noexcept {
- if(!g) return false;
- return std::any_of(stack_.begin(), stack_.end(),
- [g](const context& c) { return c.parent == g; });
- }
-
- /** @brief inside group with joinable flags */
- bool joinable() const noexcept {
- if(stack_.empty()) return false;
- return std::any_of(stack_.begin(), stack_.end(),
- [](const context& c) { return c.parent->joinable(); });
- }
-
- const context_list&
- stack() const {
- return stack_;
- }
-
- /** @brief innermost repeat group */
- const group*
- innermost_repeat_group() const noexcept {
- auto i = std::find_if(stack_.rbegin(), stack_.rend(),
- [](const context& c) { return c.parent->repeatable(); });
- return i != stack_.rend() ? i->parent : nullptr;
- }
-
- /** @brief innermost exclusive (alternatives) group */
- const group*
- innermost_exclusive_group() const noexcept {
- auto i = std::find_if(stack_.rbegin(), stack_.rend(),
- [](const context& c) { return c.parent->exclusive(); });
- return i != stack_.rend() ? i->parent : nullptr;
- }
-
- /** @brief innermost blocking group */
- const group*
- innermost_blocking_group() const noexcept {
- auto i = std::find_if(stack_.rbegin(), stack_.rend(),
- [](const context& c) { return c.parent->blocking(); });
- return i != stack_.rend() ? i->parent : nullptr;
- }
-
- /** @brief returns the outermost group that will be left on next ++*/
- const group*
- outermost_blocking_group_fully_explored() const noexcept {
- if(stack_.empty()) return nullptr;
-
- const group* g = nullptr;
- for(auto i = stack_.rbegin(); i != stack_.rend(); ++i) {
- if(i->cur+1 == i->end) {
- if(i->parent->blocking()) g = i->parent;
- } else {
- return g;
- }
- }
- return g;
- }
-
- /** @brief outermost join group */
- const group*
- outermost_join_group() const noexcept {
- auto i = std::find_if(stack_.begin(), stack_.end(),
- [](const context& c) { return c.parent->joinable(); });
- return i != stack_.end() ? i->parent : nullptr;
- }
-
- const group* root() const noexcept {
- return stack_.empty() ? nullptr : stack_.front().parent;
- }
-
- /** @brief common flag prefix of all flags in current group */
- arg_string common_flag_prefix() const noexcept {
- if(stack_.empty()) return "";
- auto g = outermost_join_group();
- return g ? g->common_flag_prefix() : arg_string("");
- }
-
- const child&
- operator * () const noexcept {
- return *stack_.back().cur;
- }
-
- const child*
- operator -> () const noexcept {
- return &(*stack_.back().cur);
- }
-
- const group&
- parent() const noexcept {
- return *(stack_.back().parent);
- }
-
-
- /** @brief go to next element of depth first search */
- depth_first_traverser&
- operator ++ () {
- if(stack_.empty()) return *this;
- //at group -> decend into group
- if(stack_.back().cur->is_group()) {
- stack_.emplace_back(stack_.back().cur->as_group());
- }
- else {
- next_sibling();
- }
- return *this;
- }
-
- /** @brief go to next sibling of current */
- depth_first_traverser&
- next_sibling() {
- if(stack_.empty()) return *this;
- ++stack_.back().cur;
- //at the end of current group?
- while(stack_.back().cur == stack_.back().end) {
- //go to parent
- stack_.pop_back();
- if(stack_.empty()) return *this;
- //go to next sibling in parent
- ++stack_.back().cur;
- }
- return *this;
- }
-
- /** @brief go to next position after siblings of current */
- depth_first_traverser&
- next_after_siblings() {
- if(stack_.empty()) return *this;
- stack_.back().cur = stack_.back().end-1;
- next_sibling();
- return *this;
- }
-
- /**
- * @brief
- */
- depth_first_traverser&
- back_to_ancestor(const group* g) {
- if(!g) return *this;
- while(!stack_.empty()) {
- const auto& top = stack_.back().cur;
- if(top->is_group() && &(top->as_group()) == g) return *this;
- stack_.pop_back();
- }
- return *this;
- }
-
- /** @brief don't visit next siblings, go back to parent on next ++
- * note: renders siblings unreachable for *this
- **/
- depth_first_traverser&
- skip_siblings() {
- if(stack_.empty()) return *this;
- //future increments won't visit subsequent siblings:
- stack_.back().end = stack_.back().cur+1;
- return *this;
- }
-
- /** @brief skips all other alternatives in surrounding exclusive groups
- * on next ++
- * note: renders alternatives unreachable for *this
- */
- depth_first_traverser&
- skip_alternatives() {
- if(stack_.empty()) return *this;
-
- //exclude all other alternatives in surrounding groups
- //by making their current position the last one
- for(auto& c : stack_) {
- if(c.parent && c.parent->exclusive() && c.cur < c.end)
- c.end = c.cur+1;
- }
-
- return *this;
- }
-
- void invalidate() {
- stack_.clear();
- }
-
- inline friend bool operator == (const depth_first_traverser& a,
- const depth_first_traverser& b)
- {
- if(a.stack_.empty() || b.stack_.empty()) return false;
-
- //parents not the same -> different position
- if(a.stack_.back().parent != b.stack_.back().parent) return false;
-
- bool aEnd = a.stack_.back().cur == a.stack_.back().end;
- bool bEnd = b.stack_.back().cur == b.stack_.back().end;
- //either both at the end of the same parent => same position
- if(aEnd && bEnd) return true;
- //or only one at the end => not at the same position
- if(aEnd || bEnd) return false;
- return std::addressof(*a.stack_.back().cur) ==
- std::addressof(*b.stack_.back().cur);
- }
- inline friend bool operator != (const depth_first_traverser& a,
- const depth_first_traverser& b)
- {
- return !(a == b);
- }
-
- memento
- undo_point() const {
- memento m;
- m.level_ = int(stack_.size());
- if(!stack_.empty()) m.context_ = stack_.back();
- return m;
- }
-
- void undo(const memento& m) {
- if(m.level_ < 1) return;
- if(m.level_ <= int(stack_.size())) {
- stack_.erase(stack_.begin() + m.level_, stack_.end());
- stack_.back() = m.context_;
- }
- else if(stack_.empty() && m.level_ == 1) {
- stack_.push_back(m.context_);
- }
- }
-
- private:
- context_list stack_;
- };
-
-
- //---------------------------------------------------------------
- group() = default;
-
- template<class Param, class... Params>
- explicit
- group(doc_string docstr, Param param, Params... params):
- children_{}, exclusive_{false}, joinable_{false}, scoped_{true}
- {
- doc(std::move(docstr));
- push_back(std::move(param), std::move(params)...);
- }
-
- template<class... Params>
- explicit
- group(parameter param, Params... params):
- children_{}, exclusive_{false}, joinable_{false}, scoped_{true}
- {
- push_back(std::move(param), std::move(params)...);
- }
-
- template<class P2, class... Ps>
- explicit
- group(group p1, P2 p2, Ps... ps):
- children_{}, exclusive_{false}, joinable_{false}, scoped_{true}
- {
- push_back(std::move(p1), std::move(p2), std::move(ps)...);
- }
-
-
- //-----------------------------------------------------
- group(const group&) = default;
- group(group&&) = default;
-
-
- //---------------------------------------------------------------
- group& operator = (const group&) = default;
- group& operator = (group&&) = default;
-
-
- //---------------------------------------------------------------
- /** @brief determines if a command line argument can be matched by a
- * combination of (partial) matches through any number of children
- */
- group& joinable(bool yes) {
- joinable_ = yes;
- return *this;
- }
-
- /** @brief returns if a command line argument can be matched by a
- * combination of (partial) matches through any number of children
- */
- bool joinable() const noexcept {
- return joinable_;
- }
-
-
- //---------------------------------------------------------------
- /** @brief turns explicit scoping on or off
- * operators , & | and other combinating functions will
- * not merge groups that are marked as scoped
- */
- group& scoped(bool yes) {
- scoped_ = yes;
- return *this;
- }
-
- /** @brief returns true if operators , & | and other combinating functions
- * will merge groups and false otherwise
- */
- bool scoped() const noexcept
- {
- return scoped_;
- }
-
-
- //---------------------------------------------------------------
- /** @brief determines if children are mutually exclusive alternatives */
- group& exclusive(bool yes) {
- exclusive_ = yes;
- return *this;
- }
- /** @brief returns if children are mutually exclusive alternatives */
- bool exclusive() const noexcept {
- return exclusive_;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns true, if any child is required to match */
- bool any_required() const
- {
- return std::any_of(children_.begin(), children_.end(),
- [](const child& n){ return n.required(); });
- }
- /** @brief returns true, if all children are required to match */
- bool all_required() const
- {
- return std::all_of(children_.begin(), children_.end(),
- [](const child& n){ return n.required(); });
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns true if any child is optional (=non-required) */
- bool any_optional() const {
- return !all_required();
- }
- /** @brief returns true if all children are optional (=non-required) */
- bool all_optional() const {
- return !any_required();
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if the entire group is blocking / positional */
- bool blocking() const noexcept {
- return token<group>::blocking() || (exclusive() && all_blocking());
- }
- //-----------------------------------------------------
- /** @brief determines if the entire group is blocking / positional */
- group& blocking(bool yes) {
- return token<group>::blocking(yes);
- }
-
- //---------------------------------------------------------------
- /** @brief returns true if any child is blocking */
- bool any_blocking() const
- {
- return std::any_of(children_.begin(), children_.end(),
- [](const child& n){ return n.blocking(); });
- }
- //---------------------------------------------------------------
- /** @brief returns true if all children is blocking */
- bool all_blocking() const
- {
- return std::all_of(children_.begin(), children_.end(),
- [](const child& n){ return n.blocking(); });
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if any child is a value parameter (recursive) */
- bool any_flagless() const
- {
- return std::any_of(children_.begin(), children_.end(),
- [](const child& p){
- return p.is_param() && p.as_param().flags().empty();
- });
- }
- /** @brief returns if all children are value parameters (recursive) */
- bool all_flagless() const
- {
- return std::all_of(children_.begin(), children_.end(),
- [](const child& p){
- return p.is_param() && p.as_param().flags().empty();
- });
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds child parameter at the end */
- group&
- push_back(const parameter& v) {
- children_.emplace_back(v);
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds child parameter at the end */
- group&
- push_back(parameter&& v) {
- children_.emplace_back(std::move(v));
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds child group at the end */
- group&
- push_back(const group& g) {
- children_.emplace_back(g);
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds child group at the end */
- group&
- push_back(group&& g) {
- children_.emplace_back(std::move(g));
- return *this;
- }
-
-
- //-----------------------------------------------------
- /** @brief adds children (groups and/or parameters) */
- template<class Param1, class Param2, class... Params>
- group&
- push_back(Param1&& param1, Param2&& param2, Params&&... params)
- {
- children_.reserve(children_.size() + 2 + sizeof...(params));
- push_back(std::forward<Param1>(param1));
- push_back(std::forward<Param2>(param2), std::forward<Params>(params)...);
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds child parameter at the beginning */
- group&
- push_front(const parameter& v) {
- children_.emplace(children_.begin(), v);
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds child parameter at the beginning */
- group&
- push_front(parameter&& v) {
- children_.emplace(children_.begin(), std::move(v));
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds child group at the beginning */
- group&
- push_front(const group& g) {
- children_.emplace(children_.begin(), g);
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds child group at the beginning */
- group&
- push_front(group&& g) {
- children_.emplace(children_.begin(), std::move(g));
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds all children of other group at the end */
- group&
- merge(group&& g)
- {
- children_.insert(children_.end(),
- std::make_move_iterator(g.begin()),
- std::make_move_iterator(g.end()));
- return *this;
- }
- //-----------------------------------------------------
- /** @brief adds all children of several other groups at the end */
- template<class... Groups>
- group&
- merge(group&& g1, group&& g2, Groups&&... gs)
- {
- merge(std::move(g1));
- merge(std::move(g2), std::forward<Groups>(gs)...);
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief indexed, nutable access to child */
- child& operator [] (size_type index) noexcept {
- return children_[index];
- }
- /** @brief indexed, non-nutable access to child */
- const child& operator [] (size_type index) const noexcept {
- return children_[index];
- }
-
- //---------------------------------------------------------------
- /** @brief mutable access to first child */
- child& front() noexcept { return children_.front(); }
- /** @brief non-mutable access to first child */
- const child& front() const noexcept { return children_.front(); }
- //-----------------------------------------------------
- /** @brief mutable access to last child */
- child& back() noexcept { return children_.back(); }
- /** @brief non-mutable access to last child */
- const child& back() const noexcept { return children_.back(); }
-
-
- //---------------------------------------------------------------
- /** @brief returns true, if group has no children, false otherwise */
- bool empty() const noexcept { return children_.empty(); }
-
- /** @brief returns number of children */
- size_type size() const noexcept { return children_.size(); }
-
- /** @brief returns number of nested levels; 1 for a flat group */
- size_type depth() const {
- size_type n = 0;
- for(const auto& c : children_) {
- auto l = 1 + c.depth();
- if(l > n) n = l;
- }
- return n;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns mutating iterator to position of first element */
- iterator begin() noexcept { return children_.begin(); }
- /** @brief returns non-mutating iterator to position of first element */
- const_iterator begin() const noexcept { return children_.begin(); }
- /** @brief returns non-mutating iterator to position of first element */
- const_iterator cbegin() const noexcept { return children_.begin(); }
-
- /** @brief returns mutating iterator to position one past the last element */
- iterator end() noexcept { return children_.end(); }
- /** @brief returns non-mutating iterator to position one past the last element */
- const_iterator end() const noexcept { return children_.end(); }
- /** @brief returns non-mutating iterator to position one past the last element */
- const_iterator cend() const noexcept { return children_.end(); }
-
-
- //---------------------------------------------------------------
- /** @brief returns augmented iterator for depth first searches
- * @details traverser knows end of iteration and can skip over children
- */
- depth_first_traverser
- begin_dfs() const noexcept {
- return depth_first_traverser{*this};
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns recursive parameter count */
- size_type param_count() const {
- size_type c = 0;
- for(const auto& n : children_) {
- c += n.param_count();
- }
- return c;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns range of all flags (recursive) */
- arg_list all_flags() const
- {
- std::vector<arg_string> all;
- gather_flags(children_, all);
- return all;
- }
-
- /** @brief returns true, if no flag occurs as true
- * prefix of any other flag (identical flags will be ignored) */
- bool flags_are_prefix_free() const
- {
- const auto fs = all_flags();
-
- using std::begin; using std::end;
- for(auto i = begin(fs), e = end(fs); i != e; ++i) {
- if(!i->empty()) {
- for(auto j = i+1; j != e; ++j) {
- if(!j->empty() && *i != *j) {
- if(i->find(*j) == 0) return false;
- if(j->find(*i) == 0) return false;
- }
- }
- }
- }
-
- return true;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns longest common prefix of all flags */
- arg_string common_flag_prefix() const
- {
- arg_list prefixes;
- gather_prefixes(children_, prefixes);
- return str::longest_common_prefix(prefixes);
- }
-
-
-private:
- //---------------------------------------------------------------
- static void
- gather_flags(const children_store& nodes, arg_list& all)
- {
- for(const auto& p : nodes) {
- if(p.is_group()) {
- gather_flags(p.as_group().children_, all);
- }
- else {
- const auto& pf = p.as_param().flags();
- using std::begin;
- using std::end;
- if(!pf.empty()) all.insert(end(all), begin(pf), end(pf));
- }
- }
- }
- //---------------------------------------------------------------
- static void
- gather_prefixes(const children_store& nodes, arg_list& all)
- {
- for(const auto& p : nodes) {
- if(p.is_group()) {
- gather_prefixes(p.as_group().children_, all);
- }
- else if(!p.as_param().flags().empty()) {
- auto pfx = str::longest_common_prefix(p.as_param().flags());
- if(!pfx.empty()) all.push_back(std::move(pfx));
- }
- }
- }
-
- //---------------------------------------------------------------
- children_store children_;
- bool exclusive_ = false;
- bool joinable_ = false;
- bool scoped_ = false;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief group or parameter
- *
- *****************************************************************************/
-using pattern = group::child;
-
-
-
-/*************************************************************************//**
- *
- * @brief apply an action to all parameters in a group
- *
- *****************************************************************************/
-template<class Action>
-void for_all_params(group& g, Action&& action)
-{
- for(auto& p : g) {
- if(p.is_group()) {
- for_all_params(p.as_group(), action);
- }
- else {
- action(p.as_param());
- }
- }
-}
-
-template<class Action>
-void for_all_params(const group& g, Action&& action)
-{
- for(auto& p : g) {
- if(p.is_group()) {
- for_all_params(p.as_group(), action);
- }
- else {
- action(p.as_param());
- }
- }
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a group of parameters and/or groups
- *
- *****************************************************************************/
-inline group
-operator , (parameter a, parameter b)
-{
- return group{std::move(a), std::move(b)}.scoped(false);
-}
-
-//---------------------------------------------------------
-inline group
-operator , (parameter a, group b)
-{
- return !b.scoped() && !b.blocking() && !b.exclusive() && !b.repeatable()
- && !b.joinable() && (b.doc().empty() || b.doc() == a.doc())
- ? b.push_front(std::move(a))
- : group{std::move(a), std::move(b)}.scoped(false);
-}
-
-//---------------------------------------------------------
-inline group
-operator , (group a, parameter b)
-{
- return !a.scoped() && !a.blocking() && !a.exclusive() && !a.repeatable()
- && !a.joinable() && (a.doc().empty() || a.doc() == b.doc())
- ? a.push_back(std::move(b))
- : group{std::move(a), std::move(b)}.scoped(false);
-}
-
-//---------------------------------------------------------
-inline group
-operator , (group a, group b)
-{
- return !a.scoped() && !a.blocking() && !a.exclusive() && !a.repeatable()
- && !a.joinable() && (a.doc().empty() || a.doc() == b.doc())
- ? a.push_back(std::move(b))
- : group{std::move(a), std::move(b)}.scoped(false);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a group of alternative parameters or groups
- *
- *****************************************************************************/
-template<class Param, class... Params>
-inline group
-one_of(Param param, Params... params)
-{
- return group{std::move(param), std::move(params)...}.exclusive(true);
-}
-
-
-/*************************************************************************//**
- *
- * @brief makes a group of alternative parameters or groups
- *
- *****************************************************************************/
-inline group
-operator | (parameter a, parameter b)
-{
- return group{std::move(a), std::move(b)}.scoped(false).exclusive(true);
-}
-
-//-------------------------------------------------------------------
-inline group
-operator | (parameter a, group b)
-{
- return !b.scoped() && !b.blocking() && b.exclusive() && !b.repeatable()
- && !b.joinable()
- && (b.doc().empty() || b.doc() == a.doc())
- ? b.push_front(std::move(a))
- : group{std::move(a), std::move(b)}.scoped(false).exclusive(true);
-}
-
-//-------------------------------------------------------------------
-inline group
-operator | (group a, parameter b)
-{
- return !a.scoped() && a.exclusive() && !a.repeatable() && !a.joinable()
- && a.blocking() == b.blocking()
- && (a.doc().empty() || a.doc() == b.doc())
- ? a.push_back(std::move(b))
- : group{std::move(a), std::move(b)}.scoped(false).exclusive(true);
-}
-
-inline group
-operator | (group a, group b)
-{
- return !a.scoped() && a.exclusive() &&!a.repeatable() && !a.joinable()
- && a.blocking() == b.blocking()
- && (a.doc().empty() || a.doc() == b.doc())
- ? a.push_back(std::move(b))
- : group{std::move(a), std::move(b)}.scoped(false).exclusive(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!)
- * no interface guarantees; might be changed or removed in the future
- *
- *****************************************************************************/
-namespace detail {
-
-inline void set_blocking(bool) {}
-
-template<class P, class... Ps>
-void set_blocking(bool yes, P& p, Ps&... ps) {
- p.blocking(yes);
- set_blocking(yes, ps...);
-}
-
-} // namespace detail
-
-
-/*************************************************************************//**
- *
- * @brief makes a parameter/group sequence by making all input objects blocking
- *
- *****************************************************************************/
-template<class Param, class... Params>
-inline group
-in_sequence(Param param, Params... params)
-{
- detail::set_blocking(true, param, params...);
- return group{std::move(param), std::move(params)...}.scoped(true);
-}
-
-
-/*************************************************************************//**
- *
- * @brief makes a parameter/group sequence by making all input objects blocking
- *
- *****************************************************************************/
-inline group
-operator & (parameter a, parameter b)
-{
- a.blocking(true);
- b.blocking(true);
- return group{std::move(a), std::move(b)}.scoped(true);
-}
-
-//---------------------------------------------------------
-inline group
-operator & (parameter a, group b)
-{
- a.blocking(true);
- return group{std::move(a), std::move(b)}.scoped(true);
-}
-
-//---------------------------------------------------------
-inline group
-operator & (group a, parameter b)
-{
- b.blocking(true);
- if(a.all_blocking() && !a.exclusive() && !a.repeatable() && !a.joinable()
- && (a.doc().empty() || a.doc() == b.doc()))
- {
- return a.push_back(std::move(b));
- }
- else {
- if(!a.all_blocking()) a.blocking(true);
- return group{std::move(a), std::move(b)}.scoped(true);
- }
-}
-
-inline group
-operator & (group a, group b)
-{
- if(!b.all_blocking()) b.blocking(true);
- if(a.all_blocking() && !a.exclusive() && !a.repeatable()
- && !a.joinable() && (a.doc().empty() || a.doc() == b.doc()))
- {
- return a.push_back(std::move(b));
- }
- else {
- if(!a.all_blocking()) a.blocking(true);
- return group{std::move(a), std::move(b)}.scoped(true);
- }
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a group of parameters and/or groups
- * where all single char flag params ("-a", "b", ...) are joinable
- *
- *****************************************************************************/
-inline group
-joinable(group g) {
- return g.joinable(true);
-}
-
-//-------------------------------------------------------------------
-template<class... Params>
-inline group
-joinable(parameter param, Params... params)
-{
- return group{std::move(param), std::move(params)...}.joinable(true);
-}
-
-template<class P2, class... Ps>
-inline group
-joinable(group p1, P2 p2, Ps... ps)
-{
- return group{std::move(p1), std::move(p2), std::move(ps)...}.joinable(true);
-}
-
-template<class Param, class... Params>
-inline group
-joinable(doc_string docstr, Param param, Params... params)
-{
- return group{std::move(param), std::move(params)...}
- .joinable(true).doc(std::move(docstr));
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a repeatable copy of a parameter
- *
- *****************************************************************************/
-inline parameter
-repeatable(parameter p) {
- return p.repeatable(true);
-}
-
-/*************************************************************************//**
- *
- * @brief makes a repeatable copy of a group
- *
- *****************************************************************************/
-inline group
-repeatable(group g) {
- return g.repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a group of parameters and/or groups
- * that is repeatable as a whole
- * Note that a repeatable group consisting entirely of non-blocking
- * children is equivalent to a non-repeatable group of
- * repeatable children.
- *
- *****************************************************************************/
-template<class P2, class... Ps>
-inline group
-repeatable(parameter p1, P2 p2, Ps... ps)
-{
- return group{std::move(p1), std::move(p2),
- std::move(ps)...}.repeatable(true);
-}
-
-template<class P2, class... Ps>
-inline group
-repeatable(group p1, P2 p2, Ps... ps)
-{
- return group{std::move(p1), std::move(p2),
- std::move(ps)...}.repeatable(true);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a parameter greedy (match with top priority)
- *
- *****************************************************************************/
-inline parameter
-greedy(parameter p) {
- return p.greedy(true);
-}
-
-inline parameter
-operator ! (parameter p) {
- return greedy(p);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief recursively prepends a prefix to all flags
- *
- *****************************************************************************/
-inline parameter&&
-with_prefix(const arg_string& prefix, parameter&& p) {
- return std::move(with_prefix(prefix, p));
-}
-
-
-//-------------------------------------------------------------------
-inline group&
-with_prefix(const arg_string& prefix, group& g)
-{
- for(auto& p : g) {
- if(p.is_group()) {
- with_prefix(prefix, p.as_group());
- } else {
- with_prefix(prefix, p.as_param());
- }
- }
- return g;
-}
-
-
-inline group&&
-with_prefix(const arg_string& prefix, group&& params)
-{
- return std::move(with_prefix(prefix, params));
-}
-
-
-template<class Param, class... Params>
-inline group
-with_prefix(arg_string prefix, Param&& param, Params&&... params)
-{
- return with_prefix(prefix, group{std::forward<Param>(param),
- std::forward<Params>(params)...});
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief recursively prepends a prefix to all flags
- *
- * @param shortpfx : used for single-letter flags
- * @param longpfx : used for flags with length > 1
- *
- *****************************************************************************/
-inline parameter&&
-with_prefixes_short_long(const arg_string& shortpfx, const arg_string& longpfx,
- parameter&& p)
-{
- return std::move(with_prefixes_short_long(shortpfx, longpfx, p));
-}
-
-
-//-------------------------------------------------------------------
-inline group&
-with_prefixes_short_long(const arg_string& shortFlagPrefix,
- const arg_string& longFlagPrefix,
- group& g)
-{
- for(auto& p : g) {
- if(p.is_group()) {
- with_prefixes_short_long(shortFlagPrefix, longFlagPrefix, p.as_group());
- } else {
- with_prefixes_short_long(shortFlagPrefix, longFlagPrefix, p.as_param());
- }
- }
- return g;
-}
-
-
-inline group&&
-with_prefixes_short_long(const arg_string& shortFlagPrefix,
- const arg_string& longFlagPrefix,
- group&& params)
-{
- return std::move(with_prefixes_short_long(shortFlagPrefix, longFlagPrefix,
- params));
-}
-
-
-template<class Param, class... Params>
-inline group
-with_prefixes_short_long(const arg_string& shortFlagPrefix,
- const arg_string& longFlagPrefix,
- Param&& param, Params&&... params)
-{
- return with_prefixes_short_long(shortFlagPrefix, longFlagPrefix,
- group{std::forward<Param>(param),
- std::forward<Params>(params)...});
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief recursively prepends a suffix to all flags
- *
- *****************************************************************************/
-inline parameter&&
-with_suffix(const arg_string& suffix, parameter&& p) {
- return std::move(with_suffix(suffix, p));
-}
-
-
-//-------------------------------------------------------------------
-inline group&
-with_suffix(const arg_string& suffix, group& g)
-{
- for(auto& p : g) {
- if(p.is_group()) {
- with_suffix(suffix, p.as_group());
- } else {
- with_suffix(suffix, p.as_param());
- }
- }
- return g;
-}
-
-
-inline group&&
-with_suffix(const arg_string& suffix, group&& params)
-{
- return std::move(with_suffix(suffix, params));
-}
-
-
-template<class Param, class... Params>
-inline group
-with_suffix(arg_string suffix, Param&& param, Params&&... params)
-{
- return with_suffix(suffix, group{std::forward<Param>(param),
- std::forward<Params>(params)...});
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief recursively prepends a suffix to all flags
- *
- * @param shortsfx : used for single-letter flags
- * @param longsfx : used for flags with length > 1
- *
- *****************************************************************************/
-inline parameter&&
-with_suffixes_short_long(const arg_string& shortsfx, const arg_string& longsfx,
- parameter&& p)
-{
- return std::move(with_suffixes_short_long(shortsfx, longsfx, p));
-}
-
-
-//-------------------------------------------------------------------
-inline group&
-with_suffixes_short_long(const arg_string& shortFlagSuffix,
- const arg_string& longFlagSuffix,
- group& g)
-{
- for(auto& p : g) {
- if(p.is_group()) {
- with_suffixes_short_long(shortFlagSuffix, longFlagSuffix, p.as_group());
- } else {
- with_suffixes_short_long(shortFlagSuffix, longFlagSuffix, p.as_param());
- }
- }
- return g;
-}
-
-
-inline group&&
-with_suffixes_short_long(const arg_string& shortFlagSuffix,
- const arg_string& longFlagSuffix,
- group&& params)
-{
- return std::move(with_suffixes_short_long(shortFlagSuffix, longFlagSuffix,
- params));
-}
-
-
-template<class Param, class... Params>
-inline group
-with_suffixes_short_long(const arg_string& shortFlagSuffix,
- const arg_string& longFlagSuffix,
- Param&& param, Params&&... params)
-{
- return with_suffixes_short_long(shortFlagSuffix, longFlagSuffix,
- group{std::forward<Param>(param),
- std::forward<Params>(params)...});
-}
-
-
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief parsing implementation details
- *
- *****************************************************************************/
-
-namespace detail {
-
-
-/*************************************************************************//**
- *
- * @brief DFS traverser that keeps track of 'scopes'
- * scope = all parameters that are either bounded by
- * two blocking parameters on the same depth level
- * or the beginning/end of the outermost group
- *
- *****************************************************************************/
-class scoped_dfs_traverser
-{
-public:
- using dfs_traverser = group::depth_first_traverser;
-
- scoped_dfs_traverser() = default;
-
- explicit
- scoped_dfs_traverser(const group& g):
- pos_{g}, lastMatch_{}, posAfterLastMatch_{}, scopes_{},
- ignoreBlocks_{false},
- repeatGroupStarted_{false}, repeatGroupContinues_{false}
- {}
-
- const dfs_traverser& base() const noexcept { return pos_; }
- const dfs_traverser& last_match() const noexcept { return lastMatch_; }
-
- const group& parent() const noexcept { return pos_.parent(); }
-
- const group* innermost_repeat_group() const noexcept {
- return pos_.innermost_repeat_group();
- }
- const group* outermost_join_group() const noexcept {
- return pos_.outermost_join_group();
- }
- const group* innermost_blocking_group() const noexcept {
- return pos_.innermost_blocking_group();
- }
- const group* innermost_exclusive_group() const noexcept {
- return pos_.innermost_exclusive_group();
- }
-
- const pattern* operator ->() const noexcept { return pos_.operator->(); }
- const pattern& operator *() const noexcept { return *pos_; }
-
- const pattern* ptr() const noexcept { return pos_.operator->(); }
-
- explicit operator bool() const noexcept { return bool(pos_); }
-
- bool joinable() const noexcept { return pos_.joinable(); }
- arg_string common_flag_prefix() const { return pos_.common_flag_prefix(); }
-
- void ignore_blocking(bool yes) { ignoreBlocks_ = yes; }
-
- void invalidate() {
- pos_.invalidate();
- }
-
- bool matched() const noexcept {
- return (pos_ == lastMatch_);
- }
-
- bool start_of_repeat_group() const noexcept { return repeatGroupStarted_; }
-
- //-----------------------------------------------------
- scoped_dfs_traverser&
- next_sibling() { pos_.next_sibling(); return *this; }
-
- scoped_dfs_traverser&
- next_after_siblings() { pos_.next_after_siblings(); return *this; }
-
-
- //-----------------------------------------------------
- scoped_dfs_traverser&
- operator ++ ()
- {
- if(!pos_) return *this;
-
- if(pos_.is_last_in_path()) {
- return_to_outermost_scope();
- return *this;
- }
-
- //current pattern can block if it didn't match already
- if(ignoreBlocks_ || matched()) {
- ++pos_;
- }
- else if(!pos_->is_group()) {
- //current group can block if we didn't have any match in it
- const group* g = pos_.outermost_blocking_group_fully_explored();
- //no match in 'g' before -> skip to after its siblings
- if(g && !lastMatch_.is_inside(g)) {
- pos_.back_to_ancestor(g).next_after_siblings();
- if(!pos_) return_to_outermost_scope();
- }
- else if(pos_->blocking()) {
- if(pos_.parent().exclusive()) {
- pos_.next_sibling();
- } else {
- //no match => skip siblings of blocking param
- pos_.next_after_siblings();
- }
- if(!pos_) return_to_outermost_scope();
- } else {
- ++pos_;
- }
- } else {
- ++pos_;
- }
- check_if_left_scope();
- return *this;
- }
-
- //-----------------------------------------------------
- void next_after_match(scoped_dfs_traverser match)
- {
- if(!match || ignoreBlocks_) return;
-
- check_repeat_group_start(match);
-
- lastMatch_ = match.base();
-
- // if there is a blocking ancestor -> go back to it
- if(!match->blocking()) {
- match.pos_.back_to_ancestor(match.innermost_blocking_group());
- }
-
- //if match is not in current position & current position is blocking
- //=> current position has to be advanced by one so that it is
- //no longer reachable within current scope
- //(can happen for repeatable, blocking parameters)
- if(match.base() != pos_ && pos_->blocking()) pos_.next_sibling();
-
- if(match->blocking()) {
- if(match.pos_.is_alternative()) {
- //discard other alternatives
- match.pos_.skip_alternatives();
- }
-
- if(is_last_in_current_scope(match.pos_)) {
- //if current param is not repeatable -> back to previous scope
- if(!match->repeatable() && !match->is_group()) {
- pos_ = std::move(match.pos_);
- if(!scopes_.empty()) pos_.undo(scopes_.top());
- }
- else { //stay at match position
- pos_ = std::move(match.pos_);
- }
- }
- else { //not last in current group
- //if current param is not repeatable, go directly to next
- if(!match->repeatable() && !match->is_group()) {
- ++match.pos_;
- }
-
- if(match.pos_.level() > pos_.level()) {
- scopes_.push(pos_.undo_point());
- pos_ = std::move(match.pos_);
- }
- else if(match.pos_.level() < pos_.level()) {
- return_to_level(match.pos_.level());
- }
- else {
- pos_ = std::move(match.pos_);
- }
- }
- posAfterLastMatch_ = pos_;
- }
- else {
- if(match.pos_.level() < pos_.level()) {
- return_to_level(match.pos_.level());
- }
- posAfterLastMatch_ = pos_;
- }
- repeatGroupContinues_ = repeat_group_continues();
- }
-
-private:
- //-----------------------------------------------------
- bool is_last_in_current_scope(const dfs_traverser& pos) const
- {
- if(scopes_.empty()) return pos.is_last_in_path();
- //check if we would leave the current scope on ++
- auto p = pos;
- ++p;
- return p.level() < scopes_.top().level();
- }
-
- //-----------------------------------------------------
- void check_repeat_group_start(const scoped_dfs_traverser& newMatch)
- {
- const auto newrg = newMatch.innermost_repeat_group();
- if(!newrg) {
- repeatGroupStarted_ = false;
- }
- else if(lastMatch_.innermost_repeat_group() != newrg) {
- repeatGroupStarted_ = true;
- }
- else if(!repeatGroupContinues_ || !newMatch.repeatGroupContinues_) {
- repeatGroupStarted_ = true;
- }
- else {
- //special case: repeat group is outermost group
- //=> we can never really 'leave' and 'reenter' it
- //but if the current scope is the first element, then we are
- //conceptually at a position 'before' the group
- repeatGroupStarted_ = scopes_.empty() || (
- newrg == pos_.root() &&
- scopes_.top().param() == &(*pos_.root()->begin()) );
- }
- repeatGroupContinues_ = repeatGroupStarted_;
- }
-
- //-----------------------------------------------------
- bool repeat_group_continues() const
- {
- if(!repeatGroupContinues_) return false;
- const auto curRepGroup = pos_.innermost_repeat_group();
- if(!curRepGroup) return false;
- if(curRepGroup != lastMatch_.innermost_repeat_group()) return false;
- if(!posAfterLastMatch_) return false;
- return true;
- }
-
- //-----------------------------------------------------
- void check_if_left_scope()
- {
- if(posAfterLastMatch_) {
- if(pos_.level() < posAfterLastMatch_.level()) {
- while(!scopes_.empty() && scopes_.top().level() >= pos_.level()) {
- pos_.undo(scopes_.top());
- scopes_.pop();
- }
- posAfterLastMatch_.invalidate();
- }
- }
- while(!scopes_.empty() && scopes_.top().level() > pos_.level()) {
- pos_.undo(scopes_.top());
- scopes_.pop();
- }
- repeatGroupContinues_ = repeat_group_continues();
- }
-
- //-----------------------------------------------------
- void return_to_outermost_scope()
- {
- posAfterLastMatch_.invalidate();
-
- if(scopes_.empty()) {
- pos_.invalidate();
- repeatGroupContinues_ = false;
- return;
- }
-
- while(!scopes_.empty() && (!pos_ || pos_.level() >= 1)) {
- pos_.undo(scopes_.top());
- scopes_.pop();
- }
- while(!scopes_.empty()) scopes_.pop();
-
- repeatGroupContinues_ = repeat_group_continues();
- }
-
- //-----------------------------------------------------
- void return_to_level(int level)
- {
- if(pos_.level() <= level) return;
- while(!scopes_.empty() && pos_.level() > level) {
- pos_.undo(scopes_.top());
- scopes_.pop();
- }
- };
-
- dfs_traverser pos_;
- dfs_traverser lastMatch_;
- dfs_traverser posAfterLastMatch_;
- std::stack<dfs_traverser::memento> scopes_;
- bool ignoreBlocks_ = false;
- bool repeatGroupStarted_ = false;
- bool repeatGroupContinues_ = false;
-};
-
-
-
-
-/*****************************************************************************
- *
- * some parameter property predicates
- *
- *****************************************************************************/
-struct select_all {
- bool operator () (const parameter&) const noexcept { return true; }
-};
-
-struct select_flags {
- bool operator () (const parameter& p) const noexcept {
- return !p.flags().empty();
- }
-};
-
-struct select_values {
- bool operator () (const parameter& p) const noexcept {
- return p.flags().empty();
- }
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief result of a matching operation
- *
- *****************************************************************************/
-class match_t {
-public:
- using size_type = arg_string::size_type;
-
- match_t() = default;
-
- match_t(arg_string s, scoped_dfs_traverser p):
- str_{std::move(s)}, pos_{std::move(p)}
- {}
-
- size_type length() const noexcept { return str_.size(); }
-
- const arg_string& str() const noexcept { return str_; }
- const scoped_dfs_traverser& pos() const noexcept { return pos_; }
-
- explicit operator bool() const noexcept { return bool(pos_); }
-
-private:
- arg_string str_;
- scoped_dfs_traverser pos_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief finds the first parameter that matches a given string;
- * candidate parameters are traversed using a scoped DFS traverser
- *
- *****************************************************************************/
-template<class ParamSelector>
-match_t
-full_match(scoped_dfs_traverser pos, const arg_string& arg,
- const ParamSelector& select)
-{
- while(pos) {
- if(pos->is_param()) {
- const auto& param = pos->as_param();
- if(select(param)) {
- const auto match = param.match(arg);
- if(match && match.length() == arg.size()) {
- return match_t{arg, std::move(pos)};
- }
- }
- }
- ++pos;
- }
- return match_t{};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief finds the first parameter that matches any (non-empty) prefix
- * of a given string;
- * candidate parameters are traversed using a scoped DFS traverser
- *
- *****************************************************************************/
-template<class ParamSelector>
-match_t
-longest_prefix_match(scoped_dfs_traverser pos, const arg_string& arg,
- const ParamSelector& select)
-{
- match_t longest;
-
- while(pos) {
- if(pos->is_param()) {
- const auto& param = pos->as_param();
- if(select(param)) {
- auto match = param.match(arg);
- if(match.prefix()) {
- if(match.length() == arg.size()) {
- return match_t{arg, std::move(pos)};
- }
- else if(match.length() > longest.length()) {
- longest = match_t{arg.substr(match.at(), match.length()),
- pos};
- }
- }
- }
- }
- ++pos;
- }
- return longest;
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief finds the first parameter that partially matches a given string;
- * candidate parameters are traversed using a scoped DFS traverser
- *
- *****************************************************************************/
-template<class ParamSelector>
-match_t
-partial_match(scoped_dfs_traverser pos, const arg_string& arg,
- const ParamSelector& select)
-{
- while(pos) {
- if(pos->is_param()) {
- const auto& param = pos->as_param();
- if(select(param)) {
- const auto match = param.match(arg);
- if(match) {
- return match_t{arg.substr(match.at(), match.length()),
- std::move(pos)};
- }
- }
- }
- ++pos;
- }
- return match_t{};
-}
-
-} //namespace detail
-
-
-
-
-
-
-/***************************************************************//**
- *
- * @brief default command line arguments parser
- *
- *******************************************************************/
-class parser
-{
-public:
- using dfs_traverser = group::depth_first_traverser;
- using scoped_dfs_traverser = detail::scoped_dfs_traverser;
-
-
- /*****************************************************//**
- * @brief arg -> parameter mapping
- *********************************************************/
- class arg_mapping {
- public:
- friend class parser;
-
- explicit
- arg_mapping(arg_index idx, arg_string s,
- const dfs_traverser& match)
- :
- index_{idx}, arg_{std::move(s)}, match_{match},
- repeat_{0}, startsRepeatGroup_{false},
- blocked_{false}, conflict_{false}
- {}
-
- explicit
- arg_mapping(arg_index idx, arg_string s) :
- index_{idx}, arg_{std::move(s)}, match_{},
- repeat_{0}, startsRepeatGroup_{false},
- blocked_{false}, conflict_{false}
- {}
-
- arg_index index() const noexcept { return index_; }
- const arg_string& arg() const noexcept { return arg_; }
-
- const parameter* param() const noexcept {
- return match_ && match_->is_param()
- ? &(match_->as_param()) : nullptr;
- }
-
- std::size_t repeat() const noexcept { return repeat_; }
-
- bool blocked() const noexcept { return blocked_; }
- bool conflict() const noexcept { return conflict_; }
-
- bool bad_repeat() const noexcept {
- if(!param()) return false;
- return repeat_ > 0 && !param()->repeatable()
- && !match_.innermost_repeat_group();
- }
-
- bool any_error() const noexcept {
- return !match_ || blocked() || conflict() || bad_repeat();
- }
-
- private:
- arg_index index_;
- arg_string arg_;
- dfs_traverser match_;
- std::size_t repeat_;
- bool startsRepeatGroup_;
- bool blocked_;
- bool conflict_;
- };
-
- /*****************************************************//**
- * @brief references a non-matched, required parameter
- *********************************************************/
- class missing_event {
- public:
- explicit
- missing_event(const parameter* p, arg_index after):
- param_{p}, aftIndex_{after}
- {}
-
- const parameter* param() const noexcept { return param_; }
-
- arg_index after_index() const noexcept { return aftIndex_; }
-
- private:
- const parameter* param_;
- arg_index aftIndex_;
- };
-
- //-----------------------------------------------------
- using missing_events = std::vector<missing_event>;
- using arg_mappings = std::vector<arg_mapping>;
-
-
-private:
- struct miss_candidate {
- miss_candidate(dfs_traverser p, arg_index idx,
- bool firstInRepeatGroup = false):
- pos{std::move(p)}, index{idx},
- startsRepeatGroup{firstInRepeatGroup}
- {}
-
- dfs_traverser pos;
- arg_index index;
- bool startsRepeatGroup;
- };
- using miss_candidates = std::vector<miss_candidate>;
-
-
-public:
- //---------------------------------------------------------------
- /** @brief initializes parser with a command line interface
- * @param offset = argument index offset used for reports
- * */
- explicit
- parser(const group& root, arg_index offset = 0):
- root_{&root}, pos_{root},
- index_{offset-1}, eaten_{0},
- args_{}, missCand_{}, blocked_{false}
- {
- for_each_potential_miss(dfs_traverser{root},
- [this](const dfs_traverser& p){
- missCand_.emplace_back(p, index_);
- });
- }
-
-
- //---------------------------------------------------------------
- /** @brief processes one command line argument */
- bool operator() (const arg_string& arg)
- {
- ++eaten_;
- ++index_;
-
- if(!valid()) return false;
-
- if(!blocked_ && try_match(arg)) return true;
-
- if(try_match_blocked(arg)) return false;
-
- //skipping of blocking & required patterns is not allowed
- if(!blocked_ && !pos_.matched() && pos_->required() && pos_->blocking()) {
- blocked_ = true;
- }
-
- add_nomatch(arg);
- return false;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns range of argument -> parameter mappings */
- const arg_mappings& args() const {
- return args_;
- }
-
- /** @brief returns list of missing events */
- missing_events missed() const {
- missing_events misses;
- misses.reserve(missCand_.size());
- for(auto i = missCand_.begin(); i != missCand_.end(); ++i) {
- misses.emplace_back(&(i->pos->as_param()), i->index);
- }
- return misses;
- }
-
- /** @brief returns number of processed command line arguments */
- arg_index parse_count() const noexcept { return eaten_; }
-
- /** @brief returns false if previously processed command line arguments
- * lead to an invalid / inconsistent parsing result
- */
- bool valid() const noexcept { return bool(pos_); }
-
- /** @brief returns false if previously processed command line arguments
- * lead to an invalid / inconsistent parsing result
- */
- explicit operator bool() const noexcept { return valid(); }
-
-
-private:
- //---------------------------------------------------------------
- using match_t = detail::match_t;
-
-
- //---------------------------------------------------------------
- /** @brief try to match argument with unreachable parameter */
- bool try_match_blocked(const arg_string& arg)
- {
- //try to match ahead (using temporary parser)
- if(pos_) {
- auto ahead = *this;
- if(try_match_blocked(std::move(ahead), arg)) return true;
- }
-
- //try to match from the beginning (using temporary parser)
- if(root_) {
- parser all{*root_, index_+1};
- if(try_match_blocked(std::move(all), arg)) return true;
- }
-
- return false;
- }
-
- //---------------------------------------------------------------
- bool try_match_blocked(parser&& parse, const arg_string& arg)
- {
- const auto nold = int(parse.args_.size());
-
- parse.pos_.ignore_blocking(true);
-
- if(!parse.try_match(arg)) return false;
-
- for(auto i = parse.args_.begin() + nold; i != parse.args_.end(); ++i) {
- args_.push_back(*i);
- args_.back().blocked_ = true;
- }
- return true;
- }
-
- //---------------------------------------------------------------
- /** @brief try to find a parameter/pattern that matches 'arg' */
- bool try_match(const arg_string& arg)
- {
- //match greedy parameters before everything else
- if(pos_->is_param() && pos_->blocking() && pos_->as_param().greedy()) {
- const auto match = pos_->as_param().match(arg);
- if(match && match.length() == arg.size()) {
- add_match(detail::match_t{arg,pos_});
- return true;
- }
- }
-
- //try flags first (alone, joinable or strict sequence)
- if(try_match_full(arg, detail::select_flags{})) return true;
- if(try_match_joined_flags(arg)) return true;
- if(try_match_joined_sequence(arg, detail::select_flags{})) return true;
- //try value params (alone or strict sequence)
- if(try_match_full(arg, detail::select_values{})) return true;
- if(try_match_joined_sequence(arg, detail::select_all{})) return true;
- //try joinable params + values in any order
- if(try_match_joined_params(arg)) return true;
- return false;
- }
-
- //---------------------------------------------------------------
- /**
- * @brief try to match full argument
- * @param select : predicate that candidate parameters must satisfy
- */
- template<class ParamSelector>
- bool try_match_full(const arg_string& arg, const ParamSelector& select)
- {
- auto match = detail::full_match(pos_, arg, select);
- if(!match) return false;
- add_match(match);
- return true;
- }
-
- //---------------------------------------------------------------
- /**
- * @brief try to match argument as blocking sequence of parameters
- * @param select : predicate that a parameter matching the prefix of
- * 'arg' must satisfy
- */
- template<class ParamSelector>
- bool try_match_joined_sequence(arg_string arg,
- const ParamSelector& acceptFirst)
- {
- auto fstMatch = detail::longest_prefix_match(pos_, arg, acceptFirst);
-
- if(!fstMatch) return false;
-
- if(fstMatch.str().size() == arg.size()) {
- add_match(fstMatch);
- return true;
- }
-
- if(!fstMatch.pos()->blocking()) return false;
-
- auto pos = fstMatch.pos();
- pos.ignore_blocking(true);
- const auto parent = &pos.parent();
- if(!pos->repeatable()) ++pos;
-
- arg.erase(0, fstMatch.str().size());
- std::vector<match_t> matches { std::move(fstMatch) };
-
- while(!arg.empty() && pos &&
- pos->blocking() && pos->is_param() &&
- (&pos.parent() == parent))
- {
- auto match = pos->as_param().match(arg);
-
- if(match.prefix()) {
- matches.emplace_back(arg.substr(0,match.length()), pos);
- arg.erase(0, match.length());
- if(!pos->repeatable()) ++pos;
- }
- else {
- if(!pos->repeatable()) return false;
- ++pos;
- }
-
- }
- //if arg not fully covered => discard temporary matches
- if(!arg.empty() || matches.empty()) return false;
-
- for(const auto& m : matches) add_match(m);
- return true;
- }
-
- //-----------------------------------------------------
- /** @brief try to match 'arg' as a concatenation of joinable flags */
- bool try_match_joined_flags(const arg_string& arg)
- {
- return find_join_group(pos_, [&](const group& g) {
- return try_match_joined(g, arg, detail::select_flags{},
- g.common_flag_prefix());
- });
- }
-
- //---------------------------------------------------------------
- /** @brief try to match 'arg' as a concatenation of joinable parameters */
- bool try_match_joined_params(const arg_string& arg)
- {
- return find_join_group(pos_, [&](const group& g) {
- return try_match_joined(g, arg, detail::select_all{});
- });
- }
-
- //-----------------------------------------------------
- /** @brief try to match 'arg' as concatenation of joinable parameters
- * that are all contained within one group
- */
- template<class ParamSelector>
- bool try_match_joined(const group& joinGroup, arg_string arg,
- const ParamSelector& select,
- const arg_string& prefix = "")
- {
- //temporary parser with 'joinGroup' as top-level group
- parser parse {joinGroup};
- //records temporary matches
- std::vector<match_t> matches;
-
- while(!arg.empty()) {
- auto match = detail::longest_prefix_match(parse.pos_, arg, select);
-
- if(!match) return false;
-
- arg.erase(0, match.str().size());
- //make sure prefix is always present after the first match
- //so that, e.g., flags "-a" and "-b" will be found in "-ab"
- if(!arg.empty() && !prefix.empty() && arg.find(prefix) != 0 &&
- prefix != match.str())
- {
- arg.insert(0,prefix);
- }
-
- parse.add_match(match);
- matches.push_back(std::move(match));
- }
-
- if(!arg.empty() || matches.empty()) return false;
-
- if(!parse.missCand_.empty()) return false;
- for(const auto& a : parse.args_) if(a.any_error()) return false;
-
- //replay matches onto *this
- for(const auto& m : matches) add_match(m);
- return true;
- }
-
- //-----------------------------------------------------
- template<class GroupSelector>
- bool find_join_group(const scoped_dfs_traverser& start,
- const GroupSelector& accept) const
- {
- if(start && start.parent().joinable()) {
- const auto& g = start.parent();
- if(accept(g)) return true;
- return false;
- }
-
- auto pos = start;
- while(pos) {
- if(pos->is_group() && pos->as_group().joinable()) {
- const auto& g = pos->as_group();
- if(accept(g)) return true;
- pos.next_sibling();
- }
- else {
- ++pos;
- }
- }
- return false;
- }
-
-
- //---------------------------------------------------------------
- void add_nomatch(const arg_string& arg) {
- args_.emplace_back(index_, arg);
- }
-
-
- //---------------------------------------------------------------
- void add_match(const match_t& match)
- {
- const auto& pos = match.pos();
- if(!pos || !pos->is_param()) return;
-
- pos_.next_after_match(pos);
-
- arg_mapping newArg{index_, match.str(), pos.base()};
- newArg.repeat_ = occurrences_of(&pos->as_param());
- newArg.conflict_ = check_conflicts(pos.base());
- newArg.startsRepeatGroup_ = pos_.start_of_repeat_group();
- args_.push_back(std::move(newArg));
-
- add_miss_candidates_after(pos);
- clean_miss_candidates_for(pos.base());
- discard_alternative_miss_candidates(pos.base());
-
- }
-
- //-----------------------------------------------------
- bool check_conflicts(const dfs_traverser& match)
- {
- if(pos_.start_of_repeat_group()) return false;
- bool conflict = false;
- for(const auto& m : match.stack()) {
- if(m.parent->exclusive()) {
- for(auto i = args_.rbegin(); i != args_.rend(); ++i) {
- if(!i->blocked()) {
- for(const auto& c : i->match_.stack()) {
- //sibling within same exclusive group => conflict
- if(c.parent == m.parent && c.cur != m.cur) {
- conflict = true;
- i->conflict_ = true;
- }
- }
- }
- //check for conflicts only within current repeat cycle
- if(i->startsRepeatGroup_) break;
- }
- }
- }
- return conflict;
- }
-
- //-----------------------------------------------------
- void clean_miss_candidates_for(const dfs_traverser& match)
- {
- auto i = std::find_if(missCand_.rbegin(), missCand_.rend(),
- [&](const miss_candidate& m) {
- return &(*m.pos) == &(*match);
- });
-
- if(i != missCand_.rend()) {
- missCand_.erase(prev(i.base()));
- }
- }
-
- //-----------------------------------------------------
- void discard_alternative_miss_candidates(const dfs_traverser& match)
- {
- if(missCand_.empty()) return;
- //find out, if miss candidate is sibling of one of the same
- //alternative groups that the current match is a member of
- //if so, we can discard the miss
-
- //go through all exclusive groups of matching pattern
- for(const auto& m : match.stack()) {
- if(m.parent->exclusive()) {
- for(auto i = int(missCand_.size())-1; i >= 0; --i) {
- bool removed = false;
- for(const auto& c : missCand_[i].pos.stack()) {
- //sibling within same exclusive group => discard
- if(c.parent == m.parent && c.cur != m.cur) {
- missCand_.erase(missCand_.begin() + i);
- if(missCand_.empty()) return;
- removed = true;
- break;
- }
- }
- //remove miss candidates only within current repeat cycle
- if(i > 0 && removed) {
- if(missCand_[i-1].startsRepeatGroup) break;
- } else {
- if(missCand_[i].startsRepeatGroup) break;
- }
- }
- }
- }
- }
-
- //-----------------------------------------------------
- void add_miss_candidates_after(const scoped_dfs_traverser& match)
- {
- auto npos = match.base();
- if(npos.is_alternative()) npos.skip_alternatives();
- ++npos;
- //need to add potential misses if:
- //either new repeat group was started
- const auto newRepGroup = match.innermost_repeat_group();
- if(newRepGroup) {
- if(pos_.start_of_repeat_group()) {
- for_each_potential_miss(std::move(npos),
- [&,this](const dfs_traverser& pos) {
- //only add candidates within repeat group
- if(newRepGroup == pos.innermost_repeat_group()) {
- missCand_.emplace_back(pos, index_, true);
- }
- });
- }
- }
- //... or an optional blocking param was hit
- else if(match->blocking() && !match->required() &&
- npos.level() >= match.base().level())
- {
- for_each_potential_miss(std::move(npos),
- [&,this](const dfs_traverser& pos) {
- //only add new candidates
- if(std::find_if(missCand_.begin(), missCand_.end(),
- [&](const miss_candidate& c){
- return &(*c.pos) == &(*pos);
- }) == missCand_.end())
- {
- missCand_.emplace_back(pos, index_);
- }
- });
- }
-
- }
-
- //-----------------------------------------------------
- template<class Action>
- static void
- for_each_potential_miss(dfs_traverser pos, Action&& action)
- {
- const auto level = pos.level();
- while(pos && pos.level() >= level) {
- if(pos->is_group() ) {
- const auto& g = pos->as_group();
- if(g.all_optional() || (g.exclusive() && g.any_optional())) {
- pos.next_sibling();
- } else {
- ++pos;
- }
- } else { //param
- if(pos->required()) {
- action(pos);
- ++pos;
- } else if(pos->blocking()) { //optional + blocking
- pos.next_after_siblings();
- } else {
- ++pos;
- }
- }
- }
- }
-
-
- //---------------------------------------------------------------
- std::size_t occurrences_of(const parameter* p) const
- {
- if(!p) return 0;
-
- auto i = std::find_if(args_.rbegin(), args_.rend(),
- [p](const arg_mapping& a){ return a.param() == p; });
-
- if(i != args_.rend()) return i->repeat() + 1;
- return 0;
- }
-
-
- //---------------------------------------------------------------
- const group* root_;
- scoped_dfs_traverser pos_;
- arg_index index_;
- arg_index eaten_;
- arg_mappings args_;
- miss_candidates missCand_;
- bool blocked_;
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief contains argument -> parameter mappings
- * and missing parameters
- *
- *****************************************************************************/
-class parsing_result
-{
-public:
- using arg_mapping = parser::arg_mapping;
- using arg_mappings = parser::arg_mappings;
- using missing_event = parser::missing_event;
- using missing_events = parser::missing_events;
- using iterator = arg_mappings::const_iterator;
-
- //-----------------------------------------------------
- /** @brief default: empty result */
- parsing_result() = default;
-
- parsing_result(arg_mappings arg2param, missing_events misses):
- arg2param_{std::move(arg2param)}, missing_{std::move(misses)}
- {}
-
- //-----------------------------------------------------
- /** @brief returns number of arguments that could not be mapped to
- * a parameter
- */
- arg_mappings::size_type
- unmapped_args_count() const noexcept {
- return std::count_if(arg2param_.begin(), arg2param_.end(),
- [](const arg_mapping& a){ return !a.param(); });
- }
-
- /** @brief returns if any argument could only be matched by an
- * unreachable parameter
- */
- bool any_blocked() const noexcept {
- return std::any_of(arg2param_.begin(), arg2param_.end(),
- [](const arg_mapping& a){ return a.blocked(); });
- }
-
- /** @brief returns if any argument matched more than one parameter
- * that were mutually exclusive */
- bool any_conflict() const noexcept {
- return std::any_of(arg2param_.begin(), arg2param_.end(),
- [](const arg_mapping& a){ return a.conflict(); });
- }
-
- /** @brief returns if any parameter matched repeatedly although
- * it was not allowed to */
- bool any_bad_repeat() const noexcept {
- return std::any_of(arg2param_.begin(), arg2param_.end(),
- [](const arg_mapping& a){ return a.bad_repeat(); });
- }
-
- /** @brief returns true if any parsing error / violation of the
- * command line interface definition occurred */
- bool any_error() const noexcept {
- return unmapped_args_count() > 0 || !missing().empty() ||
- any_blocked() || any_conflict() || any_bad_repeat();
- }
-
- /** @brief returns true if no parsing error / violation of the
- * command line interface definition occurred */
- explicit operator bool() const noexcept { return !any_error(); }
-
- /** @brief access to range of missing parameter match events */
- const missing_events& missing() const noexcept { return missing_; }
-
- /** @brief returns non-mutating iterator to position of
- * first argument -> parameter mapping */
- iterator begin() const noexcept { return arg2param_.begin(); }
- /** @brief returns non-mutating iterator to position one past the
- * last argument -> parameter mapping */
- iterator end() const noexcept { return arg2param_.end(); }
-
-private:
- //-----------------------------------------------------
- arg_mappings arg2param_;
- missing_events missing_;
-};
-
-
-
-
-namespace detail {
-namespace {
-
-/*************************************************************************//**
- *
- * @brief correct some common problems
- * does not - and MUST NOT - change the number of arguments
- * (no insertions or deletions allowed)
- *
- *****************************************************************************/
-void sanitize_args(arg_list& args)
-{
- //e.g. {"-o12", ".34"} -> {"-o", "12.34"}
-
- if(args.empty()) return;
-
- for(auto i = begin(args)+1; i != end(args); ++i) {
- if(i != begin(args) && i->size() > 1 &&
- i->find('.') == 0 && std::isdigit((*i)[1]) )
- {
- //find trailing digits in previous arg
- using std::prev;
- auto& prv = *prev(i);
- auto fstDigit = std::find_if_not(prv.rbegin(), prv.rend(),
- [](arg_string::value_type c){
- return std::isdigit(c);
- }).base();
-
- //handle leading sign
- if(fstDigit > prv.begin() &&
- (*prev(fstDigit) == '+' || *prev(fstDigit) == '-'))
- {
- --fstDigit;
- }
-
- //prepend digits from previous arg
- i->insert(begin(*i), fstDigit, end(prv));
-
- //erase digits in previous arg
- prv.erase(fstDigit, end(prv));
- }
- }
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief executes actions based on a parsing result
- *
- *****************************************************************************/
-void execute_actions(const parsing_result& res)
-{
- for(const auto& m : res) {
- if(m.param()) {
- const auto& param = *(m.param());
-
- if(m.repeat() > 0) param.notify_repeated(m.index());
- if(m.blocked()) param.notify_blocked(m.index());
- if(m.conflict()) param.notify_conflict(m.index());
- //main action
- if(!m.any_error()) param.execute_actions(m.arg());
- }
- }
-
- for(auto m : res.missing()) {
- if(m.param()) m.param()->notify_missing(m.after_index());
- }
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief parses input args
- *
- *****************************************************************************/
-static parsing_result
-parse_args(const arg_list& args, const group& cli,
- arg_index offset = 0)
-{
- //parse args and store unrecognized arg indices
- parser parse{cli, offset};
- for(const auto& arg : args) {
- parse(arg);
- if(!parse.valid()) break;
- }
-
- return parsing_result{parse.args(), parse.missed()};
-}
-
-/*************************************************************************//**
- *
- * @brief parses input args & executes actions
- *
- *****************************************************************************/
-static parsing_result
-parse_and_execute(const arg_list& args, const group& cli,
- arg_index offset = 0)
-{
- auto result = parse_args(args, cli, offset);
-
- execute_actions(result);
-
- return result;
-}
-
-} //anonymous namespace
-} // namespace detail
-
-
-
-
-/*************************************************************************//**
- *
- * @brief parses vector of arg strings and executes actions
- *
- *****************************************************************************/
-inline parsing_result
-parse(arg_list args, const group& cli)
-{
- //detail::sanitize_args(args);
- return detail::parse_and_execute(args, cli);
-}
-
-
-/*************************************************************************//**
- *
- * @brief parses initializer_list of C-style arg strings and executes actions
- *
- *****************************************************************************/
-inline parsing_result
-parse(std::initializer_list<const char*> arglist, const group& cli)
-{
- arg_list args;
- args.reserve(arglist.size());
- for(auto a : arglist) {
- args.push_back(a);
- }
-
- return parse(std::move(args), cli);
-}
-
-
-/*************************************************************************//**
- *
- * @brief parses range of arg strings and executes actions
- *
- *****************************************************************************/
-template<class InputIterator>
-inline parsing_result
-parse(InputIterator first, InputIterator last, const group& cli)
-{
- return parse(arg_list(first,last), cli);
-}
-
-
-/*************************************************************************//**
- *
- * @brief parses the standard array of command line arguments; omits argv[0]
- *
- *****************************************************************************/
-inline parsing_result
-parse(const int argc, char* argv[], const group& cli, arg_index offset = 1)
-{
- arg_list args;
- if(offset < argc) args.assign(argv+offset, argv+argc);
- //detail::sanitize_args(args);
- return detail::parse_and_execute(args, cli, offset);
-}
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief filter predicate for parameters and groups;
- * Can be used to limit documentation generation to parameter subsets.
- *
- *****************************************************************************/
-class param_filter
-{
-public:
- /** @brief only allow parameters with given prefix */
- param_filter& prefix(const arg_string& p) noexcept {
- prefix_ = p; return *this;
- }
- /** @brief only allow parameters with given prefix */
- param_filter& prefix(arg_string&& p) noexcept {
- prefix_ = std::move(p); return *this;
- }
- const arg_string& prefix() const noexcept { return prefix_; }
-
- /** @brief only allow parameters with given requirement status */
- param_filter& required(tri t) noexcept { required_ = t; return *this; }
- tri required() const noexcept { return required_; }
-
- /** @brief only allow parameters with given blocking status */
- param_filter& blocking(tri t) noexcept { blocking_ = t; return *this; }
- tri blocking() const noexcept { return blocking_; }
-
- /** @brief only allow parameters with given repeatable status */
- param_filter& repeatable(tri t) noexcept { repeatable_ = t; return *this; }
- tri repeatable() const noexcept { return repeatable_; }
-
- /** @brief only allow parameters with given docstring status */
- param_filter& has_doc(tri t) noexcept { hasDoc_ = t; return *this; }
- tri has_doc() const noexcept { return hasDoc_; }
-
-
- /** @brief returns true, if parameter satisfies all filters */
- bool operator() (const parameter& p) const noexcept {
- if(!prefix_.empty()) {
- if(!std::any_of(p.flags().begin(), p.flags().end(),
- [&](const arg_string& flag){
- return str::has_prefix(flag, prefix_);
- })) return false;
- }
- if(required() != p.required()) return false;
- if(blocking() != p.blocking()) return false;
- if(repeatable() != p.repeatable()) return false;
- if(has_doc() != !p.doc().empty()) return false;
- return true;
- }
-
-private:
- arg_string prefix_;
- tri required_ = tri::either;
- tri blocking_ = tri::either;
- tri repeatable_ = tri::either;
- tri hasDoc_ = tri::yes;
-};
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief documentation formatting options
- *
- *****************************************************************************/
-class doc_formatting
-{
-public:
- using string = doc_string;
-
- /** @brief same as 'first_column' */
-#if __cplusplus >= 201402L
- [[deprecated]]
-#endif
- doc_formatting& start_column(int col) { return first_column(col); }
-#if __cplusplus >= 201402L
- [[deprecated]]
-#endif
- int start_column() const noexcept { return first_column(); }
-
- /** @brief determines column where documentation printing starts */
- doc_formatting&
- first_column(int col) {
- //limit to [0,last_column] but push doc_column to the right if necessary
- if(col < 0) col = 0;
- else if(col > last_column()) col = last_column();
- if(col > doc_column()) doc_column(first_column());
- firstCol_ = col;
- return *this;
- }
- int first_column() const noexcept {
- return firstCol_;
- }
-
- /** @brief determines column where docstrings start */
- doc_formatting&
- doc_column(int col) {
- //limit to [first_column,last_column]
- if(col < 0) col = 0;
- else if(col < first_column()) col = first_column();
- else if(col > last_column()) col = last_column();
- docCol_ = col;
- return *this;
- }
- int doc_column() const noexcept {
- return docCol_;
- }
-
- /** @brief determines column that no documentation text must exceed;
- * (text should be wrapped appropriately after this column)
- */
- doc_formatting&
- last_column(int col) {
- //limit to [first_column,oo] but push doc_column to the left if necessary
- if(col < first_column()) col = first_column();
- if(col < doc_column()) doc_column(col);
- lastCol_ = col;
- return *this;
- }
-
- int last_column() const noexcept {
- return lastCol_;
- }
-
- /** @brief determines indent of documentation lines
- * for children of a documented group */
- doc_formatting& indent_size(int indent) { indentSize_ = indent; return *this; }
- int indent_size() const noexcept { return indentSize_; }
-
- /** @brief determines string to be used
- * if a parameter has no flags and no label */
- doc_formatting& empty_label(const string& label) {
- emptyLabel_ = label;
- return *this;
- }
- const string& empty_label() const noexcept { return emptyLabel_; }
-
- /** @brief determines string for separating parameters */
- doc_formatting& param_separator(const string& sep) {
- paramSep_ = sep;
- return *this;
- }
- const string& param_separator() const noexcept { return paramSep_; }
-
- /** @brief determines string for separating groups (in usage lines) */
- doc_formatting& group_separator(const string& sep) {
- groupSep_ = sep;
- return *this;
- }
- const string& group_separator() const noexcept { return groupSep_; }
-
- /** @brief determines string for separating alternative parameters */
- doc_formatting& alternative_param_separator(const string& sep) {
- altParamSep_ = sep;
- return *this;
- }
- const string& alternative_param_separator() const noexcept { return altParamSep_; }
-
- /** @brief determines string for separating alternative groups */
- doc_formatting& alternative_group_separator(const string& sep) {
- altGroupSep_ = sep;
- return *this;
- }
- const string& alternative_group_separator() const noexcept { return altGroupSep_; }
-
- /** @brief determines string for separating flags of the same parameter */
- doc_formatting& flag_separator(const string& sep) {
- flagSep_ = sep;
- return *this;
- }
- const string& flag_separator() const noexcept { return flagSep_; }
-
- /** @brief determines strings surrounding parameter labels */
- doc_formatting&
- surround_labels(const string& prefix, const string& postfix) {
- labelPre_ = prefix;
- labelPst_ = postfix;
- return *this;
- }
- const string& label_prefix() const noexcept { return labelPre_; }
- const string& label_postfix() const noexcept { return labelPst_; }
-
- /** @brief determines strings surrounding optional parameters/groups */
- doc_formatting&
- surround_optional(const string& prefix, const string& postfix) {
- optionPre_ = prefix;
- optionPst_ = postfix;
- return *this;
- }
- const string& optional_prefix() const noexcept { return optionPre_; }
- const string& optional_postfix() const noexcept { return optionPst_; }
-
- /** @brief determines strings surrounding repeatable parameters/groups */
- doc_formatting&
- surround_repeat(const string& prefix, const string& postfix) {
- repeatPre_ = prefix;
- repeatPst_ = postfix;
- return *this;
- }
- const string& repeat_prefix() const noexcept { return repeatPre_; }
- const string& repeat_postfix() const noexcept { return repeatPst_; }
-
- /** @brief determines strings surrounding exclusive groups */
- doc_formatting&
- surround_alternatives(const string& prefix, const string& postfix) {
- alternPre_ = prefix;
- alternPst_ = postfix;
- return *this;
- }
- const string& alternatives_prefix() const noexcept { return alternPre_; }
- const string& alternatives_postfix() const noexcept { return alternPst_; }
-
- /** @brief determines strings surrounding alternative flags */
- doc_formatting&
- surround_alternative_flags(const string& prefix, const string& postfix) {
- alternFlagPre_ = prefix;
- alternFlagPst_ = postfix;
- return *this;
- }
- const string& alternative_flags_prefix() const noexcept { return alternFlagPre_; }
- const string& alternative_flags_postfix() const noexcept { return alternFlagPst_; }
-
- /** @brief determines strings surrounding non-exclusive groups */
- doc_formatting&
- surround_group(const string& prefix, const string& postfix) {
- groupPre_ = prefix;
- groupPst_ = postfix;
- return *this;
- }
- const string& group_prefix() const noexcept { return groupPre_; }
- const string& group_postfix() const noexcept { return groupPst_; }
-
- /** @brief determines strings surrounding joinable groups */
- doc_formatting&
- surround_joinable(const string& prefix, const string& postfix) {
- joinablePre_ = prefix;
- joinablePst_ = postfix;
- return *this;
- }
- const string& joinable_prefix() const noexcept { return joinablePre_; }
- const string& joinable_postfix() const noexcept { return joinablePst_; }
-
- /** @brief determines maximum number of flags per parameter to be printed
- * in detailed parameter documentation lines */
- doc_formatting& max_flags_per_param_in_doc(int max) {
- maxAltInDocs_ = max > 0 ? max : 0;
- return *this;
- }
- int max_flags_per_param_in_doc() const noexcept { return maxAltInDocs_; }
-
- /** @brief determines maximum number of flags per parameter to be printed
- * in usage lines */
- doc_formatting& max_flags_per_param_in_usage(int max) {
- maxAltInUsage_ = max > 0 ? max : 0;
- return *this;
- }
- int max_flags_per_param_in_usage() const noexcept { return maxAltInUsage_; }
-
- /** @brief determines number of empty rows after one single-line
- * documentation entry */
- doc_formatting& line_spacing(int lines) {
- lineSpc_ = lines > 0 ? lines : 0;
- return *this;
- }
- int line_spacing() const noexcept { return lineSpc_; }
-
- /** @brief determines number of empty rows before and after a paragraph;
- * a paragraph is defined by a documented group or if
- * a parameter documentation entry used more than one line */
- doc_formatting& paragraph_spacing(int lines) {
- paragraphSpc_ = lines > 0 ? lines : 0;
- return *this;
- }
- int paragraph_spacing() const noexcept { return paragraphSpc_; }
-
- /** @brief determines if alternative flags with a common prefix should
- * be printed in a merged fashion */
- doc_formatting& merge_alternative_flags_with_common_prefix(bool yes = true) {
- mergeAltCommonPfx_ = yes;
- return *this;
- }
- bool merge_alternative_flags_with_common_prefix() const noexcept {
- return mergeAltCommonPfx_;
- }
-
- /** @brief determines if joinable flags with a common prefix should
- * be printed in a merged fashion */
- doc_formatting& merge_joinable_with_common_prefix(bool yes = true) {
- mergeJoinableCommonPfx_ = yes;
- return *this;
- }
- bool merge_joinable_with_common_prefix() const noexcept {
- return mergeJoinableCommonPfx_;
- }
-
- /** @brief determines if children of exclusive groups should be printed
- * on individual lines if the exceed 'alternatives_min_split_size'
- */
- doc_formatting& split_alternatives(bool yes = true) {
- splitTopAlt_ = yes;
- return *this;
- }
- bool split_alternatives() const noexcept {
- return splitTopAlt_;
- }
-
- /** @brief determines how many children exclusive groups can have before
- * their children are printed on individual usage lines */
- doc_formatting& alternatives_min_split_size(int size) {
- groupSplitSize_ = size > 0 ? size : 0;
- return *this;
- }
- int alternatives_min_split_size() const noexcept { return groupSplitSize_; }
-
- /** @brief determines whether to ignore new line characters in docstrings
- */
- doc_formatting& ignore_newline_chars(bool yes = true) {
- ignoreNewlines_ = yes;
- return *this;
- }
- bool ignore_newline_chars() const noexcept {
- return ignoreNewlines_;
- }
-
-private:
- string paramSep_ = string(" ");
- string groupSep_ = string(" ");
- string altParamSep_ = string("|");
- string altGroupSep_ = string(" | ");
- string flagSep_ = string(", ");
- string labelPre_ = string("<");
- string labelPst_ = string(">");
- string optionPre_ = string("[");
- string optionPst_ = string("]");
- string repeatPre_ = string("");
- string repeatPst_ = string("...");
- string groupPre_ = string("(");
- string groupPst_ = string(")");
- string alternPre_ = string("(");
- string alternPst_ = string(")");
- string alternFlagPre_ = string("");
- string alternFlagPst_ = string("");
- string joinablePre_ = string("(");
- string joinablePst_ = string(")");
- string emptyLabel_ = string("");
- int firstCol_ = 8;
- int docCol_ = 20;
- int lastCol_ = 100;
- int indentSize_ = 4;
- int maxAltInUsage_ = 1;
- int maxAltInDocs_ = 32;
- int lineSpc_ = 0;
- int paragraphSpc_ = 1;
- int groupSplitSize_ = 3;
- bool splitTopAlt_ = true;
- bool mergeAltCommonPfx_ = false;
- bool mergeJoinableCommonPfx_ = true;
- bool ignoreNewlines_ = false;
-};
-
-
-
-namespace detail {
-
-/*************************************************************************//**
- *
- * @brief stream decorator
- * that applies formatting like line wrapping
- *
- *****************************************************************************/
-template<class OStream = std::ostream, class StringT = doc_string>
-class formatting_ostream
-{
-public:
- using string_type = StringT;
- using size_type = typename string_type::size_type;
- using char_type = typename string_type::value_type;
-
- formatting_ostream(OStream& os):
- os_(os),
- curCol_{0}, firstCol_{0}, lastCol_{100},
- hangingIndent_{0}, paragraphSpacing_{0}, paragraphSpacingThreshold_{2},
- curBlankLines_{0}, curParagraphLines_{1},
- totalNonBlankLines_{0},
- ignoreInputNls_{false}
- {}
-
-
- //---------------------------------------------------------------
- const OStream& base() const noexcept { return os_; }
- OStream& base() noexcept { return os_; }
-
- bool good() const { return os_.good(); }
-
-
- //---------------------------------------------------------------
- /** @brief determines the leftmost border of the text body */
- formatting_ostream& first_column(int c) {
- firstCol_ = c < 0 ? 0 : c;
- return *this;
- }
- int first_column() const noexcept { return firstCol_; }
-
- /** @brief determines the rightmost border of the text body */
- formatting_ostream& last_column(int c) {
- lastCol_ = c < 0 ? 0 : c;
- return *this;
- }
-
- int last_column() const noexcept { return lastCol_; }
-
- int text_width() const noexcept {
- return lastCol_ - firstCol_;
- }
-
- /** @brief additional indentation for the 2nd, 3rd, ... line of
- a paragraph (sequence of soft-wrapped lines) */
- formatting_ostream& hanging_indent(int amount) {
- hangingIndent_ = amount;
- return *this;
- }
- int hanging_indent() const noexcept {
- return hangingIndent_;
- }
-
- /** @brief amount of blank lines between paragraphs */
- formatting_ostream& paragraph_spacing(int lines) {
- paragraphSpacing_ = lines;
- return *this;
- }
- int paragraph_spacing() const noexcept {
- return paragraphSpacing_;
- }
-
- /** @brief insert paragraph spacing
- if paragraph is at least 'lines' lines long */
- formatting_ostream& min_paragraph_lines_for_spacing(int lines) {
- paragraphSpacingThreshold_ = lines;
- return *this;
- }
- int min_paragraph_lines_for_spacing() const noexcept {
- return paragraphSpacingThreshold_;
- }
-
- /** @brief if set to true, newline characters will be ignored */
- formatting_ostream& ignore_newline_chars(bool yes) {
- ignoreInputNls_ = yes;
- return *this;
- }
-
- bool ignore_newline_chars() const noexcept {
- return ignoreInputNls_;
- }
-
-
- //---------------------------------------------------------------
- /* @brief insert 'n' spaces */
- void write_spaces(int n) {
- if(n < 1) return;
- os_ << string_type(size_type(n), ' ');
- curCol_ += n;
- }
-
- /* @brief go to new line, but continue current paragraph */
- void wrap_soft(int times = 1) {
- if(times < 1) return;
- if(times > 1) {
- os_ << string_type(size_type(times), '\n');
- } else {
- os_ << '\n';
- }
- curCol_ = 0;
- ++curParagraphLines_;
- }
-
- /* @brief go to new line, and start a new paragraph */
- void wrap_hard(int times = 1) {
- if(times < 1) return;
-
- if(paragraph_spacing() > 0 &&
- paragraph_lines() >= min_paragraph_lines_for_spacing())
- {
- times = paragraph_spacing() + 1;
- }
-
- if(times > 1) {
- os_ << string_type(size_type(times), '\n');
- curBlankLines_ += times - 1;
- } else {
- os_ << '\n';
- }
- if(at_begin_of_line()) {
- ++curBlankLines_;
- }
- curCol_ = 0;
- curParagraphLines_ = 1;
- }
-
-
- //---------------------------------------------------------------
- bool at_begin_of_line() const noexcept {
- return curCol_ <= current_line_begin();
- }
- int current_line_begin() const noexcept {
- return in_hanging_part_of_paragraph()
- ? firstCol_ + hangingIndent_
- : firstCol_;
- }
-
- int current_column() const noexcept {
- return curCol_;
- }
-
- int total_non_blank_lines() const noexcept {
- return totalNonBlankLines_;
- }
- int paragraph_lines() const noexcept {
- return curParagraphLines_;
- }
- int blank_lines_before_paragraph() const noexcept {
- return curBlankLines_;
- }
-
-
- //---------------------------------------------------------------
- template<class T>
- friend formatting_ostream&
- operator << (formatting_ostream& os, const T& x) {
- os.write(x);
- return os;
- }
-
- void flush() {
- os_.flush();
- }
-
-
-private:
- bool in_hanging_part_of_paragraph() const noexcept {
- return hanging_indent() > 0 && paragraph_lines() > 1;
- }
- bool current_line_empty() const noexcept {
- return curCol_ < 1;
- }
- bool left_of_text_area() const noexcept {
- return curCol_ < current_line_begin();
- }
- bool right_of_text_area() const noexcept {
- return curCol_ > lastCol_;
- }
- int columns_left_in_line() const noexcept {
- return lastCol_ - std::max(current_line_begin(), curCol_);
- }
-
- void fix_indent() {
- if(left_of_text_area()) {
- const auto fst = current_line_begin();
- write_spaces(fst - curCol_);
- curCol_ = fst;
- }
- }
-
- template<class Iter>
- bool only_whitespace(Iter first, Iter last) const {
- return last == std::find_if_not(first, last,
- [](char_type c) { return std::isspace(c); });
- }
-
- /** @brief write any object */
- template<class T>
- void write(const T& x) {
- std::ostringstream ss;
- ss << x;
- write(std::move(ss).str());
- }
-
- /** @brief write a stringstream */
- void write(const std::ostringstream& s) {
- write(s.str());
- }
-
- /** @brief write a string */
- void write(const string_type& s) {
- write(s.begin(), s.end());
- }
-
- /** @brief partition output into lines */
- template<class Iter>
- void write(Iter first, Iter last)
- {
- if(first == last) return;
- if(*first == '\n') {
- if(!ignore_newline_chars()) wrap_hard();
- ++first;
- if(first == last) return;
- }
- auto i = std::find(first, last, '\n');
- if(i != last) {
- if(ignore_newline_chars()) ++i;
- if(i != last) {
- write_line(first, i);
- write(i, last);
- }
- }
- else {
- write_line(first, last);
- }
- }
-
- /** @brief handle line wrapping due to column constraints */
- template<class Iter>
- void write_line(Iter first, Iter last)
- {
- if(first == last) return;
- if(only_whitespace(first, last)) return;
-
- if(right_of_text_area()) wrap_soft();
-
- if(at_begin_of_line()) {
- //discard whitespace, it we start a new line
- first = std::find_if(first, last,
- [](char_type c) { return !std::isspace(c); });
- if(first == last) return;
- }
-
- const auto n = int(std::distance(first,last));
- const auto m = columns_left_in_line();
- //if text to be printed is too long for one line -> wrap
- if(n > m) {
- //break before word, if break is mid-word
- auto breakat = first + m;
- while(breakat > first && !std::isspace(*breakat)) --breakat;
- //could not find whitespace before word -> try after the word
- if(!std::isspace(*breakat) && breakat == first) {
- breakat = std::find_if(first+m, last,
- [](char_type c) { return std::isspace(c); });
- }
- if(breakat > first) {
- if(curCol_ < 1) ++totalNonBlankLines_;
- fix_indent();
- std::copy(first, breakat, std::ostream_iterator<char_type>(os_));
- curBlankLines_ = 0;
- }
- if(breakat < last) {
- wrap_soft();
- write_line(breakat, last);
- }
- }
- else {
- if(curCol_ < 1) ++totalNonBlankLines_;
- fix_indent();
- std::copy(first, last, std::ostream_iterator<char_type>(os_));
- curCol_ += n;
- curBlankLines_ = 0;
- }
- }
-
- /** @brief write a single character */
- void write(char_type c)
- {
- if(c == '\n') {
- if(!ignore_newline_chars()) wrap_hard();
- }
- else {
- if(at_begin_of_line()) ++totalNonBlankLines_;
- fix_indent();
- os_ << c;
- ++curCol_;
- }
- }
-
- OStream& os_;
- int curCol_;
- int firstCol_;
- int lastCol_;
- int hangingIndent_;
- int paragraphSpacing_;
- int paragraphSpacingThreshold_;
- int curBlankLines_;
- int curParagraphLines_;
- int totalNonBlankLines_;
- bool ignoreInputNls_;
-};
-
-
-}
-
-
-
-
-/*************************************************************************//**
- *
- * @brief generates usage lines
- *
- * @details lazily evaluated
- *
- *****************************************************************************/
-class usage_lines
-{
-public:
- using string = doc_string;
-
- usage_lines(const group& cli, string prefix = "",
- const doc_formatting& fmt = doc_formatting{})
- :
- cli_(cli), fmt_(fmt), prefix_(std::move(prefix))
- {
- if(!prefix_.empty()) prefix_ += ' ';
- }
-
- usage_lines(const group& cli, const doc_formatting& fmt):
- usage_lines(cli, "", fmt)
- {}
-
- usage_lines& ommit_outermost_group_surrounders(bool yes) {
- ommitOutermostSurrounders_ = yes;
- return *this;
- }
- bool ommit_outermost_group_surrounders() const {
- return ommitOutermostSurrounders_;
- }
-
- template<class OStream>
- inline friend OStream& operator << (OStream& os, const usage_lines& p) {
- p.write(os);
- return os;
- }
-
- string str() const {
- std::ostringstream os; os << *this; return os.str();
- }
-
-
-private:
- using stream_t = detail::formatting_ostream<>;
- const group& cli_;
- doc_formatting fmt_;
- string prefix_;
- bool ommitOutermostSurrounders_ = false;
-
-
- //-----------------------------------------------------
- struct context {
- group::depth_first_traverser pos;
- std::stack<string> separators;
- std::stack<string> postfixes;
- int level = 0;
- const group* outermost = nullptr;
- bool linestart = false;
- bool useOutermost = true;
- int line = 0;
-
- bool is_singleton() const noexcept {
- return linestart && pos.is_last_in_path();
- }
- bool is_alternative() const noexcept {
- return pos.parent().exclusive();
- }
- };
-
-
- /***************************************************************//**
- *
- * @brief writes usage text for command line parameters
- *
- *******************************************************************/
- template<class OStream>
- void write(OStream& os) const
- {
- detail::formatting_ostream<OStream> fos(os);
- fos.first_column(fmt_.first_column());
- fos.last_column(fmt_.last_column());
-
- auto hindent = int(prefix_.size());
- if(fos.first_column() + hindent >= int(0.4 * fos.text_width())) {
- hindent = fmt_.indent_size();
- }
- fos.hanging_indent(hindent);
-
- fos.paragraph_spacing(fmt_.paragraph_spacing());
- fos.min_paragraph_lines_for_spacing(2);
- fos.ignore_newline_chars(fmt_.ignore_newline_chars());
-
- context cur;
- cur.pos = cli_.begin_dfs();
- cur.linestart = true;
- cur.level = cur.pos.level();
- cur.outermost = &cli_;
-
- write(fos, cur, prefix_);
- }
-
-
- /***************************************************************//**
- *
- * @brief writes usage text for command line parameters
- *
- * @param prefix all that goes in front of current things to print
- *
- *******************************************************************/
- template<class OStream>
- void write(OStream& os, context cur, string prefix) const
- {
- if(!cur.pos) return;
-
- std::ostringstream buf;
- if(cur.linestart) buf << prefix;
- const auto initPos = buf.tellp();
-
- cur.level = cur.pos.level();
-
- if(cur.useOutermost) {
- //we cannot start outside of the outermost group
- //so we have to treat it separately
- start_group(buf, cur.pos.parent(), cur);
- if(!cur.pos) {
- os << buf.str();
- return;
- }
- }
- else {
- //don't visit siblings of starter node
- cur.pos.skip_siblings();
- }
- check_end_group(buf, cur);
-
- do {
- if(buf.tellp() > initPos) cur.linestart = false;
- if(!cur.linestart && !cur.pos.is_first_in_parent()) {
- buf << cur.separators.top();
- }
- if(cur.pos->is_group()) {
- start_group(buf, cur.pos->as_group(), cur);
- if(!cur.pos) {
- os << buf.str();
- return;
- }
- }
- else {
- buf << param_label(cur.pos->as_param(), cur);
- ++cur.pos;
- }
- check_end_group(buf, cur);
- } while(cur.pos);
-
- os << buf.str();
- }
-
-
- /***************************************************************//**
- *
- * @brief handles pattern group surrounders and separators
- * and alternative splitting
- *
- *******************************************************************/
- void start_group(std::ostringstream& os,
- const group& group, context& cur) const
- {
- //does cur.pos already point to a member or to group itself?
- //needed for special treatment of outermost group
- const bool alreadyInside = &(cur.pos.parent()) == &group;
-
- auto lbl = joined_label(group, cur);
- if(!lbl.empty()) {
- os << lbl;
- cur.linestart = false;
- //skip over entire group as its label has already been created
- if(alreadyInside) {
- cur.pos.next_after_siblings();
- } else {
- cur.pos.next_sibling();
- }
- }
- else {
- const bool splitAlternatives = group.exclusive() &&
- fmt_.split_alternatives() &&
- std::any_of(group.begin(), group.end(),
- [this](const pattern& p) {
- return int(p.param_count()) >= fmt_.alternatives_min_split_size();
- });
-
- if(splitAlternatives) {
- cur.postfixes.push("");
- cur.separators.push("");
- //recursively print alternative paths in decision-DAG
- //enter group?
- if(!alreadyInside) ++cur.pos;
- cur.linestart = true;
- cur.useOutermost = false;
- auto pfx = os.str();
- os.str("");
- //print paths in DAG starting at each group member
- for(std::size_t i = 0; i < group.size(); ++i) {
- std::stringstream buf;
- cur.outermost = cur.pos->is_group() ? &(cur.pos->as_group()) : nullptr;
- write(buf, cur, pfx);
- if(buf.tellp() > int(pfx.size())) {
- os << buf.str();
- if(i < group.size()-1) {
- if(cur.line > 0) {
- os << string(fmt_.line_spacing(), '\n');
- }
- ++cur.line;
- os << '\n';
- }
- }
- cur.pos.next_sibling(); //do not descend into members
- }
- cur.pos.invalidate(); //signal end-of-path
- return;
- }
- else {
- //pre & postfixes, separators
- auto surround = group_surrounders(group, cur);
- os << surround.first;
- cur.postfixes.push(std::move(surround.second));
- cur.separators.push(group_separator(group, fmt_));
- //descend into group?
- if(!alreadyInside) ++cur.pos;
- }
- }
- cur.level = cur.pos.level();
- }
-
-
- /***************************************************************//**
- *
- *******************************************************************/
- void check_end_group(std::ostringstream& os, context& cur) const
- {
- for(; cur.level > cur.pos.level(); --cur.level) {
- os << cur.postfixes.top();
- cur.postfixes.pop();
- cur.separators.pop();
- }
- cur.level = cur.pos.level();
- }
-
-
- /***************************************************************//**
- *
- * @brief makes usage label for one command line parameter
- *
- *******************************************************************/
- string param_label(const parameter& p, const context& cur) const
- {
- const auto& parent = cur.pos.parent();
-
- const bool startsOptionalSequence =
- parent.size() > 1 && p.blocking() && cur.pos.is_first_in_parent();
-
- const bool outermost =
- ommitOutermostSurrounders_ && cur.outermost == &parent;
-
- const bool showopt = !cur.is_alternative() && !p.required()
- && !startsOptionalSequence && !outermost;
-
- const bool showrep = p.repeatable() && !outermost;
-
- string lbl;
-
- if(showrep) lbl += fmt_.repeat_prefix();
- if(showopt) lbl += fmt_.optional_prefix();
-
- const auto& flags = p.flags();
- if(!flags.empty()) {
- const int n = std::min(fmt_.max_flags_per_param_in_usage(),
- int(flags.size()));
-
- const bool surrAlt = n > 1 && !showopt && !cur.is_singleton();
-
- if(surrAlt) lbl += fmt_.alternative_flags_prefix();
- bool sep = false;
- for(int i = 0; i < n; ++i) {
- if(sep) {
- if(cur.is_singleton())
- lbl += fmt_.alternative_group_separator();
- else
- lbl += fmt_.flag_separator();
- }
- lbl += flags[i];
- sep = true;
- }
- if(surrAlt) lbl += fmt_.alternative_flags_postfix();
- }
- else {
- if(!p.label().empty()) {
- lbl += fmt_.label_prefix()
- + p.label()
- + fmt_.label_postfix();
- } else if(!fmt_.empty_label().empty()) {
- lbl += fmt_.label_prefix()
- + fmt_.empty_label()
- + fmt_.label_postfix();
- } else {
- return "";
- }
- }
-
- if(showopt) lbl += fmt_.optional_postfix();
- if(showrep) lbl += fmt_.repeat_postfix();
-
- return lbl;
- }
-
-
- /***************************************************************//**
- *
- * @brief prints flags in one group in a merged fashion
- *
- *******************************************************************/
- string joined_label(const group& g, const context& cur) const
- {
- if(!fmt_.merge_alternative_flags_with_common_prefix() &&
- !fmt_.merge_joinable_with_common_prefix()) return "";
-
- const bool flagsonly = std::all_of(g.begin(), g.end(),
- [](const pattern& p){
- return p.is_param() && !p.as_param().flags().empty();
- });
-
- if(!flagsonly) return "";
-
- const bool showOpt = g.all_optional() &&
- !(ommitOutermostSurrounders_ && cur.outermost == &g);
-
- auto pfx = g.common_flag_prefix();
- if(pfx.empty()) return "";
-
- const auto n = pfx.size();
- if(g.exclusive() &&
- fmt_.merge_alternative_flags_with_common_prefix())
- {
- string lbl;
- if(showOpt) lbl += fmt_.optional_prefix();
- lbl += pfx + fmt_.alternatives_prefix();
- bool first = true;
- for(const auto& p : g) {
- if(p.is_param()) {
- if(first)
- first = false;
- else
- lbl += fmt_.alternative_param_separator();
- lbl += p.as_param().flags().front().substr(n);
- }
- }
- lbl += fmt_.alternatives_postfix();
- if(showOpt) lbl += fmt_.optional_postfix();
- return lbl;
- }
- //no alternatives, but joinable flags
- else if(g.joinable() &&
- fmt_.merge_joinable_with_common_prefix())
- {
- const bool allSingleChar = std::all_of(g.begin(), g.end(),
- [&](const pattern& p){
- return p.is_param() &&
- p.as_param().flags().front().substr(n).size() == 1;
- });
-
- if(allSingleChar) {
- string lbl;
- if(showOpt) lbl += fmt_.optional_prefix();
- lbl += pfx;
- for(const auto& p : g) {
- if(p.is_param())
- lbl += p.as_param().flags().front().substr(n);
- }
- if(showOpt) lbl += fmt_.optional_postfix();
- return lbl;
- }
- }
-
- return "";
- }
-
-
- /***************************************************************//**
- *
- * @return symbols with which to surround a group
- *
- *******************************************************************/
- std::pair<string,string>
- group_surrounders(const group& group, const context& cur) const
- {
- string prefix;
- string postfix;
-
- const bool isOutermost = &group == cur.outermost;
- if(isOutermost && ommitOutermostSurrounders_)
- return {string{}, string{}};
-
- if(group.exclusive()) {
- if(group.all_optional()) {
- prefix = fmt_.optional_prefix();
- postfix = fmt_.optional_postfix();
- if(group.all_flagless()) {
- prefix += fmt_.label_prefix();
- postfix = fmt_.label_prefix() + postfix;
- }
- } else if(group.all_flagless()) {
- prefix = fmt_.label_prefix();
- postfix = fmt_.label_postfix();
- } else if(!cur.is_singleton() || !isOutermost) {
- prefix = fmt_.alternatives_prefix();
- postfix = fmt_.alternatives_postfix();
- }
- }
- else if(group.size() > 1 &&
- group.front().blocking() && !group.front().required())
- {
- prefix = fmt_.optional_prefix();
- postfix = fmt_.optional_postfix();
- }
- else if(group.size() > 1 && cur.is_alternative() &&
- &group != cur.outermost)
- {
- prefix = fmt_.group_prefix();
- postfix = fmt_.group_postfix();
- }
- else if(!group.exclusive() &&
- group.joinable() && !cur.linestart)
- {
- prefix = fmt_.joinable_prefix();
- postfix = fmt_.joinable_postfix();
- }
-
- if(group.repeatable()) {
- if(prefix.empty()) prefix = fmt_.group_prefix();
- prefix = fmt_.repeat_prefix() + prefix;
- if(postfix.empty()) postfix = fmt_.group_postfix();
- postfix += fmt_.repeat_postfix();
- }
-
- return {std::move(prefix), std::move(postfix)};
- }
-
-
- /***************************************************************//**
- *
- * @return symbol that separates members of a group
- *
- *******************************************************************/
- static string
- group_separator(const group& group, const doc_formatting& fmt)
- {
- const bool only1ParamPerMember = std::all_of(group.begin(), group.end(),
- [](const pattern& p) { return p.param_count() < 2; });
-
- if(only1ParamPerMember) {
- if(group.exclusive()) {
- return fmt.alternative_param_separator();
- } else {
- return fmt.param_separator();
- }
- }
- else { //there is at least one large group inside
- if(group.exclusive()) {
- return fmt.alternative_group_separator();
- } else {
- return fmt.group_separator();
- }
- }
- }
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief generates parameter and group documentation from docstrings
- *
- * @details lazily evaluated
- *
- *****************************************************************************/
-class documentation
-{
-public:
- using string = doc_string;
- using filter_function = std::function<bool(const parameter&)>;
-
- documentation(const group& cli,
- const doc_formatting& fmt = doc_formatting{},
- filter_function filter = param_filter{})
- :
- cli_(cli), fmt_{fmt}, usgFmt_{fmt}, filter_{std::move(filter)}
- {
- //necessary, because we re-use "usage_lines" to generate
- //labels for documented groups
- usgFmt_.max_flags_per_param_in_usage(
- usgFmt_.max_flags_per_param_in_doc());
- }
-
- documentation(const group& cli, filter_function filter) :
- documentation{cli, doc_formatting{}, std::move(filter)}
- {}
-
- documentation(const group& cli, const param_filter& filter) :
- documentation{cli, doc_formatting{},
- [filter](const parameter& p) { return filter(p); }}
- {}
-
- template<class OStream>
- inline friend OStream& operator << (OStream& os, const documentation& p) {
- p.write(os);
- return os;
- }
-
- string str() const {
- std::ostringstream os;
- write(os);
- return os.str();
- }
-
-
-private:
- using dfs_traverser = group::depth_first_traverser;
-
- const group& cli_;
- doc_formatting fmt_;
- doc_formatting usgFmt_;
- filter_function filter_;
- enum class paragraph { param, group };
-
-
- /***************************************************************//**
- *
- * @brief writes documentation to output stream
- *
- *******************************************************************/
- template<class OStream>
- void write(OStream& os) const {
- detail::formatting_ostream<OStream> fos(os);
- fos.first_column(fmt_.first_column());
- fos.last_column(fmt_.last_column());
- fos.hanging_indent(0);
- fos.paragraph_spacing(0);
- fos.ignore_newline_chars(fmt_.ignore_newline_chars());
- print_doc(fos, cli_);
- }
-
-
- /***************************************************************//**
- *
- * @brief writes full documentation text for command line parameters
- *
- *******************************************************************/
- template<class OStream>
- void print_doc(detail::formatting_ostream<OStream>& os,
- const group& cli, int indentLvl = 0) const
- {
- if(cli.empty()) return;
-
- //if group itself doesn't have docstring
- if(cli.doc().empty()) {
- for(const auto& p : cli) {
- print_doc(os, p, indentLvl);
- }
- }
- else { //group itself does have docstring
- bool anyDocInside = std::any_of(cli.begin(), cli.end(),
- [](const pattern& p){ return !p.doc().empty(); });
-
- if(anyDocInside) { //group docstring as title, then child entries
- handle_spacing(os, paragraph::group, indentLvl);
- os << cli.doc();
- for(const auto& p : cli) {
- print_doc(os, p, indentLvl + 1);
- }
- }
- else { //group label first then group docstring
- auto lbl = usage_lines(cli, usgFmt_)
- .ommit_outermost_group_surrounders(true).str();
-
- str::trim(lbl);
- handle_spacing(os, paragraph::param, indentLvl);
- print_entry(os, lbl, cli.doc());
- }
- }
- }
-
-
- /***************************************************************//**
- *
- * @brief writes documentation text for one group or parameter
- *
- *******************************************************************/
- template<class OStream>
- void print_doc(detail::formatting_ostream<OStream>& os,
- const pattern& ptrn, int indentLvl) const
- {
- if(ptrn.is_group()) {
- print_doc(os, ptrn.as_group(), indentLvl);
- }
- else {
- const auto& p = ptrn.as_param();
- if(!filter_(p)) return;
-
- handle_spacing(os, paragraph::param, indentLvl);
- print_entry(os, param_label(p, fmt_), p.doc());
- }
- }
-
- /***************************************************************//**
- *
- * @brief handles line and paragraph spacings
- *
- *******************************************************************/
- template<class OStream>
- void handle_spacing(detail::formatting_ostream<OStream>& os,
- paragraph p, int indentLvl) const
- {
- const auto oldIndent = os.first_column();
- const auto indent = fmt_.first_column() + indentLvl * fmt_.indent_size();
-
- if(os.total_non_blank_lines() < 1) {
- os.first_column(indent);
- return;
- }
-
- if(os.paragraph_lines() > 1 || indent < oldIndent) {
- os.wrap_hard(fmt_.paragraph_spacing() + 1);
- } else {
- os.wrap_hard();
- }
-
- if(p == paragraph::group) {
- if(os.blank_lines_before_paragraph() < fmt_.paragraph_spacing()) {
- os.wrap_hard(fmt_.paragraph_spacing() - os.blank_lines_before_paragraph());
- }
- }
- else if(os.blank_lines_before_paragraph() < fmt_.line_spacing()) {
- os.wrap_hard(fmt_.line_spacing() - os.blank_lines_before_paragraph());
- }
- os.first_column(indent);
- }
-
- /*********************************************************************//**
- *
- * @brief prints one entry = label + docstring
- *
- ************************************************************************/
- template<class OStream>
- void print_entry(detail::formatting_ostream<OStream>& os,
- const string& label, const string& docstr) const
- {
- if(label.empty()) return;
-
- os << label;
-
- if(!docstr.empty()) {
- if(os.current_column() >= fmt_.doc_column()) os.wrap_soft();
- const auto oldcol = os.first_column();
- os.first_column(fmt_.doc_column());
- os << docstr;
- os.first_column(oldcol);
- }
- }
-
-
- /*********************************************************************//**
- *
- * @brief makes label for one parameter
- *
- ************************************************************************/
- static doc_string
- param_label(const parameter& param, const doc_formatting& fmt)
- {
- doc_string lbl;
-
- if(param.repeatable()) lbl += fmt.repeat_prefix();
-
- const auto& flags = param.flags();
- if(!flags.empty()) {
- lbl += flags[0];
- const int n = std::min(fmt.max_flags_per_param_in_doc(),
- int(flags.size()));
- for(int i = 1; i < n; ++i) {
- lbl += fmt.flag_separator() + flags[i];
- }
- }
- else if(!param.label().empty() || !fmt.empty_label().empty()) {
- lbl += fmt.label_prefix();
- if(!param.label().empty()) {
- lbl += param.label();
- } else {
- lbl += fmt.empty_label();
- }
- lbl += fmt.label_postfix();
- }
-
- if(param.repeatable()) lbl += fmt.repeat_postfix();
-
- return lbl;
- }
-
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief stores strings for man page sections
- *
- *****************************************************************************/
-class man_page
-{
-public:
- //---------------------------------------------------------------
- using string = doc_string;
-
- //---------------------------------------------------------------
- /** @brief man page section */
- class section {
- public:
- using string = doc_string;
-
- section(string stitle, string scontent):
- title_{std::move(stitle)}, content_{std::move(scontent)}
- {}
-
- const string& title() const noexcept { return title_; }
- const string& content() const noexcept { return content_; }
-
- private:
- string title_;
- string content_;
- };
-
-private:
- using section_store = std::vector<section>;
-
-public:
- //---------------------------------------------------------------
- using value_type = section;
- using const_iterator = section_store::const_iterator;
- using size_type = section_store::size_type;
-
-
- //---------------------------------------------------------------
- man_page&
- append_section(string title, string content)
- {
- sections_.emplace_back(std::move(title), std::move(content));
- return *this;
- }
- //-----------------------------------------------------
- man_page&
- prepend_section(string title, string content)
- {
- sections_.emplace(sections_.begin(),
- std::move(title), std::move(content));
- return *this;
- }
-
-
- //---------------------------------------------------------------
- const section& operator [] (size_type index) const noexcept {
- return sections_[index];
- }
-
- //---------------------------------------------------------------
- size_type size() const noexcept { return sections_.size(); }
-
- bool empty() const noexcept { return sections_.empty(); }
-
-
- //---------------------------------------------------------------
- const_iterator begin() const noexcept { return sections_.begin(); }
- const_iterator end() const noexcept { return sections_.end(); }
-
-
- //---------------------------------------------------------------
- man_page& program_name(const string& n) {
- progName_ = n;
- return *this;
- }
- man_page& program_name(string&& n) {
- progName_ = std::move(n);
- return *this;
- }
- const string& program_name() const noexcept {
- return progName_;
- }
-
-
- //---------------------------------------------------------------
- man_page& section_row_spacing(int rows) {
- sectionSpc_ = rows > 0 ? rows : 0;
- return *this;
- }
- int section_row_spacing() const noexcept { return sectionSpc_; }
-
-
-private:
- int sectionSpc_ = 1;
- section_store sections_;
- string progName_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief generates man sections from command line parameters
- * with sections "synopsis" and "options"
- *
- *****************************************************************************/
-inline man_page
-make_man_page(const group& cli,
- doc_string progname = "",
- const doc_formatting& fmt = doc_formatting{})
-{
- man_page man;
- man.append_section("SYNOPSIS", usage_lines(cli,progname,fmt).str());
- man.append_section("OPTIONS", documentation(cli,fmt).str());
- return man;
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief generates man page based on command line parameters
- *
- *****************************************************************************/
-template<class OStream>
-OStream&
-operator << (OStream& os, const man_page& man)
-{
- bool first = true;
- const auto secSpc = doc_string(man.section_row_spacing() + 1, '\n');
- for(const auto& section : man) {
- if(!section.content().empty()) {
- if(first) first = false; else os << secSpc;
- if(!section.title().empty()) os << section.title() << '\n';
- os << section.content();
- }
- }
- os << '\n';
- return os;
-}
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief printing methods for debugging command line interfaces
- *
- *****************************************************************************/
-namespace debug {
-
-
-/*************************************************************************//**
- *
- * @brief prints first flag or value label of a parameter
- *
- *****************************************************************************/
-inline doc_string doc_label(const parameter& p)
-{
- if(!p.flags().empty()) return p.flags().front();
- if(!p.label().empty()) return p.label();
- return doc_string{"<?>"};
-}
-
-inline doc_string doc_label(const group&)
-{
- return "<group>";
-}
-
-inline doc_string doc_label(const pattern& p)
-{
- return p.is_group() ? doc_label(p.as_group()) : doc_label(p.as_param());
-}
-
-
-/*************************************************************************//**
- *
- * @brief prints parsing result
- *
- *****************************************************************************/
-template<class OStream>
-void print(OStream& os, const parsing_result& result)
-{
- for(const auto& m : result) {
- os << "#" << m.index() << " " << m.arg() << " -> ";
- auto p = m.param();
- if(p) {
- os << doc_label(*p) << " \t";
- if(m.repeat() > 0) {
- os << (m.bad_repeat() ? "[bad repeat " : "[repeat ")
- << m.repeat() << "]";
- }
- if(m.blocked()) os << " [blocked]";
- if(m.conflict()) os << " [conflict]";
- os << '\n';
- }
- else {
- os << " [unmapped]\n";
- }
- }
-
- for(const auto& m : result.missing()) {
- auto p = m.param();
- if(p) {
- os << doc_label(*p) << " \t";
- os << " [missing after " << m.after_index() << "]\n";
- }
- }
-}
-
-
-/*************************************************************************//**
- *
- * @brief prints parameter label and some properties
- *
- *****************************************************************************/
-template<class OStream>
-void print(OStream& os, const parameter& p)
-{
- if(p.greedy()) os << '!';
- if(p.blocking()) os << '~';
- if(!p.required()) os << '[';
- os << doc_label(p);
- if(p.repeatable()) os << "...";
- if(!p.required()) os << "]";
-}
-
-
-//-------------------------------------------------------------------
-template<class OStream>
-void print(OStream& os, const group& g, int level = 0);
-
-
-/*************************************************************************//**
- *
- * @brief prints group or parameter; uses indentation
- *
- *****************************************************************************/
-template<class OStream>
-void print(OStream& os, const pattern& param, int level = 0)
-{
- if(param.is_group()) {
- print(os, param.as_group(), level);
- }
- else {
- os << doc_string(4*level, ' ');
- print(os, param.as_param());
- }
-}
-
-
-/*************************************************************************//**
- *
- * @brief prints group and its contents; uses indentation
- *
- *****************************************************************************/
-template<class OStream>
-void print(OStream& os, const group& g, int level)
-{
- auto indent = doc_string(4*level, ' ');
- os << indent;
- if(g.blocking()) os << '~';
- if(g.joinable()) os << 'J';
- os << (g.exclusive() ? "(|\n" : "(\n");
- for(const auto& p : g) {
- print(os, p, level+1);
- }
- os << '\n' << indent << (g.exclusive() ? "|)" : ")");
- if(g.repeatable()) os << "...";
- os << '\n';
-}
-
-
-} // namespace debug
-} //namespace clipp
-
-#endif
-
diff --git a/console/parse.hpp b/console/parse.hpp
deleted file mode 100644
index abdd36c..0000000
--- a/console/parse.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#pragma once
-
-#include <iostream>
-
-#include <rawaccel.hpp>
-#include <rawaccel-error.hpp>
-
-#include "external/clipp.h"
-
-namespace rawaccel {
-
- template<typename Accel, typename StrFirst, typename... StrRest>
- clipp::parameter make_accel_cmd(modifier_args& args, StrFirst&& first_flag, StrRest&&... rest) {
- return clipp::command(first_flag, rest...)
- .set(args.acc_fn_args.accel_mode, accel_impl_t::id<Accel>);
- }
-
- mouse_modifier parse(int argc, char** argv) {
- modifier_args args{};
-
- auto make_opt_vec = [](vec2d& v, auto first_flag, auto... rest) {
- return clipp::option(first_flag, rest...) & (
- clipp::number("xy", v.x, v.y) | (
- (clipp::required("x") & clipp::number("num", v.x)),
- (clipp::required("y") & clipp::number("num", v.y))
- )
- );
- };
-
- auto make_doc_fmt = [] {
- return clipp::doc_formatting{}
- .first_column(4)
- .doc_column(28)
- .last_column(80)
- // min value to not split optional vec2 alternatives
- .alternatives_min_split_size(5);
- };
-
- // default options
- auto opt_sens = "sensitivity (default = 1)" % make_opt_vec(args.sens, "sens");
-
- auto opt_rot = "counter-clockwise rotation (default = 0)" % (
- clipp::option("rotate") &
- clipp::number("degrees", args.degrees)
- );
-
- // mode-independent accel options
- auto opt_weight = "accel multiplier (default = 1)" %
- make_opt_vec(args.acc_fn_args.acc_args.weight, "weight");
-
- auto opt_offset = "speed (dots/ms) where accel kicks in (default = 0)" % (
- clipp::option("offset") & clipp::number("speed", args.acc_fn_args.acc_args.offset)
- );
-
- auto opt_cap = "accel scale cap (default = 9)" %
- make_opt_vec(args.acc_fn_args.cap, "cap");
-
- auto opt_tmin = "minimum time between polls (default = 0.4)" % (
- clipp::option("tmin") &
- clipp::number("ms", args.acc_fn_args.time_min)
- );
-
- auto accel_var = (clipp::required("accel") & clipp::number("num", args.acc_fn_args.acc_args.accel)) % "ramp rate";
- auto limit_var = (clipp::required("limit") & clipp::number("scale", args.acc_fn_args.acc_args.limit)) % "limit";
- auto exp_var = (clipp::required("exponent") & clipp::number("num", args.acc_fn_args.acc_args.exponent)) % "exponent";
-
- // modes
- auto noaccel_mode = "no-accel mode" % make_accel_cmd<accel_noaccel>(args, "off", "noaccel");
-
- auto lin_mode = "linear accel mode:" % (
- make_accel_cmd<accel_linear>(args, "linear"),
- accel_var
- );
- auto classic_mode = "classic accel mode:" % (
- make_accel_cmd<accel_classic>(args, "classic"),
- accel_var,
- exp_var
- );
- auto nat_mode = "natural accel mode:" % (
- make_accel_cmd<accel_natural>(args, "natural"),
- accel_var,
- limit_var
- );
- auto log_mode = "logarithmic accel mode:" % (
- make_accel_cmd<accel_logarithmic>(args, "logarithmic"),
- accel_var
- );
- auto sig_mode = "sigmoid accel mode:" % (
- make_accel_cmd<accel_sigmoid>(args, "sigmoid"),
- accel_var,
- limit_var,
- (clipp::required("midpoint") & clipp::number("speed", args.acc_fn_args.acc_args.midpoint)) % "midpoint"
- );
- auto pow_mode = "power accel mode:" % (
- make_accel_cmd<accel_power>(args, "power"),
- exp_var,
- (clipp::option("scale") & clipp::number("num", args.acc_fn_args.acc_args.power_scale)) % "scale factor"
- );
-
- auto accel_mode_exclusive = (lin_mode | classic_mode | nat_mode | log_mode | sig_mode | pow_mode);
- auto accel_opts = "mode-independent accel options:" % (opt_cap, opt_weight, opt_offset, opt_tmin);
-
- bool help = false;
-
- auto cli = clipp::group(clipp::command("help").set(help)) | (
- noaccel_mode | (accel_mode_exclusive, accel_opts),
- opt_sens,
- opt_rot
- );
-
- if (!clipp::parse(argc, argv, cli)) {
- constexpr int PARSE_ERROR = 1;
-
- std::cout << clipp::usage_lines(cli, "rawaccel", make_doc_fmt());
- std::exit(PARSE_ERROR);
- }
-
- if (help) {
- std::cout << clipp::make_man_page(cli, "rawaccel", make_doc_fmt());
- std::exit(0);
- }
-
- return mouse_modifier(args);
- }
-
-} // rawaccel
diff --git a/grapher/Constants/Constants.cs b/grapher/Constants/Constants.cs
new file mode 100644
index 0000000..aaf8bb9
--- /dev/null
+++ b/grapher/Constants/Constants.cs
@@ -0,0 +1,104 @@
+using System.Drawing;
+
+namespace grapher
+{
+ public static class Constants
+ {
+ #region Constants
+
+ /// <summary> DPI by which charts are scaled if none is set by user. </summary>
+ public const int DefaultDPI = 1200;
+
+ /// <summary> Poll rate by which charts are scaled if none is set by user. </summary>
+ public const int DefaultPollRate = 1000;
+
+ /// <summary> Resolution of chart calulation. </summary>
+ public const int Resolution = 100;
+
+ /// <summary> Multiplied by DPI over poll rate to find rough max expected velocity. </summary>
+ public const double MaxMultiplier = 85;
+
+ /// <summary> Ratio of max (X, Y) used in "by component" calulations to those used in "whole vector" calculations. </summary>
+ public const double XYToCombinedRatio = 1.4;
+
+ /// <summary> Possible options to display in a layout. </summary>
+ public const int PossibleOptionsCount = 6;
+
+ /// <summary> Separation between X and Y active value labels, in pixels. </summary>
+ public const int ActiveLabelXYSeparation = 2;
+
+ /// <summary> Vertical separation between charts, in pixels. </summary>
+ public const int ChartSeparationVertical = 10;
+
+ /// <summary> Needed to show full contents in form. Unsure why. </summary>
+ public const int FormHeightPadding = 35;
+
+ /// <summary> Horizontal separation between charts, in pixels. </summary>
+ public const int ChartSeparationHorizontal = 10;
+
+ /// <summary> Default horizontal separation between x and y fields, in pixels. </summary>
+ public const int DefaultFieldSeparation = 4;
+
+ /// <summary> Default horizontal separation between an option's label and box, in pixels. </summary>
+ public const int OptionLabelBoxSeperation = 10;
+
+ /// <summary> Default horizontal separation between an option's label and box, in pixels. </summary>
+ public const int OptionVerticalSeperation = 4;
+
+ /// <summary> Horizontal separation between left side of single dropdown and left side of labels beneath dropdown </summary>
+ public const int DropDownLeftSeparation = 10;
+
+ /// <summary> Width of charts when widened </summary>
+ public const int WideChartWidth = 723;
+
+ /// <summary> Left placement of charts when widened </summary>
+ public const int WideChartLeft = 333;
+
+ /// <summary> Width of charts when narrowed </summary>
+ public const int NarrowChartWidth = 698;
+
+ /// <summary> Left placement of charts when narrowed </summary>
+ public const int NarrowChartLeft = 482;
+
+ public const int WriteButtonVerticalOffset = 50;
+
+ /// <summary> Format string for shortened x and y textboxes. </summary>
+ public const string ShortenedFormatString = "0.###";
+
+ /// <summary> Format string for default active value labels. </summary>
+ public const string DefaultActiveValueFormatString = "0.######";
+
+ /// <summary> Format string for default textboxes. </summary>
+ public const string DefaultFieldFormatString = "0.#########";
+
+ /// <summary> Format string for shortened x and y fields. </summary>
+ public const string ShortenedFieldFormatString = "0.###";
+
+ /// <summary> Format string for gain cap active value label. </summary>
+ public const string GainCapFormatString = "0.##";
+
+ /// <summary> Format string for shortened x and y dropdowns. </summary>
+ public const string AccelDropDownDefaultFullText = "Acceleration Type";
+
+ /// <summary> Format string for default dropdowns. </summary>
+ public const string AccelDropDownDefaultShortText = "Accel Type";
+
+ /// <summary> Default text to be displayed on write button. </summary>
+ public const string WriteButtonDefaultText = "Write To Driver";
+
+ /// <summary> Default text to be displayed on write button. </summary>
+ public const string WriteButtonDelayText = "Delay";
+
+ /// <summary> Default name of settings file. </summary>
+ public const string DefaultSettingsFileName = @"settings.json";
+
+ #endregion Constants
+
+ #region ReadOnly
+
+ /// <summary> Color of font in active value labels. </summary>
+ public static readonly Color ActiveValueFontColor = Color.FromArgb(255, 65, 65, 65);
+
+ #endregion ReadOnly
+ }
+}
diff --git a/grapher/Form1.Designer.cs b/grapher/Form1.Designer.cs
index a7a3e16..f8a6578 100644
--- a/grapher/Form1.Designer.cs
+++ b/grapher/Form1.Designer.cs
@@ -55,30 +55,28 @@ namespace grapher
System.Windows.Forms.DataVisualization.Charting.Series series11 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.Series series12 = new System.Windows.Forms.DataVisualization.Charting.Series();
this.AccelerationChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
- this.accelTypeDrop = new System.Windows.Forms.ComboBox();
+ this.accelTypeDropX = new System.Windows.Forms.ComboBox();
this.sensitivityBoxX = new System.Windows.Forms.TextBox();
this.sensitivityLabel = new System.Windows.Forms.Label();
this.rotationBox = new System.Windows.Forms.TextBox();
this.rotationLabel = new System.Windows.Forms.Label();
- this.accelerationBox = new System.Windows.Forms.TextBox();
- this.constantOneLabel = new System.Windows.Forms.Label();
+ this.accelerationBoxX = new System.Windows.Forms.TextBox();
+ this.constantOneLabelX = new System.Windows.Forms.Label();
this.capBoxX = new System.Windows.Forms.TextBox();
- this.capLabel = new System.Windows.Forms.Label();
- this.weightBoxFirst = new System.Windows.Forms.TextBox();
- this.weightLabel = new System.Windows.Forms.Label();
- this.weightBoxSecond = new System.Windows.Forms.TextBox();
- this.limitBox = new System.Windows.Forms.TextBox();
- this.constantTwoLabel = new System.Windows.Forms.Label();
- this.midpointBox = new System.Windows.Forms.TextBox();
- this.constantThreeLabel = new System.Windows.Forms.Label();
- this.offsetBox = new System.Windows.Forms.TextBox();
- this.offsetLabel = new System.Windows.Forms.Label();
+ this.capLabelX = new System.Windows.Forms.Label();
+ this.weightBoxX = new System.Windows.Forms.TextBox();
+ this.weightLabelX = new System.Windows.Forms.Label();
+ this.weightBoxY = new System.Windows.Forms.TextBox();
+ this.limitBoxX = new System.Windows.Forms.TextBox();
+ this.constantTwoLabelX = new System.Windows.Forms.Label();
+ this.midpointBoxX = new System.Windows.Forms.TextBox();
+ this.constantThreeLabelX = new System.Windows.Forms.Label();
+ this.offsetBoxX = new System.Windows.Forms.TextBox();
+ this.offsetLabelX = new System.Windows.Forms.Label();
this.writeButton = new System.Windows.Forms.Button();
this.sensitivityBoxY = new System.Windows.Forms.TextBox();
this.capBoxY = new System.Windows.Forms.TextBox();
this.sensXYLock = new System.Windows.Forms.CheckBox();
- this.capXYLock = new System.Windows.Forms.CheckBox();
- this.weightXYLock = new System.Windows.Forms.CheckBox();
this.LockXYLabel = new System.Windows.Forms.Label();
this.VelocityChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
this.GainChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
@@ -95,6 +93,12 @@ namespace grapher
this.capStyleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.gainCapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.legacyCapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.offsetStyleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.gainOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.legacyOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
+ this.wholeVectorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.byVectorComponentToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.startupToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.AutoWriteMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.AccelerationChartY = new System.Windows.Forms.DataVisualization.Charting.Chart();
@@ -105,18 +109,36 @@ namespace grapher
this.SensitivityActiveXLabel = new System.Windows.Forms.Label();
this.SensitivityActiveYLabel = new System.Windows.Forms.Label();
this.RotationActiveLabel = new System.Windows.Forms.Label();
- this.AccelTypeActiveLabel = new System.Windows.Forms.Label();
- this.AccelerationActiveLabel = new System.Windows.Forms.Label();
+ this.AccelTypeActiveLabelX = new System.Windows.Forms.Label();
+ this.AccelerationActiveLabelX = new System.Windows.Forms.Label();
this.CapActiveXLabel = new System.Windows.Forms.Label();
this.WeightActiveXLabel = new System.Windows.Forms.Label();
this.WeightActiveYLabel = new System.Windows.Forms.Label();
this.CapActiveYLabel = new System.Windows.Forms.Label();
- this.OffsetActiveLabel = new System.Windows.Forms.Label();
- this.LimitExpActiveLabel = new System.Windows.Forms.Label();
- this.MidpointActiveLabel = new System.Windows.Forms.Label();
- this.offsetStyleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.gainOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.legacyOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.OffsetActiveXLabel = new System.Windows.Forms.Label();
+ this.LimitExpActiveXLabel = new System.Windows.Forms.Label();
+ this.MidpointActiveXLabel = new System.Windows.Forms.Label();
+ this.accelerationBoxY = new System.Windows.Forms.TextBox();
+ this.offsetBoxY = new System.Windows.Forms.TextBox();
+ this.limitBoxY = new System.Windows.Forms.TextBox();
+ this.midpointBoxY = new System.Windows.Forms.TextBox();
+ this.accelTypeDropY = new System.Windows.Forms.ComboBox();
+ this.AccelerationActiveLabelY = new System.Windows.Forms.Label();
+ this.OffsetActiveYLabel = new System.Windows.Forms.Label();
+ this.LimitExpActiveYLabel = new System.Windows.Forms.Label();
+ this.MidpointActiveYLabel = new System.Windows.Forms.Label();
+ this.ByComponentXYLock = new System.Windows.Forms.CheckBox();
+ this.constantOneLabelY = new System.Windows.Forms.Label();
+ this.capLabelY = new System.Windows.Forms.Label();
+ this.weightLabelY = new System.Windows.Forms.Label();
+ this.offsetLabelY = new System.Windows.Forms.Label();
+ this.constantTwoLabelY = new System.Windows.Forms.Label();
+ this.constantThreeLabelY = new System.Windows.Forms.Label();
+ this.OptionSetXTitle = new System.Windows.Forms.Label();
+ this.OptionSetYTitle = new System.Windows.Forms.Label();
+ this.AccelTypeActiveLabelY = new System.Windows.Forms.Label();
+ this.ActiveValueTitleY = new System.Windows.Forms.Label();
+ this.showLastMouseMoveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)(this.AccelerationChart)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.VelocityChart)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.GainChart)).BeginInit();
@@ -134,7 +156,7 @@ namespace grapher
this.AccelerationChart.ChartAreas.Add(chartArea1);
legend1.Name = "Legend1";
this.AccelerationChart.Legends.Add(legend1);
- this.AccelerationChart.Location = new System.Drawing.Point(333, 0);
+ this.AccelerationChart.Location = new System.Drawing.Point(482, 0);
this.AccelerationChart.Name = "AccelerationChart";
series1.ChartArea = "ChartArea1";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
@@ -147,24 +169,24 @@ namespace grapher
series2.Name = "LastAccelVal";
this.AccelerationChart.Series.Add(series1);
this.AccelerationChart.Series.Add(series2);
- this.AccelerationChart.Size = new System.Drawing.Size(723, 328);
+ this.AccelerationChart.Size = new System.Drawing.Size(698, 328);
this.AccelerationChart.TabIndex = 0;
- this.AccelerationChart.Text = "chart1";
+ this.AccelerationChart.Text = "Sensitivity";
//
- // accelTypeDrop
+ // accelTypeDropX
//
- this.accelTypeDrop.FormattingEnabled = true;
- this.accelTypeDrop.Location = new System.Drawing.Point(24, 98);
- this.accelTypeDrop.Name = "accelTypeDrop";
- this.accelTypeDrop.Size = new System.Drawing.Size(151, 21);
- this.accelTypeDrop.TabIndex = 2;
- this.accelTypeDrop.Text = "Acceleration Type";
+ this.accelTypeDropX.FormattingEnabled = true;
+ this.accelTypeDropX.Location = new System.Drawing.Point(105, 110);
+ this.accelTypeDropX.Name = "accelTypeDropX";
+ this.accelTypeDropX.Size = new System.Drawing.Size(76, 21);
+ this.accelTypeDropX.TabIndex = 2;
+ this.accelTypeDropX.Text = "Accel Type";
//
// sensitivityBoxX
//
this.sensitivityBoxX.Location = new System.Drawing.Point(105, 46);
this.sensitivityBoxX.Name = "sensitivityBoxX";
- this.sensitivityBoxX.Size = new System.Drawing.Size(32, 20);
+ this.sensitivityBoxX.Size = new System.Drawing.Size(34, 20);
this.sensitivityBoxX.TabIndex = 3;
//
// sensitivityLabel
@@ -180,7 +202,7 @@ namespace grapher
//
this.rotationBox.Location = new System.Drawing.Point(105, 72);
this.rotationBox.Name = "rotationBox";
- this.rotationBox.Size = new System.Drawing.Size(70, 20);
+ this.rotationBox.Size = new System.Drawing.Size(76, 20);
this.rotationBox.TabIndex = 5;
//
// rotationLabel
@@ -192,137 +214,136 @@ namespace grapher
this.rotationLabel.TabIndex = 6;
this.rotationLabel.Text = "Rotation";
//
- // accelerationBox
+ // accelerationBoxX
//
- this.accelerationBox.Location = new System.Drawing.Point(105, 125);
- this.accelerationBox.Name = "accelerationBox";
- this.accelerationBox.Size = new System.Drawing.Size(69, 20);
- this.accelerationBox.TabIndex = 7;
+ this.accelerationBoxX.Location = new System.Drawing.Point(105, 137);
+ this.accelerationBoxX.Name = "accelerationBoxX";
+ this.accelerationBoxX.Size = new System.Drawing.Size(76, 20);
+ this.accelerationBoxX.TabIndex = 7;
//
- // constantOneLabel
+ // constantOneLabelX
//
- this.constantOneLabel.AutoSize = true;
- this.constantOneLabel.Location = new System.Drawing.Point(24, 128);
- this.constantOneLabel.Name = "constantOneLabel";
- this.constantOneLabel.Size = new System.Drawing.Size(66, 13);
- this.constantOneLabel.TabIndex = 9;
- this.constantOneLabel.Text = "Acceleration";
- this.constantOneLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.constantOneLabelX.AutoSize = true;
+ this.constantOneLabelX.Location = new System.Drawing.Point(24, 140);
+ this.constantOneLabelX.Name = "constantOneLabelX";
+ this.constantOneLabelX.Size = new System.Drawing.Size(66, 13);
+ this.constantOneLabelX.TabIndex = 9;
+ this.constantOneLabelX.Text = "Acceleration";
+ this.constantOneLabelX.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// capBoxX
//
- this.capBoxX.Location = new System.Drawing.Point(105, 151);
+ this.capBoxX.Location = new System.Drawing.Point(105, 163);
this.capBoxX.Name = "capBoxX";
- this.capBoxX.Size = new System.Drawing.Size(32, 20);
+ this.capBoxX.Size = new System.Drawing.Size(76, 20);
this.capBoxX.TabIndex = 10;
//
- // capLabel
+ // capLabelX
//
- this.capLabel.AutoSize = true;
- this.capLabel.Location = new System.Drawing.Point(34, 155);
- this.capLabel.Name = "capLabel";
- this.capLabel.Size = new System.Drawing.Size(26, 13);
- this.capLabel.TabIndex = 11;
- this.capLabel.Text = "Cap";
- this.capLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.capLabelX.AutoSize = true;
+ this.capLabelX.Location = new System.Drawing.Point(43, 166);
+ this.capLabelX.Name = "capLabelX";
+ this.capLabelX.Size = new System.Drawing.Size(26, 13);
+ this.capLabelX.TabIndex = 11;
+ this.capLabelX.Text = "Cap";
+ this.capLabelX.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
- // weightBoxFirst
+ // weightBoxX
//
- this.weightBoxFirst.Location = new System.Drawing.Point(105, 177);
- this.weightBoxFirst.Name = "weightBoxFirst";
- this.weightBoxFirst.Size = new System.Drawing.Size(32, 20);
- this.weightBoxFirst.TabIndex = 12;
+ this.weightBoxX.Location = new System.Drawing.Point(105, 189);
+ this.weightBoxX.Name = "weightBoxX";
+ this.weightBoxX.Size = new System.Drawing.Size(76, 20);
+ this.weightBoxX.TabIndex = 12;
//
- // weightLabel
+ // weightLabelX
//
- this.weightLabel.AutoSize = true;
- this.weightLabel.Location = new System.Drawing.Point(34, 180);
- this.weightLabel.Name = "weightLabel";
- this.weightLabel.Size = new System.Drawing.Size(41, 13);
- this.weightLabel.TabIndex = 13;
- this.weightLabel.Text = "Weight";
- this.weightLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.weightLabelX.AutoSize = true;
+ this.weightLabelX.Location = new System.Drawing.Point(40, 192);
+ this.weightLabelX.Name = "weightLabelX";
+ this.weightLabelX.Size = new System.Drawing.Size(41, 13);
+ this.weightLabelX.TabIndex = 13;
+ this.weightLabelX.Text = "Weight";
+ this.weightLabelX.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
- // weightBoxSecond
+ // weightBoxY
//
- this.weightBoxSecond.Location = new System.Drawing.Point(144, 177);
- this.weightBoxSecond.Name = "weightBoxSecond";
- this.weightBoxSecond.Size = new System.Drawing.Size(31, 20);
- this.weightBoxSecond.TabIndex = 14;
+ this.weightBoxY.Location = new System.Drawing.Point(331, 189);
+ this.weightBoxY.Name = "weightBoxY";
+ this.weightBoxY.Size = new System.Drawing.Size(76, 20);
+ this.weightBoxY.TabIndex = 14;
//
- // limitBox
+ // limitBoxX
//
- this.limitBox.Location = new System.Drawing.Point(105, 229);
- this.limitBox.Name = "limitBox";
- this.limitBox.Size = new System.Drawing.Size(70, 20);
- this.limitBox.TabIndex = 15;
+ this.limitBoxX.Location = new System.Drawing.Point(105, 241);
+ this.limitBoxX.Name = "limitBoxX";
+ this.limitBoxX.Size = new System.Drawing.Size(76, 20);
+ this.limitBoxX.TabIndex = 15;
//
- // constantTwoLabel
+ // constantTwoLabelX
//
- this.constantTwoLabel.AutoSize = true;
- this.constantTwoLabel.Location = new System.Drawing.Point(24, 232);
- this.constantTwoLabel.Name = "constantTwoLabel";
- this.constantTwoLabel.Size = new System.Drawing.Size(78, 13);
- this.constantTwoLabel.TabIndex = 16;
- this.constantTwoLabel.Text = "Limit/Exponent";
- this.constantTwoLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.constantTwoLabelX.AutoSize = true;
+ this.constantTwoLabelX.Location = new System.Drawing.Point(24, 244);
+ this.constantTwoLabelX.Name = "constantTwoLabelX";
+ this.constantTwoLabelX.Size = new System.Drawing.Size(78, 13);
+ this.constantTwoLabelX.TabIndex = 16;
+ this.constantTwoLabelX.Text = "Limit/Exponent";
+ this.constantTwoLabelX.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
- // midpointBox
+ // midpointBoxX
//
- this.midpointBox.Location = new System.Drawing.Point(105, 255);
- this.midpointBox.Name = "midpointBox";
- this.midpointBox.Size = new System.Drawing.Size(70, 20);
- this.midpointBox.TabIndex = 17;
+ this.midpointBoxX.Location = new System.Drawing.Point(105, 267);
+ this.midpointBoxX.Name = "midpointBoxX";
+ this.midpointBoxX.Size = new System.Drawing.Size(76, 20);
+ this.midpointBoxX.TabIndex = 17;
//
- // constantThreeLabel
+ // constantThreeLabelX
//
- this.constantThreeLabel.AutoSize = true;
- this.constantThreeLabel.Location = new System.Drawing.Point(31, 258);
- this.constantThreeLabel.Name = "constantThreeLabel";
- this.constantThreeLabel.Size = new System.Drawing.Size(47, 13);
- this.constantThreeLabel.TabIndex = 18;
- this.constantThreeLabel.Text = "Midpoint";
- this.constantThreeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.constantThreeLabelX.AutoSize = true;
+ this.constantThreeLabelX.Location = new System.Drawing.Point(34, 270);
+ this.constantThreeLabelX.Name = "constantThreeLabelX";
+ this.constantThreeLabelX.Size = new System.Drawing.Size(47, 13);
+ this.constantThreeLabelX.TabIndex = 18;
+ this.constantThreeLabelX.Text = "Midpoint";
+ this.constantThreeLabelX.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
- // offsetBox
+ // offsetBoxX
//
- this.offsetBox.Location = new System.Drawing.Point(105, 203);
- this.offsetBox.Name = "offsetBox";
- this.offsetBox.Size = new System.Drawing.Size(70, 20);
- this.offsetBox.TabIndex = 19;
+ this.offsetBoxX.Location = new System.Drawing.Point(105, 215);
+ this.offsetBoxX.Name = "offsetBoxX";
+ this.offsetBoxX.Size = new System.Drawing.Size(76, 20);
+ this.offsetBoxX.TabIndex = 19;
//
- // offsetLabel
+ // offsetLabelX
//
- this.offsetLabel.AutoSize = true;
- this.offsetLabel.Location = new System.Drawing.Point(34, 206);
- this.offsetLabel.Name = "offsetLabel";
- this.offsetLabel.Size = new System.Drawing.Size(35, 13);
- this.offsetLabel.TabIndex = 20;
- this.offsetLabel.Text = "Offset";
- this.offsetLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ this.offsetLabelX.AutoSize = true;
+ this.offsetLabelX.Location = new System.Drawing.Point(43, 218);
+ this.offsetLabelX.Name = "offsetLabelX";
+ this.offsetLabelX.Size = new System.Drawing.Size(35, 13);
+ this.offsetLabelX.TabIndex = 20;
+ this.offsetLabelX.Text = "Offset";
+ this.offsetLabelX.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// writeButton
//
- this.writeButton.Location = new System.Drawing.Point(57, 281);
+ this.writeButton.Location = new System.Drawing.Point(153, 293);
this.writeButton.Name = "writeButton";
this.writeButton.Size = new System.Drawing.Size(102, 23);
this.writeButton.TabIndex = 21;
this.writeButton.Text = "Write To Driver";
this.writeButton.UseVisualStyleBackColor = true;
- this.writeButton.Click += new System.EventHandler(this.writeButton_Click);
//
// sensitivityBoxY
//
- this.sensitivityBoxY.Location = new System.Drawing.Point(143, 46);
+ this.sensitivityBoxY.Location = new System.Drawing.Point(147, 46);
this.sensitivityBoxY.Name = "sensitivityBoxY";
- this.sensitivityBoxY.Size = new System.Drawing.Size(32, 20);
+ this.sensitivityBoxY.Size = new System.Drawing.Size(34, 20);
this.sensitivityBoxY.TabIndex = 22;
//
// capBoxY
//
- this.capBoxY.Location = new System.Drawing.Point(144, 151);
+ this.capBoxY.Location = new System.Drawing.Point(331, 163);
this.capBoxY.Name = "capBoxY";
- this.capBoxY.Size = new System.Drawing.Size(31, 20);
+ this.capBoxY.Size = new System.Drawing.Size(76, 20);
this.capBoxY.TabIndex = 23;
//
// sensXYLock
@@ -330,38 +351,16 @@ namespace grapher
this.sensXYLock.AutoSize = true;
this.sensXYLock.Checked = true;
this.sensXYLock.CheckState = System.Windows.Forms.CheckState.Checked;
- this.sensXYLock.Location = new System.Drawing.Point(198, 49);
+ this.sensXYLock.Location = new System.Drawing.Point(282, 46);
this.sensXYLock.Name = "sensXYLock";
this.sensXYLock.Size = new System.Drawing.Size(15, 14);
this.sensXYLock.TabIndex = 24;
this.sensXYLock.UseVisualStyleBackColor = true;
//
- // capXYLock
- //
- this.capXYLock.AutoSize = true;
- this.capXYLock.Checked = true;
- this.capXYLock.CheckState = System.Windows.Forms.CheckState.Checked;
- this.capXYLock.Location = new System.Drawing.Point(198, 154);
- this.capXYLock.Name = "capXYLock";
- this.capXYLock.Size = new System.Drawing.Size(15, 14);
- this.capXYLock.TabIndex = 25;
- this.capXYLock.UseVisualStyleBackColor = true;
- //
- // weightXYLock
- //
- this.weightXYLock.AutoSize = true;
- this.weightXYLock.Checked = true;
- this.weightXYLock.CheckState = System.Windows.Forms.CheckState.Checked;
- this.weightXYLock.Location = new System.Drawing.Point(198, 180);
- this.weightXYLock.Name = "weightXYLock";
- this.weightXYLock.Size = new System.Drawing.Size(15, 14);
- this.weightXYLock.TabIndex = 26;
- this.weightXYLock.UseVisualStyleBackColor = true;
- //
// LockXYLabel
//
this.LockXYLabel.AutoSize = true;
- this.LockXYLabel.Location = new System.Drawing.Point(174, 30);
+ this.LockXYLabel.Location = new System.Drawing.Point(255, 30);
this.LockXYLabel.Name = "LockXYLabel";
this.LockXYLabel.Size = new System.Drawing.Size(60, 13);
this.LockXYLabel.TabIndex = 27;
@@ -375,7 +374,7 @@ namespace grapher
this.VelocityChart.ChartAreas.Add(chartArea2);
legend2.Name = "Legend1";
this.VelocityChart.Legends.Add(legend2);
- this.VelocityChart.Location = new System.Drawing.Point(333, 334);
+ this.VelocityChart.Location = new System.Drawing.Point(482, 334);
this.VelocityChart.Name = "VelocityChart";
series3.ChartArea = "ChartArea1";
series3.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
@@ -388,7 +387,7 @@ namespace grapher
series4.Name = "LastVelocityVal";
this.VelocityChart.Series.Add(series3);
this.VelocityChart.Series.Add(series4);
- this.VelocityChart.Size = new System.Drawing.Size(723, 307);
+ this.VelocityChart.Size = new System.Drawing.Size(698, 307);
this.VelocityChart.TabIndex = 28;
this.VelocityChart.Text = "chart1";
//
@@ -400,7 +399,7 @@ namespace grapher
this.GainChart.ChartAreas.Add(chartArea3);
legend3.Name = "Legend1";
this.GainChart.Legends.Add(legend3);
- this.GainChart.Location = new System.Drawing.Point(333, 647);
+ this.GainChart.Location = new System.Drawing.Point(482, 647);
this.GainChart.Name = "GainChart";
series5.ChartArea = "ChartArea1";
series5.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
@@ -413,7 +412,7 @@ namespace grapher
series6.Name = "LastGainVal";
this.GainChart.Series.Add(series5);
this.GainChart.Series.Add(series6);
- this.GainChart.Size = new System.Drawing.Size(723, 309);
+ this.GainChart.Size = new System.Drawing.Size(698, 309);
this.GainChart.TabIndex = 29;
this.GainChart.Text = "chart1";
//
@@ -426,7 +425,7 @@ namespace grapher
this.startupToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
- this.menuStrip1.Size = new System.Drawing.Size(1786, 24);
+ this.menuStrip1.Size = new System.Drawing.Size(1884, 24);
this.menuStrip1.TabIndex = 30;
this.menuStrip1.Text = "menuStrip1";
//
@@ -435,7 +434,8 @@ namespace grapher
this.graphsToolStripMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.graphsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.showVelocityGainToolStripMenuItem,
- this.scaleByDPIToolStripMenuItem});
+ this.scaleByDPIToolStripMenuItem,
+ this.showLastMouseMoveToolStripMenuItem});
this.graphsToolStripMenuItem.ImageTransparentColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.graphsToolStripMenuItem.Name = "graphsToolStripMenuItem";
this.graphsToolStripMenuItem.Size = new System.Drawing.Size(53, 20);
@@ -444,7 +444,7 @@ namespace grapher
// showVelocityGainToolStripMenuItem
//
this.showVelocityGainToolStripMenuItem.Name = "showVelocityGainToolStripMenuItem";
- this.showVelocityGainToolStripMenuItem.Size = new System.Drawing.Size(198, 22);
+ this.showVelocityGainToolStripMenuItem.Size = new System.Drawing.Size(199, 22);
this.showVelocityGainToolStripMenuItem.Text = "Show Velocity && Gain";
//
// scaleByDPIToolStripMenuItem
@@ -454,7 +454,7 @@ namespace grapher
this.pollRateToolStripMenuItem,
this.ScaleMenuItem});
this.scaleByDPIToolStripMenuItem.Name = "scaleByDPIToolStripMenuItem";
- this.scaleByDPIToolStripMenuItem.Size = new System.Drawing.Size(198, 22);
+ this.scaleByDPIToolStripMenuItem.Size = new System.Drawing.Size(199, 22);
this.scaleByDPIToolStripMenuItem.Text = "Scale by Mouse Settngs";
//
// dPIToolStripMenuItem
@@ -495,7 +495,8 @@ namespace grapher
//
this.advancedToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.capStyleToolStripMenuItem,
- this.offsetStyleToolStripMenuItem});
+ this.offsetStyleToolStripMenuItem,
+ this.toolStripMenuItem1});
this.advancedToolStripMenuItem.Name = "advancedToolStripMenuItem";
this.advancedToolStripMenuItem.Size = new System.Drawing.Size(72, 20);
this.advancedToolStripMenuItem.Text = "Advanced";
@@ -514,15 +515,60 @@ namespace grapher
this.gainCapToolStripMenuItem.Checked = true;
this.gainCapToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.gainCapToolStripMenuItem.Name = "gainCapToolStripMenuItem";
- this.gainCapToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.gainCapToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
this.gainCapToolStripMenuItem.Text = "Gain (Default)";
//
// legacyCapToolStripMenuItem
//
this.legacyCapToolStripMenuItem.Name = "legacyCapToolStripMenuItem";
- this.legacyCapToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.legacyCapToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
this.legacyCapToolStripMenuItem.Text = "Legacy";
//
+ // offsetStyleToolStripMenuItem
+ //
+ this.offsetStyleToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.gainOffsetToolStripMenuItem,
+ this.legacyOffsetToolStripMenuItem});
+ this.offsetStyleToolStripMenuItem.Name = "offsetStyleToolStripMenuItem";
+ this.offsetStyleToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.offsetStyleToolStripMenuItem.Text = "Offset Style";
+ //
+ // gainOffsetToolStripMenuItem
+ //
+ this.gainOffsetToolStripMenuItem.Name = "gainOffsetToolStripMenuItem";
+ this.gainOffsetToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
+ this.gainOffsetToolStripMenuItem.Text = "Gain (Default)";
+ //
+ // legacyOffsetToolStripMenuItem
+ //
+ this.legacyOffsetToolStripMenuItem.Name = "legacyOffsetToolStripMenuItem";
+ this.legacyOffsetToolStripMenuItem.Size = new System.Drawing.Size(147, 22);
+ this.legacyOffsetToolStripMenuItem.Text = "Legacy";
+ //
+ // toolStripMenuItem1
+ //
+ this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.wholeVectorToolStripMenuItem,
+ this.byVectorComponentToolStripMenuItem});
+ this.toolStripMenuItem1.Name = "toolStripMenuItem1";
+ this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 22);
+ this.toolStripMenuItem1.Text = "Application Style";
+ //
+ // wholeVectorToolStripMenuItem
+ //
+ this.wholeVectorToolStripMenuItem.Checked = true;
+ this.wholeVectorToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.wholeVectorToolStripMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+ this.wholeVectorToolStripMenuItem.Name = "wholeVectorToolStripMenuItem";
+ this.wholeVectorToolStripMenuItem.Size = new System.Drawing.Size(154, 22);
+ this.wholeVectorToolStripMenuItem.Text = "Whole";
+ //
+ // byVectorComponentToolStripMenuItem
+ //
+ this.byVectorComponentToolStripMenuItem.Name = "byVectorComponentToolStripMenuItem";
+ this.byVectorComponentToolStripMenuItem.Size = new System.Drawing.Size(154, 22);
+ this.byVectorComponentToolStripMenuItem.Text = "By Component";
+ //
// startupToolStripMenuItem
//
this.startupToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -548,7 +594,7 @@ namespace grapher
this.AccelerationChartY.ChartAreas.Add(chartArea4);
legend4.Name = "Legend1";
this.AccelerationChartY.Legends.Add(legend4);
- this.AccelerationChartY.Location = new System.Drawing.Point(1062, 0);
+ this.AccelerationChartY.Location = new System.Drawing.Point(1186, 0);
this.AccelerationChartY.Name = "AccelerationChartY";
series7.ChartArea = "ChartArea1";
series7.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
@@ -561,7 +607,7 @@ namespace grapher
series8.Name = "LastAccelVal";
this.AccelerationChartY.Series.Add(series7);
this.AccelerationChartY.Series.Add(series8);
- this.AccelerationChartY.Size = new System.Drawing.Size(723, 328);
+ this.AccelerationChartY.Size = new System.Drawing.Size(698, 328);
this.AccelerationChartY.TabIndex = 31;
this.AccelerationChartY.Text = "chart1";
//
@@ -573,7 +619,7 @@ namespace grapher
this.VelocityChartY.ChartAreas.Add(chartArea5);
legend5.Name = "Legend1";
this.VelocityChartY.Legends.Add(legend5);
- this.VelocityChartY.Location = new System.Drawing.Point(1062, 334);
+ this.VelocityChartY.Location = new System.Drawing.Point(1186, 334);
this.VelocityChartY.Name = "VelocityChartY";
series9.ChartArea = "ChartArea1";
series9.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
@@ -586,7 +632,7 @@ namespace grapher
series10.Name = "LastVelocityVal";
this.VelocityChartY.Series.Add(series9);
this.VelocityChartY.Series.Add(series10);
- this.VelocityChartY.Size = new System.Drawing.Size(723, 307);
+ this.VelocityChartY.Size = new System.Drawing.Size(698, 307);
this.VelocityChartY.TabIndex = 32;
this.VelocityChartY.Text = "chart1";
//
@@ -598,7 +644,7 @@ namespace grapher
this.GainChartY.ChartAreas.Add(chartArea6);
legend6.Name = "Legend1";
this.GainChartY.Legends.Add(legend6);
- this.GainChartY.Location = new System.Drawing.Point(1062, 647);
+ this.GainChartY.Location = new System.Drawing.Point(1186, 647);
this.GainChartY.Name = "GainChartY";
series11.ChartArea = "ChartArea1";
series11.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
@@ -611,7 +657,7 @@ namespace grapher
series12.Name = "LastGainVal";
this.GainChartY.Series.Add(series11);
this.GainChartY.Series.Add(series12);
- this.GainChartY.Size = new System.Drawing.Size(723, 309);
+ this.GainChartY.Size = new System.Drawing.Size(698, 309);
this.GainChartY.TabIndex = 33;
this.GainChartY.Text = "chart1";
//
@@ -627,16 +673,16 @@ namespace grapher
// ActiveValueTitle
//
this.ActiveValueTitle.AutoSize = true;
- this.ActiveValueTitle.Location = new System.Drawing.Point(248, 30);
+ this.ActiveValueTitle.Location = new System.Drawing.Point(187, 30);
this.ActiveValueTitle.Name = "ActiveValueTitle";
- this.ActiveValueTitle.Size = new System.Drawing.Size(67, 13);
+ this.ActiveValueTitle.Size = new System.Drawing.Size(37, 13);
this.ActiveValueTitle.TabIndex = 35;
- this.ActiveValueTitle.Text = "Active Value";
+ this.ActiveValueTitle.Text = "Active";
//
// SensitivityActiveXLabel
//
this.SensitivityActiveXLabel.AutoSize = true;
- this.SensitivityActiveXLabel.Location = new System.Drawing.Point(258, 49);
+ this.SensitivityActiveXLabel.Location = new System.Drawing.Point(187, 49);
this.SensitivityActiveXLabel.Name = "SensitivityActiveXLabel";
this.SensitivityActiveXLabel.Size = new System.Drawing.Size(14, 13);
this.SensitivityActiveXLabel.TabIndex = 36;
@@ -645,7 +691,7 @@ namespace grapher
// SensitivityActiveYLabel
//
this.SensitivityActiveYLabel.AutoSize = true;
- this.SensitivityActiveYLabel.Location = new System.Drawing.Point(286, 50);
+ this.SensitivityActiveYLabel.Location = new System.Drawing.Point(216, 49);
this.SensitivityActiveYLabel.Name = "SensitivityActiveYLabel";
this.SensitivityActiveYLabel.Size = new System.Drawing.Size(14, 13);
this.SensitivityActiveYLabel.TabIndex = 37;
@@ -654,34 +700,34 @@ namespace grapher
// RotationActiveLabel
//
this.RotationActiveLabel.AutoSize = true;
- this.RotationActiveLabel.Location = new System.Drawing.Point(268, 75);
+ this.RotationActiveLabel.Location = new System.Drawing.Point(196, 75);
this.RotationActiveLabel.Name = "RotationActiveLabel";
this.RotationActiveLabel.Size = new System.Drawing.Size(13, 13);
this.RotationActiveLabel.TabIndex = 38;
this.RotationActiveLabel.Text = "0";
//
- // AccelTypeActiveLabel
+ // AccelTypeActiveLabelX
//
- this.AccelTypeActiveLabel.AutoSize = true;
- this.AccelTypeActiveLabel.Location = new System.Drawing.Point(258, 98);
- this.AccelTypeActiveLabel.Name = "AccelTypeActiveLabel";
- this.AccelTypeActiveLabel.Size = new System.Drawing.Size(41, 13);
- this.AccelTypeActiveLabel.TabIndex = 39;
- this.AccelTypeActiveLabel.Text = "Default";
+ this.AccelTypeActiveLabelX.AutoSize = true;
+ this.AccelTypeActiveLabelX.Location = new System.Drawing.Point(196, 113);
+ this.AccelTypeActiveLabelX.Name = "AccelTypeActiveLabelX";
+ this.AccelTypeActiveLabelX.Size = new System.Drawing.Size(66, 13);
+ this.AccelTypeActiveLabelX.TabIndex = 39;
+ this.AccelTypeActiveLabelX.Text = "SigmoidGain";
//
- // AccelerationActiveLabel
+ // AccelerationActiveLabelX
//
- this.AccelerationActiveLabel.AutoSize = true;
- this.AccelerationActiveLabel.Location = new System.Drawing.Point(268, 128);
- this.AccelerationActiveLabel.Name = "AccelerationActiveLabel";
- this.AccelerationActiveLabel.Size = new System.Drawing.Size(13, 13);
- this.AccelerationActiveLabel.TabIndex = 40;
- this.AccelerationActiveLabel.Text = "0";
+ this.AccelerationActiveLabelX.AutoSize = true;
+ this.AccelerationActiveLabelX.Location = new System.Drawing.Point(196, 140);
+ this.AccelerationActiveLabelX.Name = "AccelerationActiveLabelX";
+ this.AccelerationActiveLabelX.Size = new System.Drawing.Size(13, 13);
+ this.AccelerationActiveLabelX.TabIndex = 40;
+ this.AccelerationActiveLabelX.Text = "0";
//
// CapActiveXLabel
//
this.CapActiveXLabel.AutoSize = true;
- this.CapActiveXLabel.Location = new System.Drawing.Point(259, 151);
+ this.CapActiveXLabel.Location = new System.Drawing.Point(196, 166);
this.CapActiveXLabel.Name = "CapActiveXLabel";
this.CapActiveXLabel.Size = new System.Drawing.Size(13, 13);
this.CapActiveXLabel.TabIndex = 41;
@@ -690,7 +736,7 @@ namespace grapher
// WeightActiveXLabel
//
this.WeightActiveXLabel.AutoSize = true;
- this.WeightActiveXLabel.Location = new System.Drawing.Point(259, 180);
+ this.WeightActiveXLabel.Location = new System.Drawing.Point(196, 192);
this.WeightActiveXLabel.Name = "WeightActiveXLabel";
this.WeightActiveXLabel.Size = new System.Drawing.Size(13, 13);
this.WeightActiveXLabel.TabIndex = 42;
@@ -699,7 +745,7 @@ namespace grapher
// WeightActiveYLabel
//
this.WeightActiveYLabel.AutoSize = true;
- this.WeightActiveYLabel.Location = new System.Drawing.Point(286, 180);
+ this.WeightActiveYLabel.Location = new System.Drawing.Point(413, 192);
this.WeightActiveYLabel.Name = "WeightActiveYLabel";
this.WeightActiveYLabel.Size = new System.Drawing.Size(13, 13);
this.WeightActiveYLabel.TabIndex = 43;
@@ -708,74 +754,256 @@ namespace grapher
// CapActiveYLabel
//
this.CapActiveYLabel.AutoSize = true;
- this.CapActiveYLabel.Location = new System.Drawing.Point(286, 151);
+ this.CapActiveYLabel.Location = new System.Drawing.Point(413, 166);
this.CapActiveYLabel.Name = "CapActiveYLabel";
this.CapActiveYLabel.Size = new System.Drawing.Size(13, 13);
this.CapActiveYLabel.TabIndex = 44;
this.CapActiveYLabel.Text = "0";
//
- // OffsetActiveLabel
- //
- this.OffsetActiveLabel.AutoSize = true;
- this.OffsetActiveLabel.Location = new System.Drawing.Point(268, 206);
- this.OffsetActiveLabel.Name = "OffsetActiveLabel";
- this.OffsetActiveLabel.Size = new System.Drawing.Size(13, 13);
- this.OffsetActiveLabel.TabIndex = 45;
- this.OffsetActiveLabel.Text = "0";
- //
- // LimitExpActiveLabel
+ // OffsetActiveXLabel
//
- this.LimitExpActiveLabel.AutoSize = true;
- this.LimitExpActiveLabel.Location = new System.Drawing.Point(268, 232);
- this.LimitExpActiveLabel.Name = "LimitExpActiveLabel";
- this.LimitExpActiveLabel.Size = new System.Drawing.Size(13, 13);
- this.LimitExpActiveLabel.TabIndex = 46;
- this.LimitExpActiveLabel.Text = "0";
- //
- // MidpointActiveLabel
- //
- this.MidpointActiveLabel.AutoSize = true;
- this.MidpointActiveLabel.Location = new System.Drawing.Point(268, 255);
- this.MidpointActiveLabel.Name = "MidpointActiveLabel";
- this.MidpointActiveLabel.Size = new System.Drawing.Size(13, 13);
- this.MidpointActiveLabel.TabIndex = 47;
- this.MidpointActiveLabel.Text = "0";
- //
- // offsetStyleToolStripMenuItem
- //
- this.offsetStyleToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.gainOffsetToolStripMenuItem,
- this.legacyOffsetToolStripMenuItem});
- this.offsetStyleToolStripMenuItem.Name = "offsetStyleToolStripMenuItem";
- this.offsetStyleToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
- this.offsetStyleToolStripMenuItem.Text = "Offset Style";
- //
- // gainOffsetToolStripMenuItem
- //
- this.gainOffsetToolStripMenuItem.Name = "gainOffsetToolStripMenuItem";
- this.gainOffsetToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
- this.gainOffsetToolStripMenuItem.Text = "Gain (Default)";
- //
- // legacyOffsetToolStripMenuItem
- //
- this.legacyOffsetToolStripMenuItem.Name = "legacyOffsetToolStripMenuItem";
- this.legacyOffsetToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
- this.legacyOffsetToolStripMenuItem.Text = "Legacy";
+ this.OffsetActiveXLabel.AutoSize = true;
+ this.OffsetActiveXLabel.Location = new System.Drawing.Point(196, 218);
+ this.OffsetActiveXLabel.Name = "OffsetActiveXLabel";
+ this.OffsetActiveXLabel.Size = new System.Drawing.Size(13, 13);
+ this.OffsetActiveXLabel.TabIndex = 45;
+ this.OffsetActiveXLabel.Text = "0";
+ //
+ // LimitExpActiveXLabel
+ //
+ this.LimitExpActiveXLabel.AutoSize = true;
+ this.LimitExpActiveXLabel.Location = new System.Drawing.Point(196, 244);
+ this.LimitExpActiveXLabel.Name = "LimitExpActiveXLabel";
+ this.LimitExpActiveXLabel.Size = new System.Drawing.Size(13, 13);
+ this.LimitExpActiveXLabel.TabIndex = 46;
+ this.LimitExpActiveXLabel.Text = "0";
+ //
+ // MidpointActiveXLabel
+ //
+ this.MidpointActiveXLabel.AutoSize = true;
+ this.MidpointActiveXLabel.Location = new System.Drawing.Point(196, 270);
+ this.MidpointActiveXLabel.Name = "MidpointActiveXLabel";
+ this.MidpointActiveXLabel.Size = new System.Drawing.Size(13, 13);
+ this.MidpointActiveXLabel.TabIndex = 47;
+ this.MidpointActiveXLabel.Text = "0";
+ //
+ // accelerationBoxY
+ //
+ this.accelerationBoxY.Location = new System.Drawing.Point(331, 137);
+ this.accelerationBoxY.Name = "accelerationBoxY";
+ this.accelerationBoxY.Size = new System.Drawing.Size(76, 20);
+ this.accelerationBoxY.TabIndex = 48;
+ //
+ // offsetBoxY
+ //
+ this.offsetBoxY.Location = new System.Drawing.Point(331, 215);
+ this.offsetBoxY.Name = "offsetBoxY";
+ this.offsetBoxY.Size = new System.Drawing.Size(76, 20);
+ this.offsetBoxY.TabIndex = 49;
+ //
+ // limitBoxY
+ //
+ this.limitBoxY.Location = new System.Drawing.Point(331, 241);
+ this.limitBoxY.Name = "limitBoxY";
+ this.limitBoxY.Size = new System.Drawing.Size(76, 20);
+ this.limitBoxY.TabIndex = 50;
+ //
+ // midpointBoxY
+ //
+ this.midpointBoxY.Location = new System.Drawing.Point(331, 267);
+ this.midpointBoxY.Name = "midpointBoxY";
+ this.midpointBoxY.Size = new System.Drawing.Size(76, 20);
+ this.midpointBoxY.TabIndex = 51;
+ //
+ // accelTypeDropY
+ //
+ this.accelTypeDropY.FormattingEnabled = true;
+ this.accelTypeDropY.Location = new System.Drawing.Point(331, 110);
+ this.accelTypeDropY.Name = "accelTypeDropY";
+ this.accelTypeDropY.Size = new System.Drawing.Size(76, 21);
+ this.accelTypeDropY.TabIndex = 52;
+ this.accelTypeDropY.Text = "Accel Type";
+ //
+ // AccelerationActiveLabelY
+ //
+ this.AccelerationActiveLabelY.AutoSize = true;
+ this.AccelerationActiveLabelY.Location = new System.Drawing.Point(413, 140);
+ this.AccelerationActiveLabelY.Name = "AccelerationActiveLabelY";
+ this.AccelerationActiveLabelY.Size = new System.Drawing.Size(13, 13);
+ this.AccelerationActiveLabelY.TabIndex = 53;
+ this.AccelerationActiveLabelY.Text = "0";
+ //
+ // OffsetActiveYLabel
+ //
+ this.OffsetActiveYLabel.AutoSize = true;
+ this.OffsetActiveYLabel.Location = new System.Drawing.Point(413, 218);
+ this.OffsetActiveYLabel.Name = "OffsetActiveYLabel";
+ this.OffsetActiveYLabel.Size = new System.Drawing.Size(13, 13);
+ this.OffsetActiveYLabel.TabIndex = 54;
+ this.OffsetActiveYLabel.Text = "0";
+ //
+ // LimitExpActiveYLabel
+ //
+ this.LimitExpActiveYLabel.AutoSize = true;
+ this.LimitExpActiveYLabel.Location = new System.Drawing.Point(413, 244);
+ this.LimitExpActiveYLabel.Name = "LimitExpActiveYLabel";
+ this.LimitExpActiveYLabel.Size = new System.Drawing.Size(13, 13);
+ this.LimitExpActiveYLabel.TabIndex = 55;
+ this.LimitExpActiveYLabel.Text = "0";
+ //
+ // MidpointActiveYLabel
+ //
+ this.MidpointActiveYLabel.AutoSize = true;
+ this.MidpointActiveYLabel.Location = new System.Drawing.Point(413, 270);
+ this.MidpointActiveYLabel.Name = "MidpointActiveYLabel";
+ this.MidpointActiveYLabel.Size = new System.Drawing.Size(13, 13);
+ this.MidpointActiveYLabel.TabIndex = 56;
+ this.MidpointActiveYLabel.Text = "0";
+ //
+ // ByComponentXYLock
+ //
+ this.ByComponentXYLock.AutoSize = true;
+ this.ByComponentXYLock.Checked = true;
+ this.ByComponentXYLock.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.ByComponentXYLock.Location = new System.Drawing.Point(282, 93);
+ this.ByComponentXYLock.Name = "ByComponentXYLock";
+ this.ByComponentXYLock.Size = new System.Drawing.Size(15, 14);
+ this.ByComponentXYLock.TabIndex = 57;
+ this.ByComponentXYLock.UseVisualStyleBackColor = true;
+ //
+ // constantOneLabelY
+ //
+ this.constantOneLabelY.AutoSize = true;
+ this.constantOneLabelY.Location = new System.Drawing.Point(258, 140);
+ this.constantOneLabelY.Name = "constantOneLabelY";
+ this.constantOneLabelY.Size = new System.Drawing.Size(66, 13);
+ this.constantOneLabelY.TabIndex = 58;
+ this.constantOneLabelY.Text = "Acceleration";
+ //
+ // capLabelY
+ //
+ this.capLabelY.AutoSize = true;
+ this.capLabelY.Location = new System.Drawing.Point(279, 166);
+ this.capLabelY.Name = "capLabelY";
+ this.capLabelY.Size = new System.Drawing.Size(26, 13);
+ this.capLabelY.TabIndex = 59;
+ this.capLabelY.Text = "Cap";
+ //
+ // weightLabelY
+ //
+ this.weightLabelY.AutoSize = true;
+ this.weightLabelY.Location = new System.Drawing.Point(264, 192);
+ this.weightLabelY.Name = "weightLabelY";
+ this.weightLabelY.Size = new System.Drawing.Size(41, 13);
+ this.weightLabelY.TabIndex = 60;
+ this.weightLabelY.Text = "Weight";
+ //
+ // offsetLabelY
+ //
+ this.offsetLabelY.AutoSize = true;
+ this.offsetLabelY.Location = new System.Drawing.Point(270, 218);
+ this.offsetLabelY.Name = "offsetLabelY";
+ this.offsetLabelY.Size = new System.Drawing.Size(35, 13);
+ this.offsetLabelY.TabIndex = 61;
+ this.offsetLabelY.Text = "Offset";
+ //
+ // constantTwoLabelY
+ //
+ this.constantTwoLabelY.AutoSize = true;
+ this.constantTwoLabelY.Location = new System.Drawing.Point(264, 244);
+ this.constantTwoLabelY.Name = "constantTwoLabelY";
+ this.constantTwoLabelY.Size = new System.Drawing.Size(51, 13);
+ this.constantTwoLabelY.TabIndex = 62;
+ this.constantTwoLabelY.Text = "Limit/Exp";
+ //
+ // constantThreeLabelY
+ //
+ this.constantThreeLabelY.AutoSize = true;
+ this.constantThreeLabelY.Location = new System.Drawing.Point(264, 270);
+ this.constantThreeLabelY.Name = "constantThreeLabelY";
+ this.constantThreeLabelY.Size = new System.Drawing.Size(47, 13);
+ this.constantThreeLabelY.TabIndex = 63;
+ this.constantThreeLabelY.Text = "Midpoint";
+ //
+ // OptionSetXTitle
+ //
+ this.OptionSetXTitle.AutoSize = true;
+ this.OptionSetXTitle.Location = new System.Drawing.Point(142, 94);
+ this.OptionSetXTitle.Name = "OptionSetXTitle";
+ this.OptionSetXTitle.Size = new System.Drawing.Size(14, 13);
+ this.OptionSetXTitle.TabIndex = 64;
+ this.OptionSetXTitle.Text = "X";
+ //
+ // OptionSetYTitle
+ //
+ this.OptionSetYTitle.AutoSize = true;
+ this.OptionSetYTitle.Location = new System.Drawing.Point(359, 94);
+ this.OptionSetYTitle.Name = "OptionSetYTitle";
+ this.OptionSetYTitle.Size = new System.Drawing.Size(14, 13);
+ this.OptionSetYTitle.TabIndex = 65;
+ this.OptionSetYTitle.Text = "Y";
+ //
+ // AccelTypeActiveLabelY
+ //
+ this.AccelTypeActiveLabelY.AutoSize = true;
+ this.AccelTypeActiveLabelY.Location = new System.Drawing.Point(413, 113);
+ this.AccelTypeActiveLabelY.Name = "AccelTypeActiveLabelY";
+ this.AccelTypeActiveLabelY.Size = new System.Drawing.Size(66, 13);
+ this.AccelTypeActiveLabelY.TabIndex = 66;
+ this.AccelTypeActiveLabelY.Text = "SigmoidGain";
+ //
+ // ActiveValueTitleY
+ //
+ this.ActiveValueTitleY.AutoSize = true;
+ this.ActiveValueTitleY.Location = new System.Drawing.Point(428, 30);
+ this.ActiveValueTitleY.Name = "ActiveValueTitleY";
+ this.ActiveValueTitleY.Size = new System.Drawing.Size(37, 13);
+ this.ActiveValueTitleY.TabIndex = 67;
+ this.ActiveValueTitleY.Text = "Active";
+ //
+ // showLastMouseMoveToolStripMenuItem
+ //
+ this.showLastMouseMoveToolStripMenuItem.Checked = true;
+ this.showLastMouseMoveToolStripMenuItem.CheckOnClick = true;
+ this.showLastMouseMoveToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.showLastMouseMoveToolStripMenuItem.Name = "showLastMouseMoveToolStripMenuItem";
+ this.showLastMouseMoveToolStripMenuItem.Size = new System.Drawing.Size(199, 22);
+ this.showLastMouseMoveToolStripMenuItem.Text = "Show Last Mouse Move";
//
// RawAcceleration
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(1786, 958);
- this.Controls.Add(this.MidpointActiveLabel);
- this.Controls.Add(this.LimitExpActiveLabel);
- this.Controls.Add(this.OffsetActiveLabel);
+ this.ClientSize = new System.Drawing.Size(1884, 956);
+ this.Controls.Add(this.ActiveValueTitleY);
+ this.Controls.Add(this.AccelTypeActiveLabelY);
+ this.Controls.Add(this.OptionSetYTitle);
+ this.Controls.Add(this.OptionSetXTitle);
+ this.Controls.Add(this.constantThreeLabelY);
+ this.Controls.Add(this.constantTwoLabelY);
+ this.Controls.Add(this.offsetLabelY);
+ this.Controls.Add(this.weightLabelY);
+ this.Controls.Add(this.capLabelY);
+ this.Controls.Add(this.constantOneLabelY);
+ this.Controls.Add(this.ByComponentXYLock);
+ this.Controls.Add(this.MidpointActiveYLabel);
+ this.Controls.Add(this.LimitExpActiveYLabel);
+ this.Controls.Add(this.OffsetActiveYLabel);
+ this.Controls.Add(this.AccelerationActiveLabelY);
+ this.Controls.Add(this.accelTypeDropY);
+ this.Controls.Add(this.midpointBoxY);
+ this.Controls.Add(this.limitBoxY);
+ this.Controls.Add(this.offsetBoxY);
+ this.Controls.Add(this.accelerationBoxY);
+ this.Controls.Add(this.MidpointActiveXLabel);
+ this.Controls.Add(this.LimitExpActiveXLabel);
+ this.Controls.Add(this.OffsetActiveXLabel);
this.Controls.Add(this.CapActiveYLabel);
this.Controls.Add(this.WeightActiveYLabel);
this.Controls.Add(this.WeightActiveXLabel);
this.Controls.Add(this.CapActiveXLabel);
- this.Controls.Add(this.AccelerationActiveLabel);
- this.Controls.Add(this.AccelTypeActiveLabel);
+ this.Controls.Add(this.AccelerationActiveLabelX);
+ this.Controls.Add(this.AccelTypeActiveLabelX);
this.Controls.Add(this.RotationActiveLabel);
this.Controls.Add(this.SensitivityActiveYLabel);
this.Controls.Add(this.SensitivityActiveXLabel);
@@ -787,30 +1015,28 @@ namespace grapher
this.Controls.Add(this.GainChart);
this.Controls.Add(this.VelocityChart);
this.Controls.Add(this.LockXYLabel);
- this.Controls.Add(this.weightXYLock);
- this.Controls.Add(this.capXYLock);
this.Controls.Add(this.sensXYLock);
this.Controls.Add(this.capBoxY);
this.Controls.Add(this.sensitivityBoxY);
this.Controls.Add(this.writeButton);
- this.Controls.Add(this.offsetLabel);
- this.Controls.Add(this.offsetBox);
- this.Controls.Add(this.constantThreeLabel);
- this.Controls.Add(this.midpointBox);
- this.Controls.Add(this.constantTwoLabel);
- this.Controls.Add(this.limitBox);
- this.Controls.Add(this.weightBoxSecond);
- this.Controls.Add(this.weightLabel);
- this.Controls.Add(this.weightBoxFirst);
- this.Controls.Add(this.capLabel);
+ this.Controls.Add(this.offsetLabelX);
+ this.Controls.Add(this.offsetBoxX);
+ this.Controls.Add(this.constantThreeLabelX);
+ this.Controls.Add(this.midpointBoxX);
+ this.Controls.Add(this.constantTwoLabelX);
+ this.Controls.Add(this.limitBoxX);
+ this.Controls.Add(this.weightBoxY);
+ this.Controls.Add(this.weightLabelX);
+ this.Controls.Add(this.weightBoxX);
+ this.Controls.Add(this.capLabelX);
this.Controls.Add(this.capBoxX);
- this.Controls.Add(this.constantOneLabel);
- this.Controls.Add(this.accelerationBox);
+ this.Controls.Add(this.constantOneLabelX);
+ this.Controls.Add(this.accelerationBoxX);
this.Controls.Add(this.rotationLabel);
this.Controls.Add(this.rotationBox);
this.Controls.Add(this.sensitivityLabel);
this.Controls.Add(this.sensitivityBoxX);
- this.Controls.Add(this.accelTypeDrop);
+ this.Controls.Add(this.accelTypeDropX);
this.Controls.Add(this.AccelerationChart);
this.Controls.Add(this.menuStrip1);
this.Name = "RawAcceleration";
@@ -833,30 +1059,28 @@ namespace grapher
#endregion
private System.Windows.Forms.DataVisualization.Charting.Chart AccelerationChart;
- private System.Windows.Forms.ComboBox accelTypeDrop;
+ private System.Windows.Forms.ComboBox accelTypeDropX;
private System.Windows.Forms.TextBox sensitivityBoxX;
private System.Windows.Forms.Label sensitivityLabel;
private System.Windows.Forms.TextBox rotationBox;
private System.Windows.Forms.Label rotationLabel;
- private System.Windows.Forms.TextBox accelerationBox;
- private System.Windows.Forms.Label constantOneLabel;
+ private System.Windows.Forms.TextBox accelerationBoxX;
+ private System.Windows.Forms.Label constantOneLabelX;
private System.Windows.Forms.TextBox capBoxX;
- private System.Windows.Forms.Label capLabel;
- private System.Windows.Forms.TextBox weightBoxFirst;
- private System.Windows.Forms.Label weightLabel;
- private System.Windows.Forms.TextBox weightBoxSecond;
- private System.Windows.Forms.TextBox limitBox;
- private System.Windows.Forms.Label constantTwoLabel;
- private System.Windows.Forms.TextBox midpointBox;
- private System.Windows.Forms.Label constantThreeLabel;
- private System.Windows.Forms.TextBox offsetBox;
- private System.Windows.Forms.Label offsetLabel;
+ private System.Windows.Forms.Label capLabelX;
+ private System.Windows.Forms.TextBox weightBoxX;
+ private System.Windows.Forms.Label weightLabelX;
+ private System.Windows.Forms.TextBox weightBoxY;
+ private System.Windows.Forms.TextBox limitBoxX;
+ private System.Windows.Forms.Label constantTwoLabelX;
+ private System.Windows.Forms.TextBox midpointBoxX;
+ private System.Windows.Forms.Label constantThreeLabelX;
+ private System.Windows.Forms.TextBox offsetBoxX;
+ private System.Windows.Forms.Label offsetLabelX;
private System.Windows.Forms.Button writeButton;
private System.Windows.Forms.TextBox sensitivityBoxY;
private System.Windows.Forms.TextBox capBoxY;
private System.Windows.Forms.CheckBox sensXYLock;
- private System.Windows.Forms.CheckBox capXYLock;
- private System.Windows.Forms.CheckBox weightXYLock;
private System.Windows.Forms.Label LockXYLabel;
private System.Windows.Forms.DataVisualization.Charting.Chart VelocityChart;
private System.Windows.Forms.DataVisualization.Charting.Chart GainChart;
@@ -881,20 +1105,44 @@ namespace grapher
private System.Windows.Forms.Label SensitivityActiveXLabel;
private System.Windows.Forms.Label SensitivityActiveYLabel;
private System.Windows.Forms.Label RotationActiveLabel;
- private System.Windows.Forms.Label AccelTypeActiveLabel;
- private System.Windows.Forms.Label AccelerationActiveLabel;
+ private System.Windows.Forms.Label AccelTypeActiveLabelX;
+ private System.Windows.Forms.Label AccelerationActiveLabelX;
private System.Windows.Forms.Label CapActiveXLabel;
private System.Windows.Forms.Label WeightActiveXLabel;
private System.Windows.Forms.Label WeightActiveYLabel;
private System.Windows.Forms.Label CapActiveYLabel;
- private System.Windows.Forms.Label OffsetActiveLabel;
- private System.Windows.Forms.Label LimitExpActiveLabel;
- private System.Windows.Forms.Label MidpointActiveLabel;
+ private System.Windows.Forms.Label OffsetActiveXLabel;
+ private System.Windows.Forms.Label LimitExpActiveXLabel;
+ private System.Windows.Forms.Label MidpointActiveXLabel;
private System.Windows.Forms.ToolStripMenuItem startupToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem AutoWriteMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
+ private System.Windows.Forms.ToolStripMenuItem wholeVectorToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem byVectorComponentToolStripMenuItem;
+ private System.Windows.Forms.TextBox accelerationBoxY;
+ private System.Windows.Forms.TextBox offsetBoxY;
+ private System.Windows.Forms.TextBox limitBoxY;
+ private System.Windows.Forms.TextBox midpointBoxY;
+ private System.Windows.Forms.ComboBox accelTypeDropY;
+ private System.Windows.Forms.Label AccelerationActiveLabelY;
+ private System.Windows.Forms.Label OffsetActiveYLabel;
+ private System.Windows.Forms.Label LimitExpActiveYLabel;
+ private System.Windows.Forms.Label MidpointActiveYLabel;
+ private System.Windows.Forms.CheckBox ByComponentXYLock;
+ private System.Windows.Forms.Label constantOneLabelY;
+ private System.Windows.Forms.Label capLabelY;
+ private System.Windows.Forms.Label weightLabelY;
+ private System.Windows.Forms.Label offsetLabelY;
+ private System.Windows.Forms.Label constantTwoLabelY;
+ private System.Windows.Forms.Label constantThreeLabelY;
+ private System.Windows.Forms.Label OptionSetXTitle;
+ private System.Windows.Forms.Label OptionSetYTitle;
+ private System.Windows.Forms.Label AccelTypeActiveLabelY;
private System.Windows.Forms.ToolStripMenuItem offsetStyleToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem gainOffsetToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem legacyOffsetToolStripMenuItem;
+ private System.Windows.Forms.Label ActiveValueTitleY;
+ private System.Windows.Forms.ToolStripMenuItem showLastMouseMoveToolStripMenuItem;
}
}
diff --git a/grapher/Form1.cs b/grapher/Form1.cs
index ba0730c..103f239 100644
--- a/grapher/Form1.cs
+++ b/grapher/Form1.cs
@@ -12,6 +12,7 @@ using System.Runtime.InteropServices;
using grapher.Models.Calculations;
using grapher.Models.Options;
using grapher.Models.Serialized;
+using grapher.Models;
namespace grapher
{
@@ -36,146 +37,84 @@ namespace grapher
throw;
}
- var accelCharts = new AccelCharts(
- this,
- new ChartXY(AccelerationChart, AccelerationChartY),
- new ChartXY(VelocityChart, VelocityChartY),
- new ChartXY(GainChart, GainChartY),
- showVelocityGainToolStripMenuItem,
- new CheckBox[] { sensXYLock, weightXYLock, capXYLock });
-
- ActiveValueTitle.AutoSize = false;
- ActiveValueTitle.Left = LockXYLabel.Left + LockXYLabel.Width;
- ActiveValueTitle.Width = AccelerationChart.Left - ActiveValueTitle.Left;
- ActiveValueTitle.TextAlign = ContentAlignment.MiddleCenter;
-
- var sensitivity = new OptionXY(
+ AccelGUI = AccelGUIFactory.Construct(
+ this,
+ activeAccel,
+ AccelerationChart,
+ AccelerationChartY,
+ VelocityChart,
+ VelocityChartY,
+ GainChart,
+ GainChartY,
+ accelTypeDropX,
+ accelTypeDropY,
+ writeButton,
+ showVelocityGainToolStripMenuItem,
+ showLastMouseMoveToolStripMenuItem,
+ wholeVectorToolStripMenuItem,
+ byVectorComponentToolStripMenuItem,
+ gainCapToolStripMenuItem,
+ legacyCapToolStripMenuItem,
+ gainOffsetToolStripMenuItem,
+ legacyOffsetToolStripMenuItem,
+ AutoWriteMenuItem,
+ scaleByDPIToolStripMenuItem,
+ DPITextBox,
+ PollRateTextBox,
sensitivityBoxX,
sensitivityBoxY,
- sensXYLock,
- this,
- 1,
- sensitivityLabel,
- new ActiveValueLabelXY(
- new ActiveValueLabel(SensitivityActiveXLabel, ActiveValueTitle),
- new ActiveValueLabel(SensitivityActiveYLabel, ActiveValueTitle)),
- "Sensitivity",
- accelCharts);
-
- var rotation = new Option(
rotationBox,
- this,
- 0,
- rotationLabel,
- new ActiveValueLabel(RotationActiveLabel, ActiveValueTitle),
- "Rotation");
-
- var weight = new OptionXY(
- weightBoxFirst,
- weightBoxSecond,
- weightXYLock,
- this,
- 1,
- weightLabel,
- new ActiveValueLabelXY(
- new ActiveValueLabel(WeightActiveXLabel, ActiveValueTitle),
- new ActiveValueLabel(WeightActiveYLabel, ActiveValueTitle)),
- "Weight",
- accelCharts);
-
- var cap = new OptionXY(
+ weightBoxX,
+ weightBoxY,
capBoxX,
capBoxY,
- capXYLock,
- this,
- 0,
- capLabel,
- new ActiveValueLabelXY(
- new ActiveValueLabel(CapActiveXLabel, ActiveValueTitle),
- new ActiveValueLabel(CapActiveYLabel, ActiveValueTitle)),
- "Cap",
- accelCharts);
-
- var offset = new Option(
- offsetBox,
- this,
- 0,
- offsetLabel,
- new ActiveValueLabel(OffsetActiveLabel, ActiveValueTitle),
- "Offset");
-
- var offsetOptions = new OffsetOptions(
- gainOffsetToolStripMenuItem,
- legacyOffsetToolStripMenuItem,
- offset);
-
- // The name and layout of these options is handled by AccelerationOptions object.
- var acceleration = new Option(
- new Field(accelerationBox, this, 0),
- constantOneLabel,
- new ActiveValueLabel(AccelerationActiveLabel, ActiveValueTitle));
-
- var limitOrExponent = new Option(
- new Field(limitBox, this, 2),
- constantTwoLabel,
- new ActiveValueLabel(LimitExpActiveLabel, ActiveValueTitle));
-
- var midpoint = new Option(
- new Field(midpointBox, this, 0),
- constantThreeLabel,
- new ActiveValueLabel(MidpointActiveLabel, ActiveValueTitle));
-
- var accelerationOptions = new AccelOptions(
- accelTypeDrop,
- new Option[]
- {
- offset,
- acceleration,
- limitOrExponent,
- midpoint,
- },
- new OptionXY[]
- {
- weight,
- cap,
- },
- writeButton,
- new ActiveValueLabel(AccelTypeActiveLabel, ActiveValueTitle));
-
- var capOptions = new CapOptions(
- gainCapToolStripMenuItem,
- legacyCapToolStripMenuItem,
- cap,
- weight);
-
- var accelCalculator = new AccelCalculator(
- new Field(DPITextBox.TextBox, this, AccelCalculator.DefaultDPI),
- new Field(PollRateTextBox.TextBox, this, AccelCalculator.DefaultPollRate));
-
- var settings = new SettingsManager(
- activeAccel,
- accelCalculator.DPI,
- accelCalculator.PollRate,
- AutoWriteMenuItem);
-
- AccelGUI = new AccelGUI(
- this,
- accelCalculator,
- accelCharts,
- settings,
- accelerationOptions,
- sensitivity,
- rotation,
- weight,
- capOptions,
- offsetOptions,
- acceleration,
- limitOrExponent,
- midpoint,
- writeButton,
- MouseLabel,
- ScaleMenuItem,
- AutoWriteMenuItem);
+ offsetBoxX,
+ offsetBoxY,
+ accelerationBoxX,
+ accelerationBoxY,
+ limitBoxX,
+ limitBoxY,
+ midpointBoxX,
+ midpointBoxY,
+ sensXYLock,
+ ByComponentXYLock,
+ LockXYLabel,
+ sensitivityLabel,
+ rotationLabel,
+ weightLabelX,
+ weightLabelY,
+ capLabelX,
+ capLabelY,
+ offsetLabelX,
+ offsetLabelY,
+ constantOneLabelX,
+ constantOneLabelY,
+ constantTwoLabelX,
+ constantTwoLabelY,
+ constantThreeLabelX,
+ constantThreeLabelY,
+ ActiveValueTitle,
+ ActiveValueTitleY,
+ SensitivityActiveXLabel,
+ SensitivityActiveYLabel,
+ RotationActiveLabel,
+ WeightActiveXLabel,
+ WeightActiveYLabel,
+ CapActiveXLabel,
+ CapActiveYLabel,
+ OffsetActiveXLabel,
+ OffsetActiveYLabel,
+ AccelerationActiveLabelX,
+ AccelerationActiveLabelY,
+ LimitExpActiveXLabel,
+ LimitExpActiveYLabel,
+ MidpointActiveXLabel,
+ MidpointActiveYLabel,
+ AccelTypeActiveLabelX,
+ AccelTypeActiveLabelY,
+ OptionSetXTitle,
+ OptionSetYTitle,
+ MouseLabel);
}
#endregion Constructor
@@ -203,16 +142,11 @@ namespace grapher
}
- private void writeButton_Click(object sender, EventArgs e)
- {
- AccelGUI.UpdateActiveSettingsFromFields();
- }
-
- #endregion Methods
-
private void RawAcceleration_Paint(object sender, PaintEventArgs e)
{
- AccelGUI.AccelCharts.DrawPoints();
+ AccelGUI.AccelCharts.DrawLastMovement();
}
+
+ #endregion Method
}
}
diff --git a/grapher/Layouts/ClassicLayout.cs b/grapher/Layouts/ClassicLayout.cs
index 05f6c82..572566f 100644
--- a/grapher/Layouts/ClassicLayout.cs
+++ b/grapher/Layouts/ClassicLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,8 +9,13 @@ namespace grapher.Layouts
{
Name = "Classic";
Index = (int)AccelMode.classic;
- ShowOptions = new bool[] { true, true, true, false };
- OptionNames = new string[] { Offset, Acceleration, Exponent, string.Empty };
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(true, Cap);
+ WeightLayout = new OptionLayout(true, Weight);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(true, Exponent);
+ MidpointLayout = new OptionLayout(false, string.Empty);
}
}
}
diff --git a/grapher/Layouts/DefaultLayout.cs b/grapher/Layouts/DefaultLayout.cs
index 42841d5..83535c2 100644
--- a/grapher/Layouts/DefaultLayout.cs
+++ b/grapher/Layouts/DefaultLayout.cs
@@ -1,11 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
namespace grapher.Layouts
{
@@ -16,9 +9,14 @@ namespace grapher.Layouts
{
Name = "Default";
Index = (int)AccelMode.noaccel;
- ShowOptions = new bool[] { true, true, true, true };
- OptionNames = new string[] { Offset, Acceleration, $"{Limit}\\{Exponent}", Midpoint };
ButtonEnabled = false;
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(true, Cap);
+ WeightLayout = new OptionLayout(true, Weight);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(true, $"{Limit}\\{Exponent}");
+ MidpointLayout = new OptionLayout(true, Midpoint);
}
}
}
diff --git a/grapher/Layouts/LayoutBase.cs b/grapher/Layouts/LayoutBase.cs
index eed1716..6ed8fee 100644
--- a/grapher/Layouts/LayoutBase.cs
+++ b/grapher/Layouts/LayoutBase.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using grapher.Models.Options;
using System.Windows.Forms;
namespace grapher.Layouts
@@ -15,12 +11,18 @@ namespace grapher.Layouts
public const string Limit = "Limit";
public const string Midpoint = "Midpoint";
public const string Offset = "Offset";
+ public const string Cap = "Cap";
+ public const string Weight = "Weight";
public LayoutBase()
{
- ShowOptions = new bool[] { false, false, false, false };
- ShowOptionsXY = new bool[] { true, true };
- OptionNames = new string[] { string.Empty, string.Empty, string.Empty, string.Empty };
+ AccelLayout = new OptionLayout(false, string.Empty);
+ CapLayout = new OptionLayout(false, string.Empty);
+ WeightLayout = new OptionLayout(false, string.Empty);
+ OffsetLayout = new OptionLayout(false, string.Empty);
+ LimExpLayout = new OptionLayout(false, string.Empty);
+ MidpointLayout = new OptionLayout(false, string.Empty);
+
ButtonEnabled = true;
}
@@ -32,43 +34,75 @@ namespace grapher.Layouts
public string Name { get; internal set; }
- internal bool[] ShowOptions { get; set; }
+ protected bool ButtonEnabled { get; set; }
+
+ protected OptionLayout AccelLayout { get; set; }
+
+ protected OptionLayout CapLayout { get; set; }
- internal bool[] ShowOptionsXY { get; set; }
+ protected OptionLayout WeightLayout { get; set; }
- internal string[] OptionNames { get; set; }
+ protected OptionLayout OffsetLayout { get; set; }
- internal bool ButtonEnabled { get; set; }
+ protected OptionLayout LimExpLayout { get; set; }
- public void Layout(Option[] options, OptionXY[] optionsXY, Button button)
+ protected OptionLayout MidpointLayout { get; set; }
+
+ public void Layout(
+ IOption accelOption,
+ IOption capOption,
+ IOption weightOption,
+ IOption offsetOption,
+ IOption limExpOption,
+ IOption midpointOption,
+ Button button,
+ int top)
{
- // Relies on AccelOptions to keep lengths correct.
- for (int i = 0; i < options.Length; i++)
- {
- if (ShowOptions[i])
- {
- options[i].Show(OptionNames[i]);
- }
- else
- {
- options[i].Hide();
- }
- }
+ AccelLayout.Layout(accelOption);
+ CapLayout.Layout(capOption);
+ WeightLayout.Layout(weightOption);
+ OffsetLayout.Layout(offsetOption);
+ LimExpLayout.Layout(limExpOption);
+ MidpointLayout.Layout(midpointOption);
+
+ button.Enabled = ButtonEnabled;
- // Relies on AccelOptions to keep lengths correct.
- for (int i = 0; i< optionsXY.Length; i++)
+ IOption previous = null;
+ foreach (var option in new IOption[] { accelOption, capOption, weightOption, offsetOption, limExpOption, midpointOption})
{
- if (ShowOptionsXY[i])
- {
- optionsXY[i].Show();
- }
- else
+ if (option.Visible)
{
- optionsXY[i].Hide();
+ if (previous != null)
+ {
+ option.SnapTo(previous);
+ }
+ else
+ {
+ option.Top = top;
+ }
+
+ previous = option;
}
}
+ }
- button.Enabled = ButtonEnabled;
+ public void Layout(
+ IOption accelOption,
+ IOption capOption,
+ IOption weightOption,
+ IOption offsetOption,
+ IOption limExpOption,
+ IOption midpointOption,
+ Button button)
+ {
+ Layout(accelOption,
+ capOption,
+ weightOption,
+ offsetOption,
+ limExpOption,
+ midpointOption,
+ button,
+ accelOption.Top);
}
}
}
diff --git a/grapher/Layouts/LinearLayout.cs b/grapher/Layouts/LinearLayout.cs
index 0a79a64..fded8c7 100644
--- a/grapher/Layouts/LinearLayout.cs
+++ b/grapher/Layouts/LinearLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,8 +9,13 @@ namespace grapher.Layouts
{
Name = "Linear";
Index = (int)AccelMode.linear;
- ShowOptions = new bool[] { true, true, false, false };
- OptionNames = new string[] { Offset, Acceleration, string.Empty, string.Empty };
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(true, Cap);
+ WeightLayout = new OptionLayout(false, string.Empty);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(false, string.Empty);
+ MidpointLayout = new OptionLayout(false, string.Empty);
}
}
}
diff --git a/grapher/Layouts/LogLayout.cs b/grapher/Layouts/LogLayout.cs
deleted file mode 100644
index 1206fb3..0000000
--- a/grapher/Layouts/LogLayout.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace grapher.Layouts
-{
- public class LogLayout : LayoutBase
- {
- public LogLayout()
- : base()
- {
- Name = "Logarithmic";
- Index = (int)AccelMode.logarithmic;
- ShowOptions = new bool[] { true, true, false, false };
- OptionNames = new string[] { Offset, Acceleration, string.Empty, string.Empty };
- }
- }
-}
diff --git a/grapher/Layouts/NaturalGainLayout.cs b/grapher/Layouts/NaturalGainLayout.cs
index 9bb1ec8..b982b91 100644
--- a/grapher/Layouts/NaturalGainLayout.cs
+++ b/grapher/Layouts/NaturalGainLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,8 +9,13 @@ namespace grapher.Layouts
{
Name = "NaturalGain";
Index = (int)AccelMode.naturalgain;
- ShowOptions = new bool[] { true, true, true, false };
- OptionNames = new string[] { Offset, Acceleration, Limit, string.Empty };
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(false, string.Empty);
+ WeightLayout = new OptionLayout(false, string.Empty);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(true, Limit);
+ MidpointLayout = new OptionLayout(false, string.Empty);
}
}
}
diff --git a/grapher/Layouts/NaturalLayout.cs b/grapher/Layouts/NaturalLayout.cs
index 44c6c18..aa5c22c 100644
--- a/grapher/Layouts/NaturalLayout.cs
+++ b/grapher/Layouts/NaturalLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,8 +9,13 @@ namespace grapher.Layouts
{
Name = "Natural";
Index = (int)AccelMode.natural;
- ShowOptions = new bool[] { true, true, true, false };
- OptionNames = new string[] { Offset, Acceleration, Limit, string.Empty };
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(false, string.Empty);
+ WeightLayout = new OptionLayout(false, string.Empty);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(true, Limit);
+ MidpointLayout = new OptionLayout(false, string.Empty);
}
}
}
diff --git a/grapher/Layouts/OffLayout.cs b/grapher/Layouts/OffLayout.cs
index ce7c149..85c8d3f 100644
--- a/grapher/Layouts/OffLayout.cs
+++ b/grapher/Layouts/OffLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,10 +9,14 @@ namespace grapher.Layouts
{
Name = "Off";
Index = (int)AccelMode.noaccel;
- ShowOptions = new bool[] { false, false, false, false };
- OptionNames = new string[] { string.Empty, string.Empty, string.Empty, string.Empty };
- ShowOptionsXY = new bool[] { false, false };
ButtonEnabled = true;
+
+ AccelLayout = new OptionLayout(false, string.Empty);
+ CapLayout = new OptionLayout(false, string.Empty);
+ WeightLayout = new OptionLayout(false, string.Empty);
+ OffsetLayout = new OptionLayout(false, string.Empty);
+ LimExpLayout = new OptionLayout(false, string.Empty);
+ MidpointLayout = new OptionLayout(false, string.Empty);
}
}
}
diff --git a/grapher/Layouts/OptionLayout.cs b/grapher/Layouts/OptionLayout.cs
new file mode 100644
index 0000000..2f29706
--- /dev/null
+++ b/grapher/Layouts/OptionLayout.cs
@@ -0,0 +1,41 @@
+using grapher.Models.Options;
+
+namespace grapher.Layouts
+{
+ public class OptionLayout
+ {
+ #region Constructors
+
+ public OptionLayout(bool show, string name)
+ {
+ Show = show;
+ Name = name;
+ }
+
+ #endregion Constructors
+
+ #region Properties
+
+ private bool Show { get; }
+
+ private string Name { get; }
+
+ #endregion Properties
+
+ #region Methods
+
+ public void Layout(IOption option)
+ {
+ if (Show)
+ {
+ option.Show(Name);
+ }
+ else
+ {
+ option.Hide();
+ }
+ }
+
+ #endregion Methods
+ }
+}
diff --git a/grapher/Layouts/PowerLayout.cs b/grapher/Layouts/PowerLayout.cs
index c14083a..e0dcaf8 100644
--- a/grapher/Layouts/PowerLayout.cs
+++ b/grapher/Layouts/PowerLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,8 +9,13 @@ namespace grapher.Layouts
{
Name = "Power";
Index = (int)AccelMode.power;
- ShowOptions = new bool[] { true, true, true, false };
- OptionNames = new string[] { Offset, Scale, Exponent, string.Empty };
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(true, Cap);
+ WeightLayout = new OptionLayout(true, Weight);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(true, Limit);
+ MidpointLayout = new OptionLayout(false, string.Empty);
}
}
}
diff --git a/grapher/Layouts/SigmoidGainLayout.cs b/grapher/Layouts/SigmoidGainLayout.cs
index 93214ec..183e31f 100644
--- a/grapher/Layouts/SigmoidGainLayout.cs
+++ b/grapher/Layouts/SigmoidGainLayout.cs
@@ -1,9 +1,4 @@
using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Layouts
{
@@ -14,8 +9,13 @@ namespace grapher.Layouts
{
Name = "SigmoidGain";
Index = (int)AccelMode.sigmoidgain;
- ShowOptions = new bool[] { true, true, true, true };
- OptionNames = new string[] { Offset, Acceleration, Limit, Midpoint };
+
+ AccelLayout = new OptionLayout(true, Acceleration);
+ CapLayout = new OptionLayout(false, string.Empty);
+ WeightLayout = new OptionLayout(false, string.Empty);
+ OffsetLayout = new OptionLayout(true, Offset);
+ LimExpLayout = new OptionLayout(true, Limit);
+ MidpointLayout = new OptionLayout(true, Midpoint);
}
}
}
diff --git a/grapher/Layouts/SigmoidLayout.cs b/grapher/Layouts/SigmoidLayout.cs
deleted file mode 100644
index 1c7f0b9..0000000
--- a/grapher/Layouts/SigmoidLayout.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using grapher.Models.Serialized;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace grapher.Layouts
-{
- public class SigmoidLayout : LayoutBase
- {
- public SigmoidLayout()
- : base()
- {
- Name = "Sigmoid";
- Index = (int)AccelMode.sigmoid;
- ShowOptions = new bool[] { true, true, true, true };
- OptionNames = new string[] { Offset, Acceleration, Limit, Midpoint };
- }
- }
-}
diff --git a/grapher/Models/AccelGUI.cs b/grapher/Models/AccelGUI.cs
index a7d5d49..3acb943 100644
--- a/grapher/Models/AccelGUI.cs
+++ b/grapher/Models/AccelGUI.cs
@@ -3,67 +3,47 @@ using grapher.Models.Mouse;
using grapher.Models.Options;
using grapher.Models.Serialized;
using System;
-using System.CodeDom;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
namespace grapher
{
public class AccelGUI
{
- #region constructors
+ #region Constructors
public AccelGUI(
RawAcceleration accelForm,
AccelCalculator accelCalculator,
AccelCharts accelCharts,
SettingsManager settings,
- AccelOptions accelOptions,
- OptionXY sensitivity,
- Option rotation,
- OptionXY weight,
- CapOptions cap,
- OffsetOptions offset,
- Option acceleration,
- Option limtOrExp,
- Option midpoint,
+ ApplyOptions applyOptions,
Button writeButton,
Label mouseMoveLabel,
- ToolStripMenuItem scaleMenuItem,
- ToolStripMenuItem autoWriteMenuItem)
+ ToolStripMenuItem scaleMenuItem)
{
AccelForm = accelForm;
AccelCalculator = accelCalculator;
AccelCharts = accelCharts;
- AccelerationOptions = accelOptions;
- Sensitivity = sensitivity;
- Rotation = rotation;
- Weight = weight;
- Cap = cap;
- Offset = offset;
- Acceleration = acceleration;
- LimitOrExponent = limtOrExp;
- Midpoint = midpoint;
+ ApplyOptions = applyOptions;
WriteButton = writeButton;
ScaleMenuItem = scaleMenuItem;
Settings = settings;
Settings.Startup();
- UpdateGraph();
+ RefreshOnRead();
MouseWatcher = new MouseWatcher(AccelForm, mouseMoveLabel, AccelCharts);
ScaleMenuItem.Click += new System.EventHandler(OnScaleMenuItemClick);
+ WriteButton.Click += new System.EventHandler(OnWriteButtonClick);
+
+ ButtonTimer = SetupButtonTimer();
+ SetupWriteButton();
}
- #endregion constructors
+ #endregion Constructors
- #region properties
+ #region Properties
public RawAcceleration AccelForm { get; }
@@ -73,67 +53,33 @@ namespace grapher
public SettingsManager Settings { get; }
- public AccelOptions AccelerationOptions { get; }
-
- public OptionXY Sensitivity { get; }
-
- public Option Rotation { get; }
-
- public OptionXY Weight { get; }
-
- public CapOptions Cap { get; }
-
- public OffsetOptions Offset { get; }
-
- public Option Acceleration { get; }
-
- public Option LimitOrExponent { get; }
-
- public Option Midpoint { get; }
+ public ApplyOptions ApplyOptions { get; }
public Button WriteButton { get; }
+ public Timer ButtonTimer { get; }
+
public MouseWatcher MouseWatcher { get; }
public ToolStripMenuItem ScaleMenuItem { get; }
- #endregion properties
+ #endregion Properties
- #region methods
+ #region Methods
public void UpdateActiveSettingsFromFields()
{
var settings = new DriverSettings
{
- rotation = Rotation.Field.Data,
+ rotation = ApplyOptions.Rotation.Field.Data,
sensitivity = new Vec2<double>
{
- x = Sensitivity.Fields.X,
- y = Sensitivity.Fields.Y
- },
- combineMagnitudes = true,
- modes = new Vec2<AccelMode>
- {
- x = (AccelMode)AccelerationOptions.AccelerationIndex
- },
- args = new Vec2<AccelArgs>
- {
- x = new AccelArgs
- {
- offset = Offset.Offset,
- legacy_offset = Offset.LegacyOffset,
- weight = Weight.Fields.X,
- gainCap = Cap.VelocityGainCap,
- scaleCap = Cap.SensitivityCapX,
- accel = Acceleration.Field.Data,
- rate = Acceleration.Field.Data,
- powerScale = Acceleration.Field.Data,
- limit = LimitOrExponent.Field.Data,
- exponent = LimitOrExponent.Field.Data,
- powerExponent = LimitOrExponent.Field.Data,
- midpoint = Midpoint.Field.Data
- }
+ x = ApplyOptions.Sensitivity.Fields.X,
+ y = ApplyOptions.Sensitivity.Fields.Y
},
+ combineMagnitudes = ApplyOptions.IsWhole,
+ modes = ApplyOptions.GetModes(),
+ args = ApplyOptions.GetArgs(),
minimumTime = .4
};
@@ -141,10 +87,17 @@ namespace grapher
{
AccelForm.Invoke((MethodInvoker)delegate
{
+ WriteButtonDelay();
UpdateGraph();
});
});
-
+ RefreshOnRead();
+ }
+
+ public void RefreshOnRead()
+ {
+ UpdateGraph();
+ UpdateShownActiveValues();
}
public void UpdateGraph()
@@ -154,29 +107,66 @@ namespace grapher
Settings.ActiveAccel,
Settings.RawAccelSettings.AccelerationSettings);
AccelCharts.Bind();
- UpdateActiveValueLabels();
}
- public void UpdateActiveValueLabels()
+ public void UpdateShownActiveValues()
{
var settings = Settings.RawAccelSettings.AccelerationSettings;
-
- Sensitivity.SetActiveValues(settings.sensitivity.x, settings.sensitivity.y);
- Rotation.SetActiveValue(settings.rotation);
- AccelerationOptions.SetActiveValue((int)settings.modes.x);
- Offset.SetActiveValue(settings.args.x.offset, settings.args.y.offset);
- Weight.SetActiveValues(settings.args.x.weight, settings.args.x.weight);
- Acceleration.SetActiveValue(settings.args.x.accel); // rate, powerscale
- LimitOrExponent.SetActiveValue(settings.args.x.limit); //exp, powerexp
- Midpoint.SetActiveValue(settings.args.x.midpoint);
- //Cap.SetActiveValues(Settings.ActiveAccel.GainCap, Settings.ActiveAccel.CapX, Settings.ActiveAccel.CapY, Settings.ActiveAccel.GainCapEnabled);
+
+ AccelCharts.ShowActive(settings);
+ ApplyOptions.SetActiveValues(settings);
+ }
+
+ private Timer SetupButtonTimer()
+ {
+ Timer buttonTimer = new Timer();
+ buttonTimer.Enabled = true;
+ buttonTimer.Interval = Convert.ToInt32(ManagedAccel.WriteDelay);
+ buttonTimer.Tick += new System.EventHandler(OnButtonTimerTick);
+ return buttonTimer;
+ }
+
+ private void SetupWriteButton()
+ {
+ WriteButton.Top = AccelCharts.SensitivityChart.Top + AccelCharts.SensitivityChart.Height - Constants.WriteButtonVerticalOffset;
+ SetWriteButtonDefault();
+ }
+
+ private void SetWriteButtonDefault()
+ {
+ WriteButton.Text = Constants.WriteButtonDefaultText;
+ WriteButton.Enabled = true;
+ }
+
+ private void SetWriteButtonDelay()
+ {
+ WriteButton.Enabled = false;
+ WriteButton.Text = $"{Constants.WriteButtonDelayText} : {ButtonTimer.Interval} ms";
}
private void OnScaleMenuItemClick(object sender, EventArgs e)
{
UpdateGraph();
}
- #endregion methods
+
+ private void OnWriteButtonClick(object sender, EventArgs e)
+ {
+ UpdateActiveSettingsFromFields();
+ }
+
+ private void OnButtonTimerTick(object sender, EventArgs e)
+ {
+ ButtonTimer.Stop();
+ SetWriteButtonDefault();
+ }
+
+ private void WriteButtonDelay()
+ {
+ SetWriteButtonDelay();
+ ButtonTimer.Start();
+ }
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/AccelGUIFactory.cs b/grapher/Models/AccelGUIFactory.cs
new file mode 100644
index 0000000..42a7b83
--- /dev/null
+++ b/grapher/Models/AccelGUIFactory.cs
@@ -0,0 +1,303 @@
+using grapher.Models.Calculations;
+using grapher.Models.Options;
+using grapher.Models.Serialized;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace grapher.Models
+{
+ public static class AccelGUIFactory
+ {
+ #region Methods
+
+ public static AccelGUI Construct(
+ RawAcceleration form,
+ ManagedAccel activeAccel,
+ Chart accelerationChart,
+ Chart accelerationChartY,
+ Chart velocityChart,
+ Chart velocityChartY,
+ Chart gainChart,
+ Chart gainChartY,
+ ComboBox accelTypeDropX,
+ ComboBox accelTypeDropY,
+ Button writeButton,
+ ToolStripMenuItem showVelocityGainToolStripMenuItem,
+ ToolStripMenuItem showLastMouseMoveMenuItem,
+ ToolStripMenuItem wholeVectorToolStripMenuItem,
+ ToolStripMenuItem byVectorComponentToolStripMenuItem,
+ ToolStripMenuItem velocityGainCapToolStripMenuItem,
+ ToolStripMenuItem legacyCapToolStripMenuItem,
+ ToolStripMenuItem gainOffsetToolStripMenuItem,
+ ToolStripMenuItem legacyOffsetToolStripMenuItem,
+ ToolStripMenuItem autoWriteMenuItem,
+ ToolStripMenuItem scaleMenuItem,
+ ToolStripTextBox dpiTextBox,
+ ToolStripTextBox pollRateTextBox,
+ TextBox sensitivityBoxX,
+ TextBox sensitivityBoxY,
+ TextBox rotationBox,
+ TextBox weightBoxX,
+ TextBox weightBoxY,
+ TextBox capBoxX,
+ TextBox capBoxY,
+ TextBox offsetBoxX,
+ TextBox offsetBoxY,
+ TextBox accelerationBoxX,
+ TextBox accelerationBoxY,
+ TextBox limitBoxX,
+ TextBox limitBoxY,
+ TextBox midpointBoxX,
+ TextBox midpointBoxY,
+ CheckBox sensXYLock,
+ CheckBox byComponentXYLock,
+ Label lockXYLabel,
+ Label sensitivityLabel,
+ Label rotationLabel,
+ Label weightLabelX,
+ Label weightLabelY,
+ Label capLabelX,
+ Label capLabelY,
+ Label offsetLabelX,
+ Label offsetLabelY,
+ Label constantOneLabelX,
+ Label constantOneLabelY,
+ Label constantTwoLabelX,
+ Label constantTwoLabelY,
+ Label constantThreeLabelX,
+ Label constantThreeLabelY,
+ Label activeValueTitleX,
+ Label activeValueTitleY,
+ Label sensitivityActiveXLabel,
+ Label sensitivityActiveYLabel,
+ Label rotationActiveLabel,
+ Label weightActiveXLabel,
+ Label weightActiveYLabel,
+ Label capActiveXLabel,
+ Label capActiveYLabel,
+ Label offsetActiveLabelX,
+ Label offsetActiveLabelY,
+ Label accelerationActiveLabelX,
+ Label accelerationActiveLabelY,
+ Label limitExpActiveLabelX,
+ Label limitExpActiveLabelY,
+ Label midpointActiveLabelX,
+ Label midpointActiveLabelY,
+ Label accelTypeActiveLabelX,
+ Label accelTypeActiveLabelY,
+ Label optionSetXTitle,
+ Label optionSetYTitle,
+ Label mouseLabel)
+ {
+ var accelCharts = new AccelCharts(
+ form,
+ new ChartXY(accelerationChart, accelerationChartY),
+ new ChartXY(velocityChart, velocityChartY),
+ new ChartXY(gainChart, gainChartY),
+ showVelocityGainToolStripMenuItem,
+ showLastMouseMoveMenuItem,
+ writeButton);
+
+ var sensitivity = new OptionXY(
+ sensitivityBoxX,
+ sensitivityBoxY,
+ sensXYLock,
+ form,
+ 1,
+ sensitivityLabel,
+ new ActiveValueLabelXY(
+ new ActiveValueLabel(sensitivityActiveXLabel, activeValueTitleX),
+ new ActiveValueLabel(sensitivityActiveYLabel, activeValueTitleX)),
+ "Sensitivity");
+
+ var rotation = new Option(
+ rotationBox,
+ form,
+ 0,
+ rotationLabel,
+ 0,
+ new ActiveValueLabel(rotationActiveLabel, activeValueTitleX),
+ "Rotation");
+
+ var optionSetYLeft = rotation.Left + rotation.Width;
+
+ var weightX = new Option(
+ weightBoxX,
+ form,
+ 1,
+ weightLabelX,
+ 0,
+ new ActiveValueLabel(weightActiveXLabel, activeValueTitleX),
+ "Weight");
+
+ var weightY = new Option(
+ weightBoxY,
+ form,
+ 1,
+ weightLabelY,
+ optionSetYLeft,
+ new ActiveValueLabel(weightActiveYLabel, activeValueTitleY),
+ "Weight");
+
+ var capX = new Option(
+ capBoxX,
+ form,
+ 0,
+ capLabelX,
+ 0,
+ new ActiveValueLabel(capActiveXLabel, activeValueTitleX),
+ "Cap");
+
+ var capY = new Option(
+ capBoxY,
+ form,
+ 0,
+ capLabelY,
+ optionSetYLeft,
+ new ActiveValueLabel(capActiveYLabel, activeValueTitleY),
+ "Cap");
+
+ var offsetX = new Option(
+ offsetBoxX,
+ form,
+ 0,
+ offsetLabelX,
+ 0,
+ new ActiveValueLabel(offsetActiveLabelX, activeValueTitleX),
+ "Offset");
+
+ var offsetY = new Option(
+ offsetBoxY,
+ form,
+ 0,
+ offsetLabelY,
+ optionSetYLeft,
+ new ActiveValueLabel(offsetActiveLabelY, activeValueTitleY),
+ "Offset");
+
+ var offsetOptionsX = new OffsetOptions(
+ gainOffsetToolStripMenuItem,
+ legacyOffsetToolStripMenuItem,
+ offsetX);
+
+ var offsetOptionsY = new OffsetOptions(
+ gainOffsetToolStripMenuItem,
+ legacyOffsetToolStripMenuItem,
+ offsetY);
+
+ var accelerationX = new Option(
+ new Field(accelerationBoxX, form, 0),
+ constantOneLabelX,
+ new ActiveValueLabel(accelerationActiveLabelX, activeValueTitleX),
+ 0);
+
+ var accelerationY = new Option(
+ new Field(accelerationBoxY, form, 0),
+ constantOneLabelY,
+ new ActiveValueLabel(accelerationActiveLabelY, activeValueTitleY),
+ optionSetYLeft);
+
+ var limitOrExponentX = new Option(
+ new Field(limitBoxX, form, 2),
+ constantTwoLabelX,
+ new ActiveValueLabel(limitExpActiveLabelX, activeValueTitleX),
+ 0);
+
+ var limitOrExponentY = new Option(
+ new Field(limitBoxY, form, 2),
+ constantTwoLabelY,
+ new ActiveValueLabel(limitExpActiveLabelY, activeValueTitleY),
+ optionSetYLeft);
+
+ var midpointX = new Option(
+ new Field(midpointBoxX, form, 0),
+ constantThreeLabelX,
+ new ActiveValueLabel(midpointActiveLabelX, activeValueTitleY),
+ 0);
+
+ var midpointY = new Option(
+ new Field(midpointBoxY, form, 0),
+ constantThreeLabelY,
+ new ActiveValueLabel(midpointActiveLabelY, activeValueTitleY),
+ optionSetYLeft);
+
+ var capOptionsX = new CapOptions(
+ velocityGainCapToolStripMenuItem,
+ legacyCapToolStripMenuItem,
+ capX);
+
+ var capOptionsY = new CapOptions(
+ velocityGainCapToolStripMenuItem,
+ legacyCapToolStripMenuItem,
+ capY);
+
+ var accelerationOptionsX = new AccelTypeOptions(
+ accelTypeDropX,
+ accelerationX,
+ capOptionsX,
+ weightX,
+ offsetOptionsX,
+ limitOrExponentX,
+ midpointX,
+ writeButton,
+ new ActiveValueLabel(accelTypeActiveLabelX, activeValueTitleX));
+
+ var accelerationOptionsY = new AccelTypeOptions(
+ accelTypeDropY,
+ accelerationY,
+ capOptionsY,
+ weightY,
+ offsetOptionsY,
+ limitOrExponentY,
+ midpointY,
+ writeButton,
+ new ActiveValueLabel(accelTypeActiveLabelY, activeValueTitleY));
+
+ var optionsSetX = new AccelOptionSet(
+ optionSetXTitle,
+ activeValueTitleX,
+ rotationBox.Top + rotationBox.Height + Constants.OptionVerticalSeperation,
+ accelerationOptionsX);
+
+ var optionsSetY = new AccelOptionSet(
+ optionSetYTitle,
+ activeValueTitleY,
+ rotationBox.Top + rotationBox.Height + Constants.OptionVerticalSeperation,
+ accelerationOptionsY);
+
+ var applyOptions = new ApplyOptions(
+ wholeVectorToolStripMenuItem,
+ byVectorComponentToolStripMenuItem,
+ byComponentXYLock,
+ optionsSetX,
+ optionsSetY,
+ sensitivity,
+ rotation,
+ lockXYLabel,
+ accelCharts);
+
+ var accelCalculator = new AccelCalculator(
+ new Field(dpiTextBox.TextBox, form, Constants.DefaultDPI),
+ new Field(pollRateTextBox.TextBox, form, Constants.DefaultPollRate));
+
+ var settings = new SettingsManager(
+ activeAccel,
+ accelCalculator.DPI,
+ accelCalculator.PollRate,
+ autoWriteMenuItem,
+ showLastMouseMoveMenuItem);
+
+ return new AccelGUI(
+ form,
+ accelCalculator,
+ accelCharts,
+ settings,
+ applyOptions,
+ writeButton,
+ mouseLabel,
+ scaleMenuItem);
+ }
+
+ #endregion Methods
+ }
+}
diff --git a/grapher/Models/Calculations/AccelCalculator.cs b/grapher/Models/Calculations/AccelCalculator.cs
index 102de8d..092a7aa 100644
--- a/grapher/Models/Calculations/AccelCalculator.cs
+++ b/grapher/Models/Calculations/AccelCalculator.cs
@@ -3,19 +3,12 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
namespace grapher.Models.Calculations
{
public class AccelCalculator
{
- public const int DefaultDPI = 1200;
- public const int DefaultPollRate = 1000;
- public const int Resolution = 100;
- public const double MaxMultiplier = 85;
- public const double XYToCombinedRatio = 1.3;
+ #region Structs
public struct MagnitudeData
{
@@ -24,6 +17,9 @@ namespace grapher.Models.Calculations
public int y;
}
+ #endregion Structs
+
+ #region Constructors
public AccelCalculator(Field dpi, Field pollRate)
{
@@ -31,6 +27,10 @@ namespace grapher.Models.Calculations
PollRate = pollRate;
}
+ #endregion Constructors
+
+ #region Properties
+
public ReadOnlyCollection<MagnitudeData> MagnitudesCombined { get; private set; }
public ReadOnlyCollection<MagnitudeData> MagnitudesX { get; private set; }
@@ -47,6 +47,10 @@ namespace grapher.Models.Calculations
private int Increment { get; set; }
+ #endregion Fields
+
+ #region Methods
+
public void Calculate(AccelData data, ManagedAccel accel, DriverSettings settings)
{
ScaleByMouseSettings();
@@ -171,12 +175,14 @@ namespace grapher.Models.Calculations
public void ScaleByMouseSettings()
{
var dpiPollFactor = DPI.Data / PollRate.Data;
- CombinedMaxVelocity = dpiPollFactor * MaxMultiplier;
- Increment = (int) Math.Floor(CombinedMaxVelocity / Resolution);
- XYMaxVelocity = CombinedMaxVelocity * 1.5;
+ CombinedMaxVelocity = dpiPollFactor * Constants.MaxMultiplier;
+ Increment = (int)Math.Floor(CombinedMaxVelocity / Constants.Resolution);
+ XYMaxVelocity = CombinedMaxVelocity * Constants.XYToCombinedRatio;
MagnitudesCombined = GetMagnitudes();
MagnitudesX = GetMagnitudesX();
MagnitudesY = GetMagnitudesY();
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Calculations/AccelChartData.cs b/grapher/Models/Calculations/AccelChartData.cs
index 20142a7..8c0c8ea 100644
--- a/grapher/Models/Calculations/AccelChartData.cs
+++ b/grapher/Models/Calculations/AccelChartData.cs
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Models.Calculations
{
public class AccelChartData
{
+ #region Constructors
+
public AccelChartData()
{
AccelPoints = new SortedDictionary<double, double>();
@@ -17,6 +17,10 @@ namespace grapher.Models.Calculations
OutVelocityToPoints = new Dictionary<double, (double, double, double)>();
}
+ #endregion Constructors
+
+ #region Properties
+
public SortedDictionary<double, double> AccelPoints { get; }
public SortedDictionary<double, double> VelocityPoints { get; }
@@ -27,6 +31,10 @@ namespace grapher.Models.Calculations
public Dictionary<double, (double, double, double)> OutVelocityToPoints { get; }
+ #endregion Properties
+
+ #region Methods
+
public void Clear()
{
AccelPoints.Clear();
@@ -57,5 +65,7 @@ namespace grapher.Models.Calculations
return values;
}
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Calculations/AccelData.cs b/grapher/Models/Calculations/AccelData.cs
index 683c67e..eef4d01 100644
--- a/grapher/Models/Calculations/AccelData.cs
+++ b/grapher/Models/Calculations/AccelData.cs
@@ -1,15 +1,11 @@
using grapher.Models.Charts;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using static grapher.AccelCharts;
namespace grapher.Models.Calculations
{
public class AccelData
{
+ #region Constructors
public AccelData(
EstimatedPoints combined,
@@ -25,6 +21,10 @@ namespace grapher.Models.Calculations
EstimatedY = y;
}
+ #endregion Constructors
+
+ #region Properties
+
public AccelChartData Combined { get; }
public AccelChartData X { get; }
@@ -37,6 +37,10 @@ namespace grapher.Models.Calculations
private EstimatedPoints EstimatedY { get; }
+ #endregion Properties
+
+ #region Methods
+
public void Clear()
{
Combined.Clear();
@@ -70,5 +74,6 @@ namespace grapher.Models.Calculations
EstimatedY.Gain.Set(inYVelocity, yGain);
}
+ #endregion Methods
}
}
diff --git a/grapher/Models/Charts/AccelCharts.cs b/grapher/Models/Charts/AccelCharts.cs
index 1aa3909..3f228c3 100644
--- a/grapher/Models/Charts/AccelCharts.cs
+++ b/grapher/Models/Charts/AccelCharts.cs
@@ -1,23 +1,15 @@
using grapher.Models.Calculations;
using grapher.Models.Charts;
+using grapher.Models.Serialized;
using System;
-using System.Collections.Generic;
using System.Drawing;
-using System.Linq;
-using System.Security.Permissions;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
namespace grapher
{
public class AccelCharts
{
- public const int ChartSeparationVertical = 10;
-
- /// <summary> Needed to show full contents in form. Unsure why. </summary>
- public const int FormHeightPadding = 35;
+ #region Constructors
public AccelCharts(
Form form,
@@ -25,7 +17,8 @@ namespace grapher
ChartXY velocityChart,
ChartXY gainChart,
ToolStripMenuItem enableVelocityAndGain,
- ICollection<CheckBox> checkBoxesXY)
+ ToolStripMenuItem enableLastMouseMove,
+ Button writeButton)
{
Estimated = new EstimatedPoints();
EstimatedX = new EstimatedPoints();
@@ -37,7 +30,8 @@ namespace grapher
VelocityChart = velocityChart;
GainChart = gainChart;
EnableVelocityAndGain = enableVelocityAndGain;
- CheckBoxesXY = checkBoxesXY;
+ EnableLastValue = enableLastMouseMove;
+ WriteButton = writeButton;
SensitivityChart.SetPointBinds(Estimated.Sensitivity, EstimatedX.Sensitivity, EstimatedY.Sensitivity);
VelocityChart.SetPointBinds(Estimated.Velocity, EstimatedX.Velocity, EstimatedY.Velocity);
@@ -45,21 +39,28 @@ namespace grapher
SensitivityChart.SetTop(0);
VelocityChart.SetHeight(SensitivityChart.Height);
- VelocityChart.SetTop(SensitivityChart.Height + ChartSeparationVertical);
+ VelocityChart.SetTop(SensitivityChart.Height + Constants.ChartSeparationVertical);
GainChart.SetHeight(SensitivityChart.Height);
- GainChart.SetTop(VelocityChart.Top + VelocityChart.Height + ChartSeparationVertical);
+ GainChart.SetTop(VelocityChart.Top + VelocityChart.Height + Constants.ChartSeparationVertical);
Rectangle screenRectangle = ContaingForm.RectangleToScreen(ContaingForm.ClientRectangle);
FormBorderHeight = screenRectangle.Top - ContaingForm.Top;
EnableVelocityAndGain.Click += new System.EventHandler(OnEnableClick);
- EnableVelocityAndGain.CheckedChanged += new System.EventHandler(OnEnableCheckStateChange);
+ EnableVelocityAndGain.CheckedChanged += new System.EventHandler(OnEnableVelocityGainCheckStateChange);
+
+ EnableLastValue.CheckedChanged += new System.EventHandler(OnEnableLastMouseMoveCheckStateChange);
HideVelocityAndGain();
+ SensitivityChart.Show();
Combined = false;
ShowCombined();
}
+ #endregion Constructors
+
+ #region Properties
+
public Form ContaingForm { get; }
public ChartXY SensitivityChart { get; }
@@ -70,6 +71,10 @@ namespace grapher
public ToolStripMenuItem EnableVelocityAndGain { get; }
+ private ToolStripMenuItem EnableLastValue { get; }
+
+ private Button WriteButton { get; }
+
public AccelData AccelData { get; }
private EstimatedPoints Estimated { get; }
@@ -78,12 +83,14 @@ namespace grapher
private EstimatedPoints EstimatedY { get; }
- private ICollection<CheckBox> CheckBoxesXY { get; }
-
private bool Combined { get; set; }
private int FormBorderHeight { get; }
+ #endregion Properties
+
+ #region Methods
+
public void MakeDots(int x, int y, double timeInMs)
{
if (Combined)
@@ -96,11 +103,14 @@ namespace grapher
}
}
- public void DrawPoints()
+ public void DrawLastMovement()
{
- SensitivityChart.DrawPoints();
- VelocityChart.DrawPoints();
- GainChart.DrawPoints();
+ if (EnableLastValue.Checked)
+ {
+ SensitivityChart.DrawLastMovementValue();
+ VelocityChart.DrawLastMovementValue();
+ GainChart.DrawLastMovementValue();
+ }
}
public void Bind()
@@ -119,9 +129,9 @@ namespace grapher
}
}
- public void RefreshXY()
+ public void ShowActive(DriverSettings driverSettings)
{
- if (CheckBoxesXY.All(box => box.Checked))
+ if (driverSettings.combineMagnitudes)
{
ShowCombined();
}
@@ -131,12 +141,30 @@ namespace grapher
}
}
+ public void SetWidened()
+ {
+ SensitivityChart.SetWidened();
+ VelocityChart.SetWidened();
+ GainChart.SetWidened();
+ UpdateFormWidth();
+ AlignWriteButton();
+ }
+
+ public void SetNarrowed()
+ {
+ SensitivityChart.SetNarrowed();
+ VelocityChart.SetNarrowed();
+ GainChart.SetNarrowed();
+ UpdateFormWidth();
+ AlignWriteButton();
+ }
+
private void OnEnableClick(object sender, EventArgs e)
{
EnableVelocityAndGain.Checked = !EnableVelocityAndGain.Checked;
}
- private void OnEnableCheckStateChange(object sender, EventArgs e)
+ private void OnEnableVelocityGainCheckStateChange(object sender, EventArgs e)
{
if (EnableVelocityAndGain.Checked)
{
@@ -148,14 +176,24 @@ namespace grapher
}
}
+ private void OnEnableLastMouseMoveCheckStateChange(object sender, EventArgs e)
+ {
+ if (!EnableLastValue.Checked)
+ {
+ SensitivityChart.ClearLastValue();
+ VelocityChart.ClearLastValue();
+ GainChart.ClearLastValue();
+ }
+ }
+
private void ShowVelocityAndGain()
{
VelocityChart.Show();
GainChart.Show();
- ContaingForm.Height = SensitivityChart.Height +
- ChartSeparationVertical +
+ ContaingForm.Height = SensitivityChart.Height +
+ Constants.ChartSeparationVertical +
VelocityChart.Height +
- ChartSeparationVertical +
+ Constants.ChartSeparationVertical +
GainChart.Height +
FormBorderHeight;
}
@@ -199,5 +237,12 @@ namespace grapher
{
ContaingForm.Width = SensitivityChart.Left + SensitivityChart.Width;
}
+
+ private void AlignWriteButton()
+ {
+ WriteButton.Left = SensitivityChart.Left / 2 - WriteButton.Width / 2;
+ }
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Charts/ChartXY.cs b/grapher/Models/Charts/ChartXY.cs
index 81874a2..30be229 100644
--- a/grapher/Models/Charts/ChartXY.cs
+++ b/grapher/Models/Charts/ChartXY.cs
@@ -1,26 +1,11 @@
-using grapher.Models.Charts;
-using grapher.Models.Mouse;
-using System;
+using grapher.Models.Mouse;
using System.Collections;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
-using static grapher.AccelCharts;
namespace grapher
{
public class ChartXY
{
- #region Consts
-
- public const int ChartSeparationHorizontal = 10;
-
- #endregion Consts
-
#region Constructors
public ChartXY(Chart chartX, Chart chartY)
@@ -31,10 +16,16 @@ namespace grapher
ChartY.Top = ChartX.Top;
ChartY.Height = ChartX.Height;
ChartY.Width = ChartX.Width;
- ChartY.Left = ChartX.Left + ChartX.Width + ChartSeparationHorizontal;
+ ChartY.Left = ChartX.Left + ChartX.Width + Constants.ChartSeparationHorizontal;
SetupChart(ChartX);
SetupChart(ChartY);
+
+ Combined = false;
+ SetCombined();
+
+ Widened = false;
+ SetWidened();
}
#endregion Constructors
@@ -82,6 +73,10 @@ namespace grapher
public bool Combined { get; private set; }
+ public bool Widened { get; private set; }
+
+ public bool Visible { get; private set; }
+
private PointData CombinedPointData { get; set; }
private PointData XPointData { get; set; }
@@ -134,7 +129,7 @@ namespace grapher
YPointData = y;
}
- public void DrawPoints()
+ public void DrawLastMovementValue()
{
if(Combined)
{
@@ -147,6 +142,12 @@ namespace grapher
}
}
+ public void ClearLastValue()
+ {
+ ChartX.Series[1].Points.Clear();
+ ChartY.Series[1].Points.Clear();
+ }
+
public void Bind(IDictionary data)
{
ChartX.Series[0].Points.DataBindXY(data.Keys, data.Values);
@@ -171,7 +172,7 @@ namespace grapher
{
if (Combined)
{
- if (ChartX.Visible)
+ if (Visible)
{
ChartY.Show();
}
@@ -180,19 +181,56 @@ namespace grapher
}
}
+ public void SetWidened()
+ {
+ if (!Widened)
+ {
+ ChartX.Width = Constants.WideChartWidth;
+ ChartY.Width = Constants.WideChartWidth;
+
+ ChartX.Left = Constants.WideChartLeft;
+ ChartY.Left = ChartX.Left + ChartX.Width + Constants.ChartSeparationHorizontal;
+
+ Widened = true;
+ }
+ }
+
+ public void SetNarrowed()
+ {
+ if (Widened)
+ {
+ ChartX.Width = Constants.NarrowChartWidth;
+ ChartY.Width = Constants.NarrowChartWidth;
+
+ ChartX.Left = Constants.NarrowChartLeft;
+ ChartY.Left = ChartX.Left + ChartX.Width + Constants.ChartSeparationHorizontal;
+
+ Widened = false;
+ }
+ }
+
public void Hide()
{
- ChartX.Hide();
- ChartY.Hide();
+ if (Visible)
+ {
+ ChartX.Hide();
+ ChartY.Hide();
+ Visible = false;
+ }
}
public void Show()
{
- ChartX.Show();
-
- if (!Combined)
+ if (!Visible)
{
- ChartY.Show();
+ ChartX.Show();
+
+ if (!Combined)
+ {
+ ChartY.Show();
+ }
+
+ Visible = true;
}
}
diff --git a/grapher/Models/Charts/EstimatedPoints.cs b/grapher/Models/Charts/EstimatedPoints.cs
index fa0718b..f7ba3ce 100644
--- a/grapher/Models/Charts/EstimatedPoints.cs
+++ b/grapher/Models/Charts/EstimatedPoints.cs
@@ -1,14 +1,11 @@
using grapher.Models.Mouse;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Models.Charts
{
public class EstimatedPoints
{
+ #region Constructors
+
public EstimatedPoints()
{
Sensitivity = new PointData();
@@ -16,10 +13,16 @@ namespace grapher.Models.Charts
Gain = new PointData();
}
+ #endregion Constructors
+
+ #region Properties
+
public PointData Sensitivity { get; }
public PointData Velocity { get; }
public PointData Gain { get; }
+
+ #endregion Properties
}
}
diff --git a/grapher/Models/Fields/Field.cs b/grapher/Models/Fields/Field.cs
index 1810081..0d1813e 100644
--- a/grapher/Models/Fields/Field.cs
+++ b/grapher/Models/Fields/Field.cs
@@ -1,22 +1,12 @@
using System;
-using System.Collections.Generic;
using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher
{
public class Field
{
- #region Constants
-
- public const string DefaultFormatString = "0.#########";
-
- #endregion Constants
-
- #region Enums
+ #region Enumerations
public enum FieldState
{
@@ -27,8 +17,13 @@ namespace grapher
Unavailable,
}
- #endregion Enums
+ #endregion Enumerations
+
+ #region Fields
+
+ private double _data;
+ #endregion Fields
#region Constructors
@@ -36,11 +31,11 @@ namespace grapher
{
DefaultText = DecimalString(defaultData);
Box = box;
- Data = defaultData;
+ _data = defaultData;
DefaultData = defaultData;
State = FieldState.Undefined;
ContainingForm = containingForm;
- FormatString = DefaultFormatString;
+ FormatString = Constants.DefaultFieldFormatString;
box.KeyDown += new System.Windows.Forms.KeyEventHandler(KeyDown);
box.Leave += new System.EventHandler(FocusLeave);
@@ -55,8 +50,6 @@ namespace grapher
private Form ContainingForm { get; }
- public double Data { get; private set; }
-
public string FormatString { get; set; }
public string DefaultText { get; }
@@ -65,6 +58,68 @@ namespace grapher
public FieldState PreviousState { get; private set; }
+ public double Data {
+ get
+ {
+ if (Box.Visible)
+ {
+ return _data;
+ }
+ else
+ {
+ return DefaultData;
+ }
+ }
+ }
+
+ public int Top
+ {
+ get
+ {
+ return Box.Top;
+ }
+ set
+ {
+ Box.Top = value;
+ }
+ }
+
+ public int Height
+ {
+ get
+ {
+ return Box.Height;
+ }
+ set
+ {
+ Box.Height = value;
+ }
+ }
+
+ public int Left
+ {
+ get
+ {
+ return Box.Left;
+ }
+ set
+ {
+ Box.Left = value;
+ }
+ }
+
+ public int Width
+ {
+ get
+ {
+ return Box.Width;
+ }
+ set
+ {
+ Box.Width = value;
+ }
+ }
+
private double DefaultData { get; }
#endregion Properties
@@ -81,7 +136,7 @@ namespace grapher
PreviousState = FieldState.Default;
}
- Data = DefaultData;
+ _data = DefaultData;
Box.Text = DefaultText;
ContainingForm.ActiveControl = null;
}
@@ -118,7 +173,7 @@ namespace grapher
{
SetToEntered();
- Data = value;
+ _data = value;
Box.Text = DecimalString(Data);
}
@@ -197,7 +252,7 @@ namespace grapher
{
try
{
- Data = Convert.ToDouble(Box.Text);
+ _data = Convert.ToDouble(Box.Text);
}
catch
{
diff --git a/grapher/Models/Fields/FieldXY.cs b/grapher/Models/Fields/FieldXY.cs
index 609af9d..15e6800 100644
--- a/grapher/Models/Fields/FieldXY.cs
+++ b/grapher/Models/Fields/FieldXY.cs
@@ -1,38 +1,36 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher
{
public class FieldXY
{
- public const int DefaultSeparation = 4;
+ #region Constructors
- public const string ShortenedFormatString = "0.###";
-
- public FieldXY(TextBox xBox, TextBox yBox, CheckBox lockCheckBox, Form containingForm, double defaultData, AccelCharts accelCharts)
+ public FieldXY(TextBox xBox, TextBox yBox, CheckBox lockCheckBox, Form containingForm, double defaultData)
{
XField = new Field(xBox, containingForm, defaultData);
YField = new Field(yBox, containingForm, defaultData);
- YField.FormatString = ShortenedFormatString;
+ YField.FormatString = Constants.ShortenedFormatString;
LockCheckBox = lockCheckBox;
LockCheckBox.CheckedChanged += new System.EventHandler(CheckChanged);
- AccelCharts = accelCharts;
- XField.Box.Width = (YField.Box.Left + YField.Box.Width - XField.Box.Left - DefaultSeparation) / 2;
+ XField.Box.Width = (YField.Box.Left + YField.Box.Width - XField.Box.Left - Constants.DefaultFieldSeparation) / 2;
YField.Box.Width = XField.Box.Width;
DefaultWidthX = XField.Box.Width;
DefaultWidthY = YField.Box.Width;
- YField.Box.Left = XField.Box.Left + XField.Box.Width + DefaultSeparation;
+ YField.Box.Left = XField.Box.Left + XField.Box.Width + Constants.DefaultFieldSeparation;
CombinedWidth = DefaultWidthX + DefaultWidthY + YField.Box.Left - (XField.Box.Left + DefaultWidthX);
SetCombined();
}
+
+ #endregion Constructors
+
+ #region Properties
+
public double X
{
get => XField.Data;
@@ -59,7 +57,58 @@ namespace grapher
public Field YField { get; }
- private AccelCharts AccelCharts { get; }
+ public int CombinedWidth { get; }
+
+ public int Left {
+ get
+ {
+ return XField.Left;
+ }
+ set
+ {
+ }
+ }
+
+ public int Width
+ {
+ get
+ {
+ return CombinedWidth;
+ }
+ set
+ {
+ }
+ }
+
+ public int Top
+ {
+ get
+ {
+ return XField.Top;
+ }
+ set
+ {
+ }
+ }
+
+ public int Height
+ {
+ get
+ {
+ return XField.Height;
+ }
+ set
+ {
+ }
+ }
+
+ public bool Visible
+ {
+ get
+ {
+ return XField.Box.Visible;
+ }
+ }
private bool Combined { get; set; }
@@ -67,7 +116,10 @@ namespace grapher
private int DefaultWidthY { get; }
- private int CombinedWidth { get; }
+
+ #endregion Properties
+
+ #region Methods
private void CheckChanged(object sender, EventArgs e)
{
@@ -79,8 +131,6 @@ namespace grapher
{
SetSeparate();
}
-
- AccelCharts.RefreshXY();
}
public void SetCombined()
@@ -89,7 +139,7 @@ namespace grapher
YField.SetToUnavailable();
YField.Box.Hide();
XField.Box.Width = CombinedWidth;
- XField.FormatString = Field.DefaultFormatString;
+ XField.FormatString = Constants.DefaultFieldFormatString;
}
public void SetSeparate()
@@ -99,7 +149,7 @@ namespace grapher
XField.Box.Width = DefaultWidthX;
YField.Box.Width = DefaultWidthY;
- XField.FormatString = ShortenedFormatString;
+ XField.FormatString = Constants.ShortenedFormatString;
if (XField.State == Field.FieldState.Default)
{
@@ -131,5 +181,7 @@ namespace grapher
XField.Box.Hide();
YField.Box.Hide();
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Mouse/MouseWatcher.cs b/grapher/Models/Mouse/MouseWatcher.cs
index fea4e2d..405110e 100644
--- a/grapher/Models/Mouse/MouseWatcher.cs
+++ b/grapher/Models/Mouse/MouseWatcher.cs
@@ -1,16 +1,12 @@
using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher.Models.Mouse
{
public class MouseWatcher
{
+ #region External
/// <summary>
/// Enumeration containing HID usage page flags.
/// </summary>
@@ -677,6 +673,10 @@ namespace grapher.Models.Mouse
[DllImport("user32.dll")]
public static extern int GetRawInputData(IntPtr hRawInput, RawInputCommand uiCommand, out RawInput pData, ref int pcbSize, int cbSizeHeader);
+ #endregion External
+
+ #region Constructors
+
public MouseWatcher(Form containingForm, Label display, AccelCharts accelCharts)
{
ContainingForm = containingForm;
@@ -695,6 +695,10 @@ namespace grapher.Models.Mouse
PollTime = 1;
}
+ #endregion Constructors
+
+ #region Properties
+
private Form ContainingForm { get; }
private Label Display { get; }
@@ -703,6 +707,10 @@ namespace grapher.Models.Mouse
private double PollTime { get; }
+ #endregion Properties
+
+ #region Methods
+
public void OnMouseMove(int x, int y, double timeInMs)
{
Display.Text = $"Last (x, y): ({x}, {y})";
@@ -723,5 +731,7 @@ namespace grapher.Models.Mouse
}
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Mouse/PointData.cs b/grapher/Models/Mouse/PointData.cs
index 12a6e73..374c52e 100644
--- a/grapher/Models/Mouse/PointData.cs
+++ b/grapher/Models/Mouse/PointData.cs
@@ -1,13 +1,11 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace grapher.Models.Mouse
{
public class PointData
{
+ #region Constructors
+
public PointData()
{
Lock = new Object();
@@ -15,6 +13,10 @@ namespace grapher.Models.Mouse
Y = new double[] { 0 };
}
+ #endregion Constructors
+
+ #region Properties
+
public Object Lock { get; }
private double[] X { get; set; }
@@ -29,6 +31,10 @@ namespace grapher.Models.Mouse
}
}
+ #endregion Properties
+
+ #region Methods
+
public void Get(out double[] x, out double[] y)
{
lock(Lock)
@@ -37,5 +43,7 @@ namespace grapher.Models.Mouse
y = Y;
}
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Options/AccelOptionSet.cs b/grapher/Models/Options/AccelOptionSet.cs
new file mode 100644
index 0000000..bc0d368
--- /dev/null
+++ b/grapher/Models/Options/AccelOptionSet.cs
@@ -0,0 +1,117 @@
+using grapher.Models.Serialized;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace grapher.Models.Options
+{
+ public class AccelOptionSet
+ {
+ public AccelOptionSet(
+ Label title,
+ Label activeValuesTitle,
+ int topAnchor,
+ AccelTypeOptions accelTypeOptions)
+ {
+ OptionsTitle = title;
+ ActiveValuesTitle = activeValuesTitle;
+ TopAnchor = topAnchor;
+ Options = accelTypeOptions;
+
+ ActiveValuesTitle.AutoSize = false;
+ ActiveValuesTitle.TextAlign = ContentAlignment.MiddleCenter;
+
+ Options.ShowFull();
+
+ OptionsTitle.Top = TopAnchor;
+ IsTitleMode = true;
+ SetRegularMode();
+ }
+
+ public int TopAnchor { get; }
+
+ public Label OptionsTitle { get; }
+
+ public Label ActiveValuesTitle { get; }
+
+ public AccelTypeOptions Options { get; }
+
+
+ public bool IsTitleMode { get; private set; }
+
+ public void SetRegularMode()
+ {
+ if (IsTitleMode)
+ {
+ IsTitleMode = false;
+
+ HideTitle();
+ Options.ShowFull();
+ }
+ }
+
+ public void SetTitleMode(string title)
+ {
+ OptionsTitle.Text = title;
+
+ if (!IsTitleMode)
+ {
+ IsTitleMode = true;
+
+ Options.ShowShortened();
+ DisplayTitle();
+ }
+ }
+
+ public void Hide()
+ {
+ OptionsTitle.Hide();
+ ActiveValuesTitle.Hide();
+ Options.Hide();
+ }
+
+ public void Show()
+ {
+ if (IsTitleMode)
+ {
+ OptionsTitle.Show();
+ }
+
+ ActiveValuesTitle.Show();
+ Options.Show();
+ }
+
+ public void DisplayTitle()
+ {
+ OptionsTitle.Show();
+
+ Options.Top = OptionsTitle.Top + OptionsTitle.Height + Constants.OptionVerticalSeperation;
+ }
+
+ public void HideTitle()
+ {
+ OptionsTitle.Hide();
+
+ Options.Top = TopAnchor;
+ }
+
+ public void SetArgs(ref AccelArgs args)
+ {
+ Options.SetArgs(ref args);
+ }
+
+ public AccelArgs GenerateArgs()
+ {
+ return Options.GenerateArgs();
+ }
+
+ public void SetActiveValues(int mode, AccelArgs args)
+ {
+ Options.SetActiveValues(mode, args);
+ }
+
+ public void AlignActiveValues()
+ {
+ Options.AlignActiveValues();
+ }
+ }
+}
diff --git a/grapher/Models/Options/AccelOptions.cs b/grapher/Models/Options/AccelOptions.cs
deleted file mode 100644
index 6b98274..0000000
--- a/grapher/Models/Options/AccelOptions.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using grapher.Layouts;
-using grapher.Models.Options;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-namespace grapher
-{
- public class AccelOptions
- {
- public const int PossibleOptionsCount = 4;
- public const int PossibleOptionsXYCount = 2;
-
- public static readonly Dictionary<string, LayoutBase> AccelerationTypes = new List<LayoutBase>
- {
- new LinearLayout(),
- new ClassicLayout(),
- new NaturalLayout(),
- new LogLayout(),
- new SigmoidLayout(),
- new PowerLayout(),
- new NaturalGainLayout(),
- new SigmoidGainLayout(),
- new OffLayout()
- }.ToDictionary(k => k.Name);
-
- public AccelOptions(
- ComboBox accelDropdown,
- Option[] options,
- OptionXY[] optionsXY,
- Button writeButton,
- ActiveValueLabel activeValueLabel)
- {
- AccelDropdown = accelDropdown;
- AccelDropdown.Items.Clear();
- AccelDropdown.Items.AddRange(AccelerationTypes.Keys.ToArray());
- AccelDropdown.SelectedIndexChanged += new System.EventHandler(OnIndexChanged);
-
- if (options.Length > PossibleOptionsCount)
- {
- throw new Exception("Layout given too many options.");
- }
-
- if (optionsXY.Length > PossibleOptionsXYCount)
- {
- throw new Exception("Layout given too many options.");
- }
-
- Options = options;
- OptionsXY = optionsXY;
- WriteButton = writeButton;
- ActiveValueLabel = activeValueLabel;
-
- Layout("Off");
- }
-
- public Button WriteButton { get; }
-
- public ComboBox AccelDropdown { get; }
-
- public int AccelerationIndex { get; private set; }
-
- public ActiveValueLabel ActiveValueLabel { get; }
-
- public Option[] Options { get; }
-
- public OptionXY[] OptionsXY { get; }
-
- public void SetActiveValue(int index)
- {
- var name = AccelerationTypes.Where(t => t.Value.Index == index).FirstOrDefault().Value.Name;
- ActiveValueLabel.SetValue(name);
- }
-
- private void OnIndexChanged(object sender, EventArgs e)
- {
- var accelerationTypeString = AccelDropdown.SelectedItem.ToString();
- Layout(accelerationTypeString);
- }
-
- private void Layout(string type)
- {
- var accelerationType = AccelerationTypes[type];
- AccelerationIndex = accelerationType.Index;
- accelerationType.Layout(Options, OptionsXY, WriteButton);
- }
- }
-}
diff --git a/grapher/Models/Options/AccelTypeOptions.cs b/grapher/Models/Options/AccelTypeOptions.cs
new file mode 100644
index 0000000..14c2019
--- /dev/null
+++ b/grapher/Models/Options/AccelTypeOptions.cs
@@ -0,0 +1,281 @@
+using grapher.Layouts;
+using grapher.Models.Options;
+using grapher.Models.Serialized;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace grapher
+{
+ public class AccelTypeOptions : OptionBase
+ {
+ #region Fields
+
+ public static readonly Dictionary<string, LayoutBase> AccelerationTypes = new List<LayoutBase>
+ {
+ new LinearLayout(),
+ new ClassicLayout(),
+ new NaturalLayout(),
+ new PowerLayout(),
+ new NaturalGainLayout(),
+ new SigmoidGainLayout(),
+ new OffLayout()
+ }.ToDictionary(k => k.Name);
+
+ #endregion Fields
+
+ #region Constructors
+
+ public AccelTypeOptions(
+ ComboBox accelDropdown,
+ Option acceleration,
+ CapOptions cap,
+ Option weight,
+ OffsetOptions offset,
+ Option limitOrExponent,
+ Option midpoint,
+ Button writeButton,
+ ActiveValueLabel accelTypeActiveValue)
+ {
+ AccelDropdown = accelDropdown;
+ AccelDropdown.Items.Clear();
+ AccelDropdown.Items.AddRange(AccelerationTypes.Keys.ToArray());
+ AccelDropdown.SelectedIndexChanged += new System.EventHandler(OnIndexChanged);
+
+ Acceleration = acceleration;
+ Cap = cap;
+ Weight = weight;
+ Offset = offset;
+ LimitOrExponent = limitOrExponent;
+ Midpoint = midpoint;
+ WriteButton = writeButton;
+ AccelTypeActiveValue = accelTypeActiveValue;
+
+ AccelTypeActiveValue.Left = AccelDropdown.Left + AccelDropdown.Width;
+ AccelTypeActiveValue.Height = AccelDropdown.Height;
+
+ Layout("Off");
+ ShowingDefault = true;
+ }
+
+ #endregion Constructors
+
+ #region Properties
+
+ public Button WriteButton { get; }
+
+ public ComboBox AccelDropdown { get; }
+
+ public int AccelerationIndex
+ {
+ get
+ {
+ return AccelerationType.Index;
+ }
+ }
+
+ public LayoutBase AccelerationType { get; private set; }
+
+ public ActiveValueLabel AccelTypeActiveValue { get; }
+
+ public Option Acceleration { get; }
+
+ public CapOptions Cap { get; }
+
+ public Option Weight { get; }
+
+ public OffsetOptions Offset { get; }
+
+ public Option LimitOrExponent { get; }
+
+ public Option Midpoint { get; }
+
+ public override int Top
+ {
+ get
+ {
+ return AccelDropdown.Top;
+ }
+ set
+ {
+ AccelDropdown.Top = value;
+ AccelTypeActiveValue.Top = value;
+ Layout(value + AccelDropdown.Height + Constants.OptionVerticalSeperation);
+ }
+ }
+
+ public override int Height
+ {
+ get
+ {
+ return AccelDropdown.Height;
+ }
+ }
+
+ public override int Left
+ {
+ get
+ {
+ return AccelDropdown.Left;
+ }
+ set
+ {
+ AccelDropdown.Left = value;
+ }
+ }
+
+ public override int Width
+ {
+ get
+ {
+ return AccelDropdown.Width;
+ }
+ set
+ {
+ AccelDropdown.Width = value;
+ }
+ }
+
+ public override bool Visible
+ {
+ get
+ {
+ return AccelDropdown.Visible;
+ }
+ }
+
+ private bool ShowingDefault { get; set; }
+
+ #endregion Properties
+
+ #region Methods
+
+ public override void Hide()
+ {
+ AccelDropdown.Hide();
+ AccelTypeActiveValue.Hide();
+
+ Acceleration.Hide();
+ Cap.Hide();
+ Weight.Hide();
+ Offset.Hide();
+ LimitOrExponent.Hide();
+ Midpoint.Hide();
+ }
+
+ public void Show()
+ {
+ AccelDropdown.Show();
+ AccelTypeActiveValue.Show();
+ Layout();
+ }
+
+ public override void Show(string name)
+ {
+ Show();
+ }
+
+ public void SetActiveValues(int index, AccelArgs args)
+ {
+ var name = AccelerationTypes.Where(t => t.Value.Index == index).FirstOrDefault().Value.Name;
+ AccelTypeActiveValue.SetValue(name);
+
+ Weight.SetActiveValue(args.weight);
+ Cap.SetActiveValues(args.gainCap, args.scaleCap, args.gainCap > 0);
+ Offset.SetActiveValue(args.offset, args.legacy_offset);
+ Acceleration.SetActiveValue(args.accel);
+ LimitOrExponent.SetActiveValue(args.exponent);
+ Midpoint.SetActiveValue(args.midpoint);
+ }
+
+ public void ShowFull()
+ {
+ if (ShowingDefault)
+ {
+ AccelDropdown.Text = Constants.AccelDropDownDefaultFullText;
+ }
+
+ Left = Acceleration.Left + Constants.DropDownLeftSeparation;
+ Width = Acceleration.Width - Constants.DropDownLeftSeparation;
+ }
+
+ public void ShowShortened()
+ {
+ if (ShowingDefault)
+ {
+ AccelDropdown.Text = Constants.AccelDropDownDefaultShortText;
+ }
+
+ Left = Acceleration.Field.Left;
+ Width = Acceleration.Field.Width;
+ }
+
+ public void SetArgs(ref AccelArgs args)
+ {
+ args.accel = Acceleration.Field.Data;
+ args.rate = Acceleration.Field.Data;
+ args.powerScale = Acceleration.Field.Data;
+ args.gainCap = Cap.VelocityGainCap;
+ args.scaleCap = Cap.SensitivityCap;
+ args.limit = LimitOrExponent.Field.Data;
+ args.exponent = LimitOrExponent.Field.Data;
+ args.powerExponent = LimitOrExponent.Field.Data;
+ args.offset = Offset.Offset;
+ args.legacy_offset = Offset.LegacyOffset;
+ args.midpoint = Midpoint.Field.Data;
+ args.weight = Weight.Field.Data;
+ }
+
+ public AccelArgs GenerateArgs()
+ {
+ AccelArgs args = new AccelArgs();
+ SetArgs(ref args);
+ return args;
+ }
+
+ public override void AlignActiveValues()
+ {
+ AccelTypeActiveValue.Align();
+ Acceleration.AlignActiveValues();
+ Cap.AlignActiveValues();
+ Offset.AlignActiveValues();
+ Weight.AlignActiveValues();
+ LimitOrExponent.AlignActiveValues();
+ Midpoint.AlignActiveValues();
+ }
+
+ private void OnIndexChanged(object sender, EventArgs e)
+ {
+ var accelerationTypeString = AccelDropdown.SelectedItem.ToString();
+ Layout(accelerationTypeString, Beneath);
+ ShowingDefault = false;
+ }
+
+ private void Layout(string type, int top = -1)
+ {
+ AccelerationType = AccelerationTypes[type];
+ Layout(top);
+ }
+
+ private void Layout(int top = -1)
+ {
+ if (top < 0)
+ {
+ top = Acceleration.Top;
+ }
+
+ AccelerationType.Layout(
+ Acceleration,
+ Cap,
+ Weight,
+ Offset,
+ LimitOrExponent,
+ Midpoint,
+ WriteButton,
+ top);
+ }
+
+ #endregion Methods
+ }
+}
diff --git a/grapher/Models/Options/ActiveValueLabel.cs b/grapher/Models/Options/ActiveValueLabel.cs
index 138775a..18a4400 100644
--- a/grapher/Models/Options/ActiveValueLabel.cs
+++ b/grapher/Models/Options/ActiveValueLabel.cs
@@ -1,34 +1,42 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Drawing;
using System.Windows.Forms;
namespace grapher.Models.Options
{
public class ActiveValueLabel
{
- public const string DefaultFormatString = "0.######";
- public static readonly Color ActiveValueFontColor = Color.FromArgb(255, 65, 65, 65);
+ #region Constants
+
+
+ #endregion Constants
+
+ #region Fields
private string _prefix;
private string _value;
+ #endregion Fields
+
+ #region Constructors
+
public ActiveValueLabel(Label valueLabel, Label centeringLabel)
{
ValueLabel = valueLabel;
- ValueLabel.ForeColor = ActiveValueFontColor;
- Left = centeringLabel.Left;
- Width = centeringLabel.Width;
ValueLabel.AutoSize = false;
ValueLabel.TextAlign = ContentAlignment.MiddleCenter;
+ ValueLabel.ForeColor = Constants.ActiveValueFontColor;
- FormatString = DefaultFormatString;
+ CenteringLabel = centeringLabel;
+ Align();
+
+ FormatString = Constants.DefaultActiveValueFormatString;
Prefix = string.Empty;
}
+ #endregion Constructors
+
+ #region Properties
+
public Label ValueLabel { get; }
public string FormatString { get; set; }
@@ -79,6 +87,37 @@ namespace grapher.Models.Options
}
}
+ public int Top
+ {
+ get
+ {
+ return ValueLabel.Top;
+ }
+ set
+ {
+ ValueLabel.Top = value;
+ }
+ }
+
+ public int Height
+ {
+ get
+ {
+ return ValueLabel.Height;
+ }
+
+ set
+ {
+ ValueLabel.Height = value;
+ }
+ }
+
+ public Label CenteringLabel { get; }
+
+ #endregion Properties
+
+ #region Methods
+
public void Hide()
{
ValueLabel.Hide();
@@ -103,5 +142,13 @@ namespace grapher.Models.Options
{
ValueLabel.Text = string.IsNullOrWhiteSpace(Prefix) ? Value: $"{Prefix}: {Value}";
}
+
+ public void Align()
+ {
+ Left = CenteringLabel.Left;
+ Width = CenteringLabel.Width;
+ }
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Options/ActiveValueLabelXY.cs b/grapher/Models/Options/ActiveValueLabelXY.cs
index 12506e9..9498c66 100644
--- a/grapher/Models/Options/ActiveValueLabelXY.cs
+++ b/grapher/Models/Options/ActiveValueLabelXY.cs
@@ -1,15 +1,13 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace grapher.Models.Options
+namespace grapher.Models.Options
{
public class ActiveValueLabelXY
{
- public const int ActiveLabelXYSeparation = 2;
- public const string ShortenedFormatString = "0.###";
+ #region Constants
+
+
+ #endregion Constants
+
+ #region Constructors
public ActiveValueLabelXY(
ActiveValueLabel x,
@@ -18,26 +16,57 @@ namespace grapher.Models.Options
X = x;
Y = y;
- FullWidth = x.Width;
- ShortenedWidth = (FullWidth - ActiveLabelXYSeparation) / 2;
-
- Y.Left = X.Left + ShortenedWidth + ActiveLabelXYSeparation;
+ Align(x.Width);
Y.Width = ShortenedWidth;
- Y.FormatString = ShortenedFormatString;
+ Y.FormatString = Constants.ShortenedFormatString;
Combined = false;
SetCombined();
}
+ #endregion Constructors
+
+ #region Properties
+
public ActiveValueLabel X { get; }
public ActiveValueLabel Y { get; }
public bool Combined { get; private set; }
- private int FullWidth { get; }
+ public int Left
+ {
+ get
+ {
+ return X.Left;
+ }
+ set
+ {
+ X.Left = value;
+ SetYLeft();
+ }
+ }
+
+ public int Height
+ {
+ get
+ {
+ return X.Height;
+ }
+ set
+ {
+ X.Height = value;
+ Y.Height = value;
+ }
+ }
+
+ private int FullWidth { get; set; }
+
+ private int ShortenedWidth { get; set; }
- private int ShortenedWidth { get; }
+ #endregion Properties
+
+ #region Methods
public void SetValues(double x, double y)
{
@@ -58,7 +87,7 @@ namespace grapher.Models.Options
{
if (!Combined)
{
- X.FormatString = ActiveValueLabel.DefaultFormatString;
+ X.FormatString = Constants.DefaultActiveValueFormatString;
X.Width = FullWidth;
X.Prefix = string.Empty;
Y.Hide();
@@ -71,7 +100,7 @@ namespace grapher.Models.Options
{
if (Combined)
{
- X.FormatString = ShortenedFormatString;
+ X.FormatString = Constants.ShortenedFormatString;
X.Width = ShortenedWidth;
X.Prefix = "X";
Y.Prefix = "Y";
@@ -80,5 +109,35 @@ namespace grapher.Models.Options
Combined = false;
}
+
+ public void AlignActiveValues()
+ {
+ Align(X.CenteringLabel.Width);
+
+ if (Combined)
+ {
+ X.Width = FullWidth;
+ }
+ else
+ {
+ X.Width = ShortenedWidth;
+ }
+ }
+
+ private void Align (int width)
+ {
+ FullWidth = width;
+ ShortenedWidth = (FullWidth - Constants.ActiveLabelXYSeparation) / 2;
+
+ SetYLeft();
+ Y.Width = ShortenedWidth;
+ }
+
+ private void SetYLeft()
+ {
+ Y.Left = X.Left + ShortenedWidth + Constants.ActiveLabelXYSeparation;
+ }
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Options/ApplyOptions.cs b/grapher/Models/Options/ApplyOptions.cs
new file mode 100644
index 0000000..241fe50
--- /dev/null
+++ b/grapher/Models/Options/ApplyOptions.cs
@@ -0,0 +1,255 @@
+using grapher.Models.Serialized;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace grapher.Models.Options
+{
+ public class ApplyOptions
+ {
+ #region Constructors
+
+ public ApplyOptions(
+ ToolStripMenuItem wholeVectorMenuItem,
+ ToolStripMenuItem byComponentMenuItem,
+ CheckBox byComponentVectorXYLock,
+ AccelOptionSet optionSetX,
+ AccelOptionSet optionSetY,
+ OptionXY sensitivity,
+ Option rotation,
+ Label lockXYLabel,
+ AccelCharts accelCharts)
+ {
+ WholeVectorMenuItem = wholeVectorMenuItem;
+ ByComponentVectorMenuItem = byComponentMenuItem;
+
+ WholeVectorMenuItem.Click += new System.EventHandler(OnWholeClicked);
+ ByComponentVectorMenuItem.Click += new System.EventHandler(OnByComponentClicked);
+
+ WholeVectorMenuItem.CheckedChanged += new System.EventHandler(OnWholeCheckedChange);
+ ByComponentVectorMenuItem.CheckedChanged += new System.EventHandler(OnByComponentCheckedChange);
+
+ ByComponentVectorXYLock = byComponentVectorXYLock;
+ OptionSetX = optionSetX;
+ OptionSetY = optionSetY;
+ Sensitivity = sensitivity;
+ Rotation = rotation;
+ LockXYLabel = lockXYLabel;
+ AccelCharts = accelCharts;
+
+ LockXYLabel.AutoSize = false;
+ LockXYLabel.TextAlign = ContentAlignment.MiddleCenter;
+
+ ByComponentVectorXYLock.CheckedChanged += new System.EventHandler(OnByComponentXYLockChecked);
+ ByComponentVectorXYLock.Checked = true;
+
+ Rotation.SnapTo(Sensitivity);
+
+ EnableWholeApplication();
+ }
+
+ #endregion Constructors
+
+ #region Properties
+
+ public ToolStripMenuItem WholeVectorMenuItem { get; }
+
+ public ToolStripMenuItem ByComponentVectorMenuItem { get; }
+
+ public CheckBox ByComponentVectorXYLock { get; }
+
+ public AccelOptionSet OptionSetX { get; }
+
+ public AccelOptionSet OptionSetY { get; }
+
+ public OptionXY Sensitivity { get; }
+
+ public Option Rotation { get; }
+
+ public AccelCharts AccelCharts { get; }
+
+ public Label ActiveValueTitleY { get; }
+
+ public Label LockXYLabel { get; }
+
+ public bool IsWhole { get; private set; }
+
+ #endregion Properties
+
+ #region Methods
+
+ public Vec2<AccelMode> GetModes()
+ {
+ var xMode = (AccelMode)OptionSetX.Options.AccelerationIndex;
+
+ return new Vec2<AccelMode>
+ {
+ x = xMode,
+ y = ByComponentVectorXYLock.Checked ? xMode : (AccelMode)OptionSetY.Options.AccelerationIndex
+ };
+ }
+
+ public Vec2<AccelArgs> GetArgs()
+ {
+ var xArgs = OptionSetX.GenerateArgs();
+
+ return new Vec2<AccelArgs>
+ {
+ x = xArgs,
+ y = ByComponentVectorXYLock.Checked ? xArgs : OptionSetY.GenerateArgs()
+ };
+
+ }
+
+ public void SetActiveValues(
+ double xSens,
+ double ySens,
+ double rotation,
+ int xMode,
+ int yMode,
+ AccelArgs xArgs,
+ AccelArgs yArgs,
+ bool isWhole)
+ {
+ Sensitivity.SetActiveValues(xSens, ySens);
+ Rotation.SetActiveValue(rotation);
+ OptionSetX.SetActiveValues(xMode, xArgs);
+ OptionSetY.SetActiveValues(yMode, yArgs);
+ WholeVectorMenuItem.Checked = isWhole;
+ ByComponentVectorMenuItem.Checked = !isWhole;
+ }
+
+ public void SetActiveValues(DriverSettings settings)
+ {
+ SetActiveValues(
+ settings.sensitivity.x,
+ settings.sensitivity.x,
+ settings.rotation,
+ (int)settings.modes.x,
+ (int)settings.modes.y,
+ settings.args.x,
+ settings.args.y,
+ settings.combineMagnitudes);
+ }
+
+ public void OnWholeClicked(object sender, EventArgs e)
+ {
+ if (!WholeVectorMenuItem.Checked)
+ {
+ WholeVectorMenuItem.Checked = true;
+ ByComponentVectorMenuItem.Checked = false;
+ }
+ }
+
+ public void OnByComponentClicked(object sender, EventArgs e)
+ {
+ if (!ByComponentVectorMenuItem.Checked)
+ {
+ WholeVectorMenuItem.Checked = false;
+ ByComponentVectorMenuItem.Checked = true;
+ }
+ }
+
+ public void OnWholeCheckedChange(object sender, EventArgs e)
+ {
+ if (WholeVectorMenuItem.Checked)
+ {
+ EnableWholeApplication();
+ }
+ }
+
+ public void OnByComponentCheckedChange(object sender, EventArgs e)
+ {
+ if (ByComponentVectorMenuItem.Checked)
+ {
+ EnableByComponentApplication();
+ }
+ }
+
+ public void ShowWholeSet()
+ {
+ OptionSetX.SetRegularMode();
+ OptionSetY.Hide();
+ AccelCharts.SetWidened();
+ SetActiveTitlesWhole();
+ }
+
+ public void ShowByComponentAsOneSet()
+ {
+ OptionSetX.SetTitleMode("X = Y");
+ OptionSetY.Hide();
+ AccelCharts.SetWidened();
+ SetActiveTitlesByComponents();
+ }
+
+ public void ShowByComponentAsTwoSets()
+ {
+ OptionSetX.SetTitleMode("X");
+ OptionSetY.SetTitleMode("Y");
+ OptionSetY.Show();
+ AccelCharts.SetNarrowed();
+ }
+
+ public void ShowByComponentSet()
+ {
+ if (ByComponentVectorXYLock.Checked)
+ {
+ ShowByComponentAsOneSet();
+ }
+ else
+ {
+ ShowByComponentAsTwoSets();
+ }
+ }
+
+ private void OnByComponentXYLockChecked(object sender, EventArgs e)
+ {
+ if (!IsWhole)
+ {
+ ShowByComponentSet();
+ }
+ }
+
+ public void EnableWholeApplication()
+ {
+ IsWhole = true;
+ ByComponentVectorXYLock.Hide();
+ ShowWholeSet();
+ }
+
+ public void EnableByComponentApplication()
+ {
+ IsWhole = false;
+ ByComponentVectorXYLock.Show();
+ ShowByComponentSet();
+ }
+
+ private void SetActiveTitlesWhole()
+ {
+ OptionSetX.ActiveValuesTitle.Left = OptionSetX.Options.Left + OptionSetX.Options.Width;
+ LockXYLabel.Width = (AccelCharts.SensitivityChart.Left - OptionSetX.ActiveValuesTitle.Left) / 2;
+ OptionSetX.ActiveValuesTitle.Width = LockXYLabel.Width;
+ LockXYLabel.Left = OptionSetX.ActiveValuesTitle.Left + OptionSetX.ActiveValuesTitle.Width;
+ Sensitivity.Fields.LockCheckBox.Left = LockXYLabel.Left + LockXYLabel.Width / 2 - Sensitivity.Fields.LockCheckBox.Width / 2;
+ ByComponentVectorXYLock.Left = Sensitivity.Fields.LockCheckBox.Left;
+ AlignActiveValues();
+ }
+
+ private void SetActiveTitlesByComponents()
+ {
+ OptionSetY.ActiveValuesTitle.Left = OptionSetY.Options.Left + OptionSetY.Options.Width;
+ OptionSetY.ActiveValuesTitle.Width = Constants.NarrowChartLeft - OptionSetY.ActiveValuesTitle.Left;
+ AlignActiveValues();
+ }
+
+ private void AlignActiveValues()
+ {
+ OptionSetX.AlignActiveValues();
+ OptionSetY.AlignActiveValues();
+ Sensitivity.AlignActiveValues();
+ Rotation.AlignActiveValues();
+ }
+
+ #endregion Methods
+ }
+}
diff --git a/grapher/Models/Options/CapOptions.cs b/grapher/Models/Options/CapOptions.cs
index 87bac88..5e47d7b 100644
--- a/grapher/Models/Options/CapOptions.cs
+++ b/grapher/Models/Options/CapOptions.cs
@@ -1,29 +1,27 @@
using grapher.Models.Options;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher
{
- public class CapOptions
+ public class CapOptions : OptionBase
{
+ #region Constants
- public const string GainCapFormatString = "0.##";
+
+ #endregion Constants
+
+ #region Constructors
public CapOptions(
ToolStripMenuItem velocityGainCapCheck,
ToolStripMenuItem legacyCapCheck,
- OptionXY capOption,
- OptionXY weightOption)
+ Option capOption)
{
VelocityGainCapCheck = velocityGainCapCheck;
LegacyCapCheck = legacyCapCheck;
CapOption = capOption;
- WeightOption = weightOption;
LegacyCapCheck.Click += new System.EventHandler(OnSensitivityCapCheckClick);
VelocityGainCapCheck.Click += new System.EventHandler(OnVelocityGainCapCheckClick);
@@ -34,20 +32,24 @@ namespace grapher
EnableVelocityGainCap();
}
+ #endregion Constructors
+
+ #region Properties
+
public ToolStripMenuItem LegacyCapCheck { get; }
public ToolStripMenuItem VelocityGainCapCheck { get; }
- public OptionXY CapOption { get; }
+ public Option CapOption { get; }
- public OptionXY WeightOption { get; }
+ public bool IsSensitivityGain { get; private set; }
- public double SensitivityCapX {
+ public double SensitivityCap {
get
{
if (IsSensitivityGain)
{
- return CapOption.Fields.X;
+ return CapOption.Field.Data;
}
else
{
@@ -56,52 +58,122 @@ namespace grapher
}
}
- public double SensitivityCapY {
+ public double VelocityGainCap {
get
{
if (IsSensitivityGain)
{
- return CapOption.Fields.Y;
+ return 0;
}
else
{
- return 0;
+ return CapOption.Field.Data;
}
}
}
- public double VelocityGainCap {
+ public override int Top
+ {
+ get
+ {
+ return CapOption.Top;
+ }
+ set
+ {
+ CapOption.Top = value;
+ }
+ }
+
+ public override int Height
+ {
get
{
- if (IsSensitivityGain)
- {
- return 0;
- }
- else
- {
- return CapOption.Fields.X;
- }
+ return CapOption.Height;
}
}
- public bool IsSensitivityGain { get; private set; }
+ public override int Left
+ {
+ get
+ {
+ return CapOption.Left;
+ }
+ set
+ {
+ CapOption.Left = value;
+ }
+ }
+
+ public override int Width
+ {
+ get
+ {
+ return CapOption.Width;
+ }
+ set
+ {
+ CapOption.Width = value;
+ }
+ }
- public void SetActiveValues(double gainCap, double sensCapX, double sensCapY, bool capGainEnabled)
+ public override bool Visible
+ {
+ get
+ {
+ return CapOption.Visible;
+ }
+ }
+
+ #endregion Properties
+
+ #region Methods
+
+ public override void Hide()
+ {
+ CapOption.Hide();
+ }
+
+ public void Show()
+ {
+ CapOption.Show();
+ }
+
+ public override void Show(string name)
+ {
+ CapOption.Show(name);
+ }
+
+ public void SnapTo(Option option)
+ {
+ Top = option.Top + option.Height + Constants.OptionVerticalSeperation;
+ }
+
+
+ public void SetActiveValues(double gainCap, double sensCap, bool capGainEnabled)
{
if (capGainEnabled)
{
- CapOption.ActiveValueLabels.X.FormatString = GainCapFormatString;
- CapOption.ActiveValueLabels.X.Prefix = "Gain";
- CapOption.SetActiveValues(gainCap, gainCap);
+ CapOption.ActiveValueLabel.FormatString = Constants.GainCapFormatString;
+ CapOption.ActiveValueLabel.Prefix = "Gain";
+ CapOption.SetActiveValue(gainCap);
+ LegacyCapCheck.Checked = true;
+ VelocityGainCapCheck.Checked = false;
}
else
{
- CapOption.ActiveValueLabels.X.FormatString = ActiveValueLabel.DefaultFormatString;
- CapOption.ActiveValueLabels.X.Prefix = string.Empty;
- CapOption.SetActiveValues(sensCapX, sensCapY);
+ CapOption.ActiveValueLabel.FormatString = Constants.DefaultActiveValueFormatString;
+ CapOption.ActiveValueLabel.Prefix = string.Empty;
+ CapOption.SetActiveValue(sensCap);
+ LegacyCapCheck.Checked = false;
+ VelocityGainCapCheck.Checked = true;
}
}
+ public override void AlignActiveValues()
+ {
+ CapOption.AlignActiveValues();
+ }
+
void OnSensitivityCapCheckClick(object sender, EventArgs e)
{
if (!LegacyCapCheck.Checked)
@@ -139,19 +211,15 @@ namespace grapher
void EnableSensitivityCap()
{
IsSensitivityGain = true;
- CapOption.Fields.LockCheckBox.Enabled = true;
- WeightOption.Fields.LockCheckBox.Enabled = true;
CapOption.SetName("Sensitivity Cap");
}
void EnableVelocityGainCap()
{
IsSensitivityGain = false;
- CapOption.Fields.LockCheckBox.Checked = true;
- CapOption.Fields.LockCheckBox.Enabled = false;
- WeightOption.Fields.LockCheckBox.Checked = true;
- WeightOption.Fields.LockCheckBox.Enabled = false;
CapOption.SetName("Velocity Gain Cap");
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Options/IOption.cs b/grapher/Models/Options/IOption.cs
new file mode 100644
index 0000000..fff1623
--- /dev/null
+++ b/grapher/Models/Options/IOption.cs
@@ -0,0 +1,23 @@
+namespace grapher.Models.Options
+{
+ public interface IOption
+ {
+ int Top { get; set; }
+
+ int Height { get; }
+
+ int Left { get; }
+
+ int Width { get; }
+
+ int Beneath { get; }
+
+ bool Visible { get; }
+
+ void Show(string name);
+
+ void Hide();
+
+ void SnapTo(IOption option);
+ }
+}
diff --git a/grapher/Models/Options/OffsetOptions.cs b/grapher/Models/Options/OffsetOptions.cs
index 0b01ab9..b351ab5 100644
--- a/grapher/Models/Options/OffsetOptions.cs
+++ b/grapher/Models/Options/OffsetOptions.cs
@@ -1,13 +1,9 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher.Models.Options
{
- public class OffsetOptions
+ public class OffsetOptions : OptionBase
{
public OffsetOptions(
ToolStripMenuItem velocityGainOffsetCheck,
@@ -65,6 +61,73 @@ namespace grapher.Models.Options
}
}
+ public override int Top
+ {
+ get
+ {
+ return OffsetOption.Top;
+ }
+ set
+ {
+ OffsetOption.Top = value;
+ }
+ }
+
+ public override int Height
+ {
+ get
+ {
+ return OffsetOption.Height;
+ }
+ }
+
+ public override int Left
+ {
+ get
+ {
+ return OffsetOption.Left;
+ }
+ set
+ {
+ OffsetOption.Left = value;
+ }
+ }
+
+ public override int Width
+ {
+ get
+ {
+ return OffsetOption.Width;
+ }
+ set
+ {
+ OffsetOption.Width = value;
+ }
+ }
+
+ public override bool Visible
+ {
+ get
+ {
+ return OffsetOption.Visible;
+ }
+ }
+
+ public override void Hide()
+ {
+ OffsetOption.Hide();
+ }
+
+ public void Show()
+ {
+ OffsetOption.Show();
+ }
+
+ public override void Show(string name)
+ {
+ OffsetOption.Show(name);
+ }
+
public void SetActiveValue(double offset, double legacyOffset)
{
if (offset > 0)
@@ -77,6 +140,11 @@ namespace grapher.Models.Options
}
}
+ public override void AlignActiveValues()
+ {
+ OffsetOption.AlignActiveValues();
+ }
+
public void OnVelocityGainOffsetClick(object sender, EventArgs e)
{
if (!VelocityGainOffsetCheck.Checked)
diff --git a/grapher/Models/Options/Option.cs b/grapher/Models/Options/Option.cs
index b0ef374..5dc022b 100644
--- a/grapher/Models/Options/Option.cs
+++ b/grapher/Models/Options/Option.cs
@@ -1,23 +1,30 @@
using grapher.Models.Options;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher
{
- public class Option
+ public class Option : OptionBase
{
+ #region Constructors
+
public Option(
Field field,
Label label,
- ActiveValueLabel activeValueLabel)
+ ActiveValueLabel activeValueLabel,
+ int left)
{
Field = field;
Label = label;
ActiveValueLabel = activeValueLabel;
+ Left = left;
+
+ label.AutoSize = false;
+ label.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ label.Width = Field.Left - left - Constants.OptionLabelBoxSeperation;
+ label.Height = Field.Height;
+
+ ActiveValueLabel.Left = Field.Left + Field.Width;
+ ActiveValueLabel.Height = Field.Height;
}
public Option(
@@ -25,11 +32,13 @@ namespace grapher
Form containingForm,
double defaultData,
Label label,
+ int left,
ActiveValueLabel activeValueLabel)
: this(
new Field(box, containingForm, defaultData),
label,
- activeValueLabel)
+ activeValueLabel,
+ left)
{
}
@@ -38,6 +47,7 @@ namespace grapher
Form containingForm,
double defaultData,
Label label,
+ int left,
ActiveValueLabel activeValueLabel,
string startingName)
: this(
@@ -45,22 +55,82 @@ namespace grapher
containingForm,
defaultData,
label,
+ left,
activeValueLabel)
{
SetName(startingName);
}
+ #endregion Constructors
+
+ #region Properties
+
public Field Field { get; }
public Label Label { get; }
public ActiveValueLabel ActiveValueLabel { get; }
+ public override int Top
+ {
+ get
+ {
+ return Field.Top;
+ }
+ set
+ {
+ Field.Top = value;
+ Label.Top = value;
+ ActiveValueLabel.Top = value;
+ }
+ }
+
+ public override int Height
+ {
+ get
+ {
+ return Field.Height;
+ }
+ }
+
+ public override int Left
+ {
+ get
+ {
+ return Label.Left;
+ }
+ set
+ {
+ Label.Left = value;
+ }
+ }
+ public override int Width
+ {
+ get
+ {
+ return Field.Left + Field.Width - Label.Left;
+ }
+ set
+ {
+ }
+ }
+
+ public override bool Visible
+ {
+ get
+ {
+ return Field.Box.Visible;
+ }
+ }
+
+ #endregion Properties
+
+ #region Methods
+
public void SetName(string name)
{
Label.Text = name;
//Label.Left = Convert.ToInt32((Field.Box.Left / 2.0) - (Label.Width / 2.0)); //Centered
- Label.Left = Convert.ToInt32(Field.Box.Left - Label.Width - 10); //Right-aligned
}
public void SetActiveValue(double value)
@@ -68,7 +138,7 @@ namespace grapher
ActiveValueLabel.SetValue(value);
}
- public void Hide()
+ public override void Hide()
{
Field.Box.Hide();
Label.Hide();
@@ -87,11 +157,18 @@ namespace grapher
ActiveValueLabel.SetValue(value);
}
- public void Show(string name)
+ public override void Show(string name)
{
SetName(name);
Show();
}
+
+ public override void AlignActiveValues()
+ {
+ ActiveValueLabel.Align();
+ }
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Options/OptionBase.cs b/grapher/Models/Options/OptionBase.cs
new file mode 100644
index 0000000..5f6dca1
--- /dev/null
+++ b/grapher/Models/Options/OptionBase.cs
@@ -0,0 +1,33 @@
+namespace grapher.Models.Options
+{
+ public abstract class OptionBase : IOption
+ {
+ public abstract int Top { get; set; }
+
+ public abstract int Height { get; }
+
+ public abstract int Left { get; set; }
+
+ public abstract int Width { get; set; }
+
+ public int Beneath {
+ get
+ {
+ return Top + Height + Constants.OptionVerticalSeperation;
+ }
+ }
+
+ public abstract bool Visible { get; }
+
+ public abstract void Show(string Name);
+
+ public abstract void Hide();
+
+ public abstract void AlignActiveValues();
+
+ public virtual void SnapTo(IOption option)
+ {
+ Top = option.Beneath;
+ }
+ }
+}
diff --git a/grapher/Models/Options/OptionXY.cs b/grapher/Models/Options/OptionXY.cs
index 8e22617..6d6129a 100644
--- a/grapher/Models/Options/OptionXY.cs
+++ b/grapher/Models/Options/OptionXY.cs
@@ -1,20 +1,18 @@
using grapher.Models.Options;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher
{
- public class OptionXY
+ public class OptionXY : OptionBase
{
+ #region Constructors
public OptionXY(FieldXY fields, Label label, ActiveValueLabelXY activeValueLabels)
{
Fields = fields;
Label = label;
ActiveValueLabels = activeValueLabels;
+ ActiveValueLabels.Left = fields.CombinedWidth + fields.Left;
}
public OptionXY(
@@ -24,9 +22,8 @@ namespace grapher
Form containingForm,
double defaultData,
Label label,
- AccelCharts accelCharts,
ActiveValueLabelXY activeValueLabels)
- : this(new FieldXY(xBox, yBox, lockCheckBox, containingForm, defaultData, accelCharts), label, activeValueLabels)
+ : this(new FieldXY(xBox, yBox, lockCheckBox, containingForm, defaultData), label, activeValueLabels)
{
}
@@ -38,8 +35,7 @@ namespace grapher
double defaultData,
Label label,
ActiveValueLabelXY activeValueLabels,
- string startingName,
- AccelCharts accelCharts):
+ string startingName):
this(
xBox,
yBox,
@@ -47,18 +43,76 @@ namespace grapher
containingForm,
defaultData,
label,
- accelCharts,
activeValueLabels)
{
SetName(startingName);
}
+ #endregion Constructors
+
+ #region Properties
+
public FieldXY Fields { get; }
public Label Label { get; }
public ActiveValueLabelXY ActiveValueLabels { get; }
+ public override int Top
+ {
+ get
+ {
+ return Fields.Top;
+ }
+ set
+ {
+ Fields.Top = value;
+ }
+ }
+
+ public override int Height
+ {
+ get
+ {
+ return Fields.Height;
+ }
+ }
+
+ public override int Left
+ {
+ get
+ {
+ return Fields.Left;
+ }
+ set
+ {
+ Fields.Left = value;
+ }
+ }
+
+ public override int Width
+ {
+ get
+ {
+ return Fields.Width;
+ }
+ set
+ {
+ Fields.Width = value;
+ }
+ }
+
+ public override bool Visible
+ {
+ get
+ {
+ return Fields.Visible;
+ }
+ }
+ #endregion Properties
+
+ #region Methods
+
public void SetName(string name)
{
Label.Text = name;
@@ -71,7 +125,12 @@ namespace grapher
ActiveValueLabels.SetValues(x, y);
}
- public void Hide()
+ public override void AlignActiveValues()
+ {
+ ActiveValueLabels.AlignActiveValues();
+ }
+
+ public override void Hide()
{
Fields.Hide();
Fields.LockCheckBox.Hide();
@@ -85,12 +144,13 @@ namespace grapher
Label.Show();
}
- public void Show(string name)
+ public override void Show(string name)
{
SetName(name);
Show();
}
+ #endregion Methods
}
}
diff --git a/grapher/Models/Serialized/DriverSettings.cs b/grapher/Models/Serialized/DriverSettings.cs
index cdccf88..d7c9444 100644
--- a/grapher/Models/Serialized/DriverSettings.cs
+++ b/grapher/Models/Serialized/DriverSettings.cs
@@ -4,11 +4,17 @@ using System.Threading;
namespace grapher.Models.Serialized
{
+ #region Enumerations
+
public enum AccelMode
{
- linear, classic, natural, logarithmic, sigmoid, naturalgain, sigmoidgain, power, noaccel
+ linear, classic, natural, naturalgain, sigmoidgain, power, noaccel
}
+ #endregion Enumerations
+
+ #region Structs
+
[StructLayout(LayoutKind.Sequential)]
public struct AccelArgs
{
@@ -33,10 +39,14 @@ namespace grapher.Models.Serialized
public T y;
}
+ #endregion Structs
+
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public class DriverSettings
{
+ #region Fields
+
private static readonly IntPtr UnmanagedSettingsHandle =
Marshal.AllocHGlobal(Marshal.SizeOf<DriverSettings>());
private static object UnmanagedSettingsLock = new object();
@@ -48,6 +58,10 @@ namespace grapher.Models.Serialized
public Vec2<double> sensitivity;
public double minimumTime;
+ #endregion Fields
+
+ #region Methods
+
public static DriverSettings GetActive()
{
DriverInterop.GetActiveSettings(UnmanagedSettingsHandle);
@@ -97,5 +111,7 @@ namespace grapher.Models.Serialized
*/
return true;
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Serialized/GUISettings.cs b/grapher/Models/Serialized/GUISettings.cs
index 7c8e9a4..2543104 100644
--- a/grapher/Models/Serialized/GUISettings.cs
+++ b/grapher/Models/Serialized/GUISettings.cs
@@ -1,17 +1,13 @@
using Newtonsoft.Json;
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
namespace grapher.Models.Serialized
{
[Serializable]
public class GUISettings
{
+ #region Constructors
+
public GUISettings() {}
public GUISettings(bool autoWrite, int dpi, int pollRate)
@@ -21,6 +17,10 @@ namespace grapher.Models.Serialized
PollRate = pollRate;
}
+ #endregion Constructors
+
+ #region Properties
+
[JsonProperty(Order = 1)]
public bool AutoWriteToDriverOnStartup { get; set; }
@@ -29,5 +29,10 @@ namespace grapher.Models.Serialized
[JsonProperty(Order = 3)]
public int PollRate { get; set; }
+
+ [JsonProperty(Order = 4)]
+ public bool ShowLastMouseMove { get; set; }
+
+ #endregion Properties
}
}
diff --git a/grapher/Models/Serialized/RawAccelSettings.cs b/grapher/Models/Serialized/RawAccelSettings.cs
index 7aed917..3f5aebc 100644
--- a/grapher/Models/Serialized/RawAccelSettings.cs
+++ b/grapher/Models/Serialized/RawAccelSettings.cs
@@ -1,26 +1,25 @@
using Newtonsoft.Json;
using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
namespace grapher.Models.Serialized
{
[Serializable]
public class RawAccelSettings
{
- public const string DefaultSettingsFileName = @"settings.json";
+ #region Fields
+
public static readonly string ExecutingDirectory = AppDomain.CurrentDomain.BaseDirectory;
- public static readonly string DefaultSettingsFile = Path.Combine(ExecutingDirectory, DefaultSettingsFileName);
+ public static readonly string DefaultSettingsFile = Path.Combine(ExecutingDirectory, Constants.DefaultSettingsFileName);
public static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error,
};
+ #endregion Fields
+
+ #region Constructors
+
public RawAccelSettings() { }
public RawAccelSettings(
@@ -31,10 +30,18 @@ namespace grapher.Models.Serialized
GUISettings = guiSettings;
}
+ #endregion Constructors
+
+ #region Properties
+
public GUISettings GUISettings { get; set; }
public DriverSettings AccelerationSettings { get; set; }
+ #endregion Properties
+
+ #region Methods
+
public static RawAccelSettings Load()
{
return Load(DefaultSettingsFile);
@@ -75,5 +82,7 @@ namespace grapher.Models.Serialized
{
File.WriteAllText(file, JsonConvert.SerializeObject(this, Formatting.Indented));
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Models/Serialized/SettingsManager.cs b/grapher/Models/Serialized/SettingsManager.cs
index c300bde..ccffc3f 100644
--- a/grapher/Models/Serialized/SettingsManager.cs
+++ b/grapher/Models/Serialized/SettingsManager.cs
@@ -6,18 +6,26 @@ namespace grapher.Models.Serialized
{
public class SettingsManager
{
+ #region Constructors
+
public SettingsManager(
ManagedAccel activeAccel,
Field dpiField,
Field pollRateField,
- ToolStripMenuItem autoWrite)
+ ToolStripMenuItem autoWrite,
+ ToolStripMenuItem showLastMouseMove)
{
ActiveAccel = activeAccel;
DpiField = dpiField;
PollRateField = pollRateField;
AutoWriteMenuItem = autoWrite;
+ ShowLastMouseMoveMenuItem = showLastMouseMove;
}
+ #endregion Constructors
+
+ #region Properties
+
public ManagedAccel ActiveAccel { get; }
public RawAccelSettings RawAccelSettings { get; private set; }
@@ -28,6 +36,12 @@ namespace grapher.Models.Serialized
private ToolStripMenuItem AutoWriteMenuItem { get; set; }
+ private ToolStripMenuItem ShowLastMouseMoveMenuItem { get; set; }
+
+ #endregion Properties
+
+ #region Methods
+
public void UpdateActiveSettings(DriverSettings settings, Action afterAccelSettingsUpdate = null)
{
settings.SendToDriverAndUpdate(ActiveAccel, () =>
@@ -37,7 +51,8 @@ namespace grapher.Models.Serialized
{
AutoWriteToDriverOnStartup = AutoWriteMenuItem.Checked,
DPI = (int)DpiField.Data,
- PollRate = (int)PollRateField.Data
+ PollRate = (int)PollRateField.Data,
+ ShowLastMouseMove = ShowLastMouseMoveMenuItem.Checked,
};
RawAccelSettings.Save();
@@ -53,6 +68,7 @@ namespace grapher.Models.Serialized
DpiField.SetToEntered(RawAccelSettings.GUISettings.DPI);
PollRateField.SetToEntered(RawAccelSettings.GUISettings.PollRate);
AutoWriteMenuItem.Checked = RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup;
+ ShowLastMouseMoveMenuItem.Checked = RawAccelSettings.GUISettings.ShowLastMouseMove;
}
public void Startup()
@@ -80,9 +96,12 @@ namespace grapher.Models.Serialized
{
AutoWriteToDriverOnStartup = AutoWriteMenuItem.Checked,
DPI = (int)DpiField.Data,
- PollRate = (int)PollRateField.Data
+ PollRate = (int)PollRateField.Data,
+ ShowLastMouseMove = ShowLastMouseMoveMenuItem.Checked,
});
RawAccelSettings.Save();
}
+
+ #endregion Methods
}
}
diff --git a/grapher/Program.cs b/grapher/Program.cs
index b36ece3..85fd040 100644
--- a/grapher/Program.cs
+++ b/grapher/Program.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace grapher
diff --git a/grapher/grapher.csproj b/grapher/grapher.csproj
index 28322bb..74e2959 100644
--- a/grapher/grapher.csproj
+++ b/grapher/grapher.csproj
@@ -53,8 +53,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Constants\Constants.cs" />
<Compile Include="Layouts\NaturalGainLayout.cs" />
<Compile Include="Layouts\SigmoidGainLayout.cs" />
+ <Compile Include="Models\AccelGUIFactory.cs" />
<Compile Include="Models\Calculations\AccelCalculator.cs" />
<Compile Include="Models\Calculations\AccelChartData.cs" />
<Compile Include="Models\Calculations\AccelData.cs" />
@@ -63,9 +65,11 @@
<Compile Include="Models\Charts\EstimatedPoints.cs" />
<Compile Include="Models\Mouse\MouseWatcher.cs" />
<Compile Include="Models\Mouse\PointData.cs" />
- <Compile Include="Models\Options\AccelOptions.cs" />
+ <Compile Include="Models\Options\AccelTypeOptions.cs" />
+ <Compile Include="Models\Options\AccelOptionSet.cs" />
<Compile Include="Models\Options\ActiveValueLabel.cs" />
<Compile Include="Models\Options\ActiveValueLabelXY.cs" />
+ <Compile Include="Models\Options\ApplyOptions.cs" />
<Compile Include="Models\Options\CapOptions.cs" />
<Compile Include="Models\Charts\ChartXY.cs" />
<Compile Include="Models\Fields\Field.cs" />
@@ -80,13 +84,14 @@
<Compile Include="Layouts\DefaultLayout.cs" />
<Compile Include="Layouts\LayoutBase.cs" />
<Compile Include="Layouts\LinearLayout.cs" />
- <Compile Include="Layouts\LogLayout.cs" />
<Compile Include="Layouts\NaturalLayout.cs" />
<Compile Include="Layouts\OffLayout.cs" />
<Compile Include="Layouts\PowerLayout.cs" />
- <Compile Include="Layouts\SigmoidLayout.cs" />
+ <Compile Include="Models\Options\IOption.cs" />
<Compile Include="Models\Options\OffsetOptions.cs" />
<Compile Include="Models\Options\Option.cs" />
+ <Compile Include="Layouts\OptionLayout.cs" />
+ <Compile Include="Models\Options\OptionBase.cs" />
<Compile Include="Models\Options\OptionXY.cs" />
<Compile Include="Models\Serialized\GUISettings.cs" />
<Compile Include="Models\Serialized\DriverSettings.cs" />
diff --git a/rawaccel.sln b/rawaccel.sln
index 9eb1101..f2eab80 100644
--- a/rawaccel.sln
+++ b/rawaccel.sln
@@ -9,8 +9,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcx
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "installer", "installer\installer.vcxproj", "{896950D1-520A-420A-B6B1-73014B92A68C}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "console", "console\console.vcxproj", "{AB7B3759-B85F-4067-8935-FB4539B41869}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common-install", "common-install\common-install.vcxitems", "{058D66C6-D88B-4FDB-B0E4-0A6FE7483B95}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uninstaller", "uninstaller\uninstaller.vcxproj", "{A4097FF6-A6F0-44E8-B8D0-538D0FB75936}"
@@ -27,7 +25,6 @@ Global
common\common.vcxitems*{60d6c942-ac20-4c05-a2be-54b5c966534d}*SharedItemsImports = 4
common-install\common-install.vcxitems*{896950d1-520a-420a-b6b1-73014b92a68c}*SharedItemsImports = 4
common-install\common-install.vcxitems*{a4097ff6-a6f0-44e8-b8d0-538d0fb75936}*SharedItemsImports = 4
- common\common.vcxitems*{ab7b3759-b85f-4067-8935-fb4539b41869}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -43,10 +40,6 @@ Global
{896950D1-520A-420A-B6B1-73014B92A68C}.Debug|x64.Build.0 = Debug|x64
{896950D1-520A-420A-B6B1-73014B92A68C}.Release|x64.ActiveCfg = Release|x64
{896950D1-520A-420A-B6B1-73014B92A68C}.Release|x64.Build.0 = Release|x64
- {AB7B3759-B85F-4067-8935-FB4539B41869}.Debug|x64.ActiveCfg = Debug|x64
- {AB7B3759-B85F-4067-8935-FB4539B41869}.Debug|x64.Build.0 = Debug|x64
- {AB7B3759-B85F-4067-8935-FB4539B41869}.Release|x64.ActiveCfg = Release|x64
- {AB7B3759-B85F-4067-8935-FB4539B41869}.Release|x64.Build.0 = Release|x64
{A4097FF6-A6F0-44E8-B8D0-538D0FB75936}.Debug|x64.ActiveCfg = Debug|x64
{A4097FF6-A6F0-44E8-B8D0-538D0FB75936}.Debug|x64.Build.0 = Debug|x64
{A4097FF6-A6F0-44E8-B8D0-538D0FB75936}.Release|x64.ActiveCfg = Release|x64
diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp
index 757d3f1..3108bda 100644
--- a/wrapper/wrapper.cpp
+++ b/wrapper/wrapper.cpp
@@ -24,6 +24,8 @@ public ref class ManagedAccel
mouse_modifier* const modifier_instance = new mouse_modifier();
public:
+ static initonly double WriteDelay = -10000000 / -10000.0;
+
virtual ~ManagedAccel()
{
delete modifier_instance;