Initial commit
This commit is contained in:
99
AgIsoVirtualTerminal/.clang-format
Normal file
99
AgIsoVirtualTerminal/.clang-format
Normal file
@@ -0,0 +1,99 @@
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel : true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: true
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 0
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
FixNamespaceComments: false
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 2
|
||||
UseTab: ForIndentation
|
||||
60
AgIsoVirtualTerminal/.cmake-format.yaml
Normal file
60
AgIsoVirtualTerminal/.cmake-format.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
format:
|
||||
disable: false
|
||||
line_width: 80
|
||||
tab_size: 2
|
||||
use_tabchars: false
|
||||
fractional_tab_policy: use-space
|
||||
max_subgroups_hwrap: 2
|
||||
max_pargs_hwrap: 6
|
||||
max_rows_cmdline: 2
|
||||
separate_ctrl_name_with_space: false
|
||||
separate_fn_name_with_space: false
|
||||
dangle_parens: false
|
||||
dangle_align: prefix
|
||||
min_prefix_chars: 4
|
||||
max_prefix_chars: 10
|
||||
max_lines_hwrap: 2
|
||||
line_ending: unix
|
||||
command_case: canonical
|
||||
keyword_case: unchanged
|
||||
always_wrap: []
|
||||
enable_sort: true
|
||||
autosort: false
|
||||
require_valid_layout: false
|
||||
layout_passes: {}
|
||||
markup:
|
||||
bullet_char: "*"
|
||||
enum_char: .
|
||||
first_comment_is_literal: false
|
||||
literal_comment_pattern: null
|
||||
fence_pattern: ^\s*([`~]{3}[`~]*)(.*)$
|
||||
ruler_pattern: ^\s*[^\w\s]{3}.*[^\w\s]{3}$
|
||||
explicit_trailing_pattern: "#<"
|
||||
hashruler_min_length: 10
|
||||
canonicalize_hashrulers: true
|
||||
enable_markup: true
|
||||
lint:
|
||||
disabled_codes: [C0301]
|
||||
function_pattern: "[0-9a-z_]+"
|
||||
macro_pattern: "[0-9A-Z_]+"
|
||||
global_var_pattern: "[a-zA-Z][0-9a-zA-Z_]+"
|
||||
internal_var_pattern: _[A-Z][0-9A-Z_]+
|
||||
local_var_pattern: "[a-z][a-z0-9_]+"
|
||||
private_var_pattern: _[0-9a-z_]+
|
||||
public_var_pattern: "[A-Z][0-9A-Z_]+"
|
||||
argument_var_pattern: "[a-z][a-z0-9_]+"
|
||||
keyword_pattern: "[A-Z][0-9A-Z_]+"
|
||||
max_conditionals_custom_parser: 2
|
||||
min_statement_spacing: 1
|
||||
max_statement_spacing: 2
|
||||
max_returns: 6
|
||||
max_branches: 12
|
||||
max_arguments: 5
|
||||
max_localvars: 15
|
||||
max_statements: 50
|
||||
encode:
|
||||
emit_byteorder_mark: false
|
||||
input_encoding: utf-8
|
||||
output_encoding: utf-8
|
||||
misc:
|
||||
per_command: {}
|
||||
44
AgIsoVirtualTerminal/.gitignore
vendored
Normal file
44
AgIsoVirtualTerminal/.gitignore
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Editors
|
||||
.vs/
|
||||
.vscode/
|
||||
out
|
||||
build
|
||||
|
||||
# QtCreator cmake temp files
|
||||
CMakeLists.txt.user
|
||||
|
||||
# KDE hidden file artifacts
|
||||
.directory
|
||||
219
AgIsoVirtualTerminal/CMakeLists.txt
Normal file
219
AgIsoVirtualTerminal/CMakeLists.txt
Normal file
@@ -0,0 +1,219 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(
|
||||
"AgISOVirtualTerminal"
|
||||
LANGUAGES CXX
|
||||
VERSION 1.3.0)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
|
||||
set(JUCE_WEB_BROWSER OFF)
|
||||
set(BUILD_TESTING OFF)
|
||||
|
||||
if(WIN32)
|
||||
set(CAN_DRIVER "WindowsPCANBasic")
|
||||
list(APPEND CAN_DRIVER "TouCAN")
|
||||
|
||||
if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND MINGW))
|
||||
list(APPEND CAN_DRIVER "WindowsInnoMakerUSB2CAN")
|
||||
else()
|
||||
message(
|
||||
STATUS
|
||||
"InnoMaker hardware will not be supported in this build because you are using mingw"
|
||||
)
|
||||
endif()
|
||||
list(APPEND CAN_DRIVER "SYS_TEC")
|
||||
elseif(APPLE)
|
||||
set(CAN_DRIVER "MacCANPCAN")
|
||||
else()
|
||||
set(CAN_DRIVER "SocketCAN")
|
||||
endif()
|
||||
|
||||
find_package(JUCE MODULE)
|
||||
find_package(CAN_Stack MODULE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
juce_add_gui_app(
|
||||
AgISOVirtualTerminal
|
||||
ICON_BIG
|
||||
doc/smallLogo.png
|
||||
# image file to use as an icon ICON_SMALL ...
|
||||
COMPANY_NAME
|
||||
"Open-Agriculture"
|
||||
COMPANY_COPYRIGHT
|
||||
"Open-Agriculture"
|
||||
COMPANY_WEBSITE
|
||||
"https://github.com/Open-Agriculture"
|
||||
PRODUCT_NAME
|
||||
"AgISOVirtualTerminal"
|
||||
NEEDS_CURL
|
||||
FALSE
|
||||
NEEDS_WEB_BROWSER
|
||||
FALSE
|
||||
DESCRIPTION
|
||||
"An ISO11783-6 Server")
|
||||
|
||||
set_target_properties(AgISOVirtualTerminal PROPERTIES CXX_STANDARD 17)
|
||||
|
||||
target_compile_definitions(AgISOVirtualTerminal PRIVATE JUCE_USE_CURL=0
|
||||
JUCE_WEB_BROWSER=0)
|
||||
|
||||
juce_generate_juce_header(AgISOVirtualTerminal)
|
||||
|
||||
target_sources(
|
||||
AgISOVirtualTerminal
|
||||
PRIVATE src/Main.cpp
|
||||
"src/ServerMainComponent.cpp"
|
||||
"src/DataMaskComponent.cpp"
|
||||
"src/WorkingSetSelectorComponent.cpp"
|
||||
"src/PictureGraphicComponent.cpp"
|
||||
"src/WorkingSetComponent.cpp"
|
||||
"src/AlarmMaskComponent.cpp"
|
||||
"src/DataMaskRenderAreaComponent.cpp"
|
||||
"src/JuceManagedWorkingSetCache.cpp"
|
||||
"src/OutputRectangleComponent.cpp"
|
||||
"src/OutputStringComponent.cpp"
|
||||
"src/ButtonComponent.cpp"
|
||||
"src/ContainerComponent.cpp"
|
||||
"src/ObjectPointerComponent.cpp"
|
||||
"src/OutputNumberComponent.cpp"
|
||||
"src/SoftkeyMaskRenderArea.cpp"
|
||||
"src/KeyComponent.cpp"
|
||||
"src/SoftKeyMaskComponent.cpp"
|
||||
"src/OutputMeterComponent.cpp"
|
||||
"src/InputBooleanComponent.cpp"
|
||||
"src/LoggerComponent.cpp"
|
||||
"src/InputNumberComponent.cpp"
|
||||
"src/OutputEllipseComponent.cpp"
|
||||
"src/OutputLineComponent.cpp"
|
||||
"src/OutputLinearBarGraphComponent.cpp"
|
||||
"src/OutputPolygonComponent.cpp"
|
||||
"src/InputStringComponent.cpp"
|
||||
"src/AlarmMaskAudio.cpp"
|
||||
"src/AppImages.cpp"
|
||||
"src/ASCIILogFile.cpp"
|
||||
"src/ConfigureHardwareWindow.cpp"
|
||||
"src/ConfigureHardwareComponent.cpp"
|
||||
"src/StringEncodingConversions.cpp"
|
||||
"src/InputListComponent.cpp"
|
||||
"src/ShortcutsWindow.cpp")
|
||||
|
||||
target_include_directories(AgISOVirtualTerminal
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
target_link_libraries(
|
||||
AgISOVirtualTerminal
|
||||
PRIVATE juce::juce_gui_extra juce::juce_audio_basics juce::juce_audio_utils
|
||||
isobus::Isobus isobus::HardwareIntegration isobus::Utility
|
||||
PUBLIC juce::juce_recommended_config_flags juce::juce_recommended_lto_flags)
|
||||
|
||||
if(WIN32)
|
||||
add_custom_command(
|
||||
TARGET AgISOVirtualTerminal
|
||||
POST_BUILD
|
||||
COMMENT "Copying PCANBasic.dll to the build directory"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_if_different
|
||||
${CMAKE_CURRENT_LIST_DIR}/lib/PCANBasic.dll
|
||||
"$<TARGET_FILE_DIR:AgISOVirtualTerminal>"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(
|
||||
TARGET AgISOVirtualTerminal
|
||||
POST_BUILD
|
||||
COMMENT "Copying Usbcan64.dll to the build directory"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_if_different
|
||||
${CMAKE_CURRENT_LIST_DIR}/lib/Usbcan64.dll
|
||||
"$<TARGET_FILE_DIR:AgISOVirtualTerminal>"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(
|
||||
TARGET AgISOVirtualTerminal
|
||||
POST_BUILD
|
||||
COMMENT "Copying canal.dll to the build directory"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_if_different
|
||||
${CMAKE_CURRENT_LIST_DIR}/lib/canal.dll
|
||||
"$<TARGET_FILE_DIR:AgISOVirtualTerminal>"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(
|
||||
TARGET AgISOVirtualTerminal
|
||||
POST_BUILD
|
||||
COMMENT "Copying InnoMakerUsb2CanLib.dll to the build directory"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_if_different
|
||||
${CMAKE_CURRENT_LIST_DIR}/lib/InnoMakerUsb2CanLib.dll
|
||||
"$<TARGET_FILE_DIR:AgISOVirtualTerminal>"
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
install(
|
||||
TARGETS AgISOVirtualTerminal
|
||||
RUNTIME DESTINATION bin
|
||||
BUNDLE DESTINATION . COMPONENT applications)
|
||||
else()
|
||||
install(TARGETS AgISOVirtualTerminal RUNTIME DESTINATION bin
|
||||
COMPONENT applications)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_LIST_DIR}/lib/Usbcan64.dll
|
||||
DESTINATION bin
|
||||
COMPONENT applications)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_LIST_DIR}/lib/PCANBasic.dll
|
||||
DESTINATION bin
|
||||
COMPONENT applications)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_LIST_DIR}/lib/canal.dll
|
||||
DESTINATION bin
|
||||
COMPONENT applications)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_LIST_DIR}/lib/InnoMakerUsb2CanLib.dll
|
||||
DESTINATION bin
|
||||
COMPONENT applications)
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_NAME "AgISOVirtualTerminal")
|
||||
set(CPACK_PACKAGE_VENDOR "Open-Agriculture")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An ISO11783-6 Server")
|
||||
set(CPACK_PACKAGE_VERSION "1.3.0")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "0")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "AgISOVirtualTerminal")
|
||||
set(CPACK_COMPONENTS_ALL applications)
|
||||
set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "AgISOVirtualTerminal")
|
||||
set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION
|
||||
"A free and open source ISO11783-6 Server")
|
||||
set(CPACK_PACKAGE_CONTACT "delgrossoengineering@protonmail.com")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_LIST_DIR}/LICENSE")
|
||||
set(CPACK_PACKAGE_EXECUTABLES "AgISOVirtualTerminal" "AgISOVirtualTerminal")
|
||||
set(CPACK_ALL_INSTALL_TYPES Full)
|
||||
set(CPACK_COMPONENT_LIBRARIES_INSTALL_TYPES Full)
|
||||
set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full)
|
||||
set(CPACK_NSIS_INSTALLED_ICON_NAME ${CMAKE_CURRENT_LIST_DIR}/doc/smallLogo.ico)
|
||||
set(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT})
|
||||
set(CPACK_NSIS_MUI_ICON ${CPACK_NSIS_INSTALLED_ICON_NAME})
|
||||
set(CPACK_NSIS_MUI_UNICON ${CPACK_NSIS_INSTALLED_ICON_NAME})
|
||||
set(CPACK_NSIS_DISPLAY_NAME "AgISOVirtualTerminal")
|
||||
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT applications)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
if(APPLE)
|
||||
set(CPACK_GENERATOR DragNDrop ${CPACK_GENERATOR})
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_DMG_FORMAT "UDBZ")
|
||||
set(CPACK_DMG_VOLUME_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_SYSTEM_NAME "OSX")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
|
||||
set(CPACK_PACKAGE_ICON ${CPACK_NSIS_INSTALLED_ICON_NAME})
|
||||
endif()
|
||||
|
||||
# Must be after the last CPACK macros
|
||||
include(CPack)
|
||||
15
AgIsoVirtualTerminal/CMakeSettings.json
Normal file
15
AgIsoVirtualTerminal/CMakeSettings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
674
AgIsoVirtualTerminal/LICENSE
Normal file
674
AgIsoVirtualTerminal/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
194
AgIsoVirtualTerminal/README.md
Normal file
194
AgIsoVirtualTerminal/README.md
Normal file
@@ -0,0 +1,194 @@
|
||||
<div align="center">
|
||||
|
||||
# AgIsoVirtualTerminal 🚜
|
||||
|
||||
— <ins>**Ag**</ins>riculture <ins>**ISO**</ins>-11783 <ins>**Virtual Terminal**</ins>
|
||||
|
||||
*The experimental free and open-source ISOBUS virtual terminal for everyone - from hobbyists to industry!*
|
||||
|
||||
[Issues & Suggestions](https://github.com/Open-Agriculture/AgIsoVirtualTerminal/issues) | [Discussions](https://github.com/Open-Agriculture/AgIsoVirtualTerminal/discussions) | [Discord](https://discord.gg/uU2XMVUD4b) | [Telegram](https://t.me/+kzd4-9Je5bo1ZDg6)
|
||||
|
||||
[](https://github.com/Open-Agriculture/AgIsoVirtualTerminal/commits/main)
|
||||
[](https://github.com/Open-Agriculture/AgIsoVirtualTerminal/blob/main/LICENSE)
|
||||
|
||||
</div>
|
||||
|
||||
## About
|
||||
|
||||
This project is a multi-platform, experimental ISO11783-6 virtual terminal server GUI meant for agricultural and forestry equipment.
|
||||
|
||||
AgIsoVirtualTerminal is designed to serve as the reference/example implementation of the AgIsoStack++ VT server interface.
|
||||
|
||||
The project is written in C++, compiled with CMake, and is based on [AgIsoStack++](https://github.com/Open-Agriculture/AgIsoStack-plus-plus) and the [JUCE](https://github.com/juce-framework/JUCE) GUI framework.
|
||||
|
||||
This project is in **active development**, and some features may not be completely supported or AEF conformant, but will continue to be improved over time.
|
||||
|
||||
We currently support Windows, Linux, and OSX. We may support other platforms in the future.
|
||||
|
||||
## Screenshots
|
||||
|
||||
 
|
||||
|
||||
## Project Status
|
||||
|
||||
This section is temporary and will be updated as progress is made on the project.
|
||||
|
||||
Supported features:
|
||||
|
||||
- All basic ISO11783 functionality, such as address claiming, TP, ETP, diagnostic protocol, etc.
|
||||
- Object pool deserializer (most objects up to version 6 with some exceptions)
|
||||
- Data masks
|
||||
- Alarm masks
|
||||
- Soft key masks
|
||||
- Key objects
|
||||
- Containers
|
||||
- Object Pointers
|
||||
- Input numbers
|
||||
- Input Boolean
|
||||
- Output numbers
|
||||
- Output rectangles
|
||||
- Output ellipse
|
||||
- Output polygon
|
||||
- Output line
|
||||
- Buttons
|
||||
- Output linear bar graph (except target line)
|
||||
- Output meter (except tick marks and target line)
|
||||
- Picture graphics (with and without run-length encoding)
|
||||
- Output Strings (partial - font clipping is not compliant)
|
||||
- Input lists
|
||||
- Most relevant VT server CAN messages
|
||||
- Logging
|
||||
- Multiple simultaneous VT clients
|
||||
- Selecting different working sets
|
||||
- Most common macro and extended macro functionality
|
||||
|
||||
Unimplemented features (for now - we are always adding new features)
|
||||
|
||||
- Arbitrary audio control functionality
|
||||
- Window masks (tolerated in the object pool though)
|
||||
- Aux N/O (Tolerated in the object pool though)
|
||||
- Animations
|
||||
- Output Lists
|
||||
- Output arched bar graph (Tolerated in the object pool though)
|
||||
- Graphics contexts
|
||||
- Pointing events
|
||||
- TAN
|
||||
- Several messages, such as ESC
|
||||
- Open GL mode (currently only software rendering is supported, though JUCE's software rendering is very RAM efficient compared to GL)
|
||||
- Some way of automatically checking for new releases
|
||||
- Probably more things to be honest
|
||||
|
||||
## Download
|
||||
|
||||
If you don't want to compile the software yourself or contribute code to this project, we will post official Windows Installers, OSX .dmg files, and Linux .deb packages on the [releases page](https://github.com/Open-Agriculture/AgIsoVirtualTerminal/releases) which you can use to easily run this software.
|
||||
|
||||
Be sure to check back from time to time for new releases!
|
||||
|
||||
## Compilation
|
||||
|
||||
This project is compiled with CMake and your favorite C++17 compiler.
|
||||
|
||||
### Dependencies
|
||||
|
||||
Make sure you have `git` installed on your system.
|
||||
You can follow the instructions [here](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to install it. Then, follow the instructions below to install the dependencies for your platform.
|
||||
|
||||
Linux:
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install libasound2-dev libjack-jackd2-dev ladspa-sdk libcurl4-openssl-dev libfreetype6-dev libx11-dev libxcomposite-dev libxcursor-dev libxcursor-dev libxext-dev libxinerama-dev libxrandr-dev libxrender-dev libwebkit2gtk-4.0-dev libglu1-mesa-dev mesa-common-dev cmake pkg-config
|
||||
```
|
||||
|
||||
Fedora:
|
||||
```
|
||||
sudo dnf install cmake ninja-build libX11-devel alsa-lib-devel jack-audio-connection-kit-devel freetype-devel mesa-libGL-devel libcurl-devel webkit2gtk4-devel
|
||||
```
|
||||
|
||||
OSX:
|
||||
|
||||
If you don't have Brew installed, you'll probably want to install it to make acquiring CMake easier. You can find instructions [here](https://brew.sh/).
|
||||
|
||||
```
|
||||
xcode-select --install
|
||||
brew install cmake
|
||||
```
|
||||
|
||||
Windows:
|
||||
|
||||
On Windows, if you don't have Visual Studio 2022 installed, you will need to download and install the [Build Tools for Visual Studio 2022](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022).
|
||||
|
||||
Only 64 bit builds are supported on Windows.
|
||||
|
||||
### A note about CMake Versions
|
||||
|
||||
CMake 3.22 or higher is required! If the version you have is too old, such as if you are on Ubuntu 18.04 and using the one provided with `apt-get`, you can instead download the latest version of CMake [here](https://cmake.org/download/) and use that to compile this software.
|
||||
|
||||
### Building
|
||||
|
||||
Generally, to build the project you'll need to clone the repository and run CMake.
|
||||
|
||||
```
|
||||
git clone
|
||||
cmake -S. -B build -Wno-dev
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
### Creating a Windows Installer
|
||||
|
||||
This project supports automatic creation of a Windows installer.
|
||||
|
||||
Creating a Windows installer requires the nullsoft scriptable install system (NSIS) to be installed on your system. You can download it [here](https://nsis.sourceforge.io/Download).
|
||||
|
||||
Using the visual studio developer command prompt or developer powershell, run the following commands from the root of the repository:
|
||||
|
||||
```
|
||||
cmake -S . -B build -Wno-dev
|
||||
cmake --build build --target package --config Release
|
||||
```
|
||||
|
||||
This will generate a .exe installer in the build directory.
|
||||
|
||||
### Creating a Linux .deb package
|
||||
|
||||
Creating a .deb package is somewhat easier than creating a Windows installer, but keep in mind that the package will only work on Debian-based systems and only for the same version of each system.
|
||||
For example, a package created on Ubuntu 20.04 will only work on Ubuntu 20.04 and not on Ubuntu 18.04 or 22.04.
|
||||
|
||||
```
|
||||
cmake -S . -B build -Wno-dev
|
||||
cd build
|
||||
cpack -G DEB
|
||||
sudo dpkg -i AgISOVirtualTerminal-<version>-Linux.deb
|
||||
```
|
||||
|
||||
You can uninstall the package with `sudo apt remove AgISOVirtualTerminal` or `sudo dnf autoremove AgISOVirtualTerminal`.
|
||||
|
||||
### Creating an OSX .dmg package
|
||||
|
||||
```
|
||||
cmake -S . -B build -Wno-dev
|
||||
cmake --build build --target package --config Release
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* On OSX, if you get an error about `libPCBUSB` when trying to run the program, you'll need to allow the file in System Preferences -> Security & Privacy. This is due to our inclusion of the Mac port of the PCAN driver, and isn't something we can control.
|
||||
|
||||
If you find something that doesn't work, please open an issue on GitHub. Seriously. We want to know about it. Our goal is to make this application completely conformant to the VT standard, so finding issues will help accelerate that process.
|
||||
|
||||
If you open an issue, we need the object pool of the working set you were using, plus all logging output from the program to fix it!
|
||||
|
||||
### Disclaimers
|
||||
|
||||
Because this software is licensed under the GPL v3.0, you may not include this software in any closed source software, nor link to it in any way from closed source software.
|
||||
|
||||
If you wish to sponsor development of this software, please contact us in the discord or telegram channels.
|
||||
|
||||
This project is not associated with the Agricultural Industry Electronics Foundation (AEF) in any way.
|
||||
|
||||
This project is not associated with the International Organization for Standardization (ISO) in any way.
|
||||
|
||||
Don't ask us to share the ISO standards with you. We can't. You have to buy them from ISO. We don't have the right to share them with you.
|
||||
|
||||
By acquiring or using this project you agree to the [JUCE License](https://github.com/juce-framework/JUCE/blob/master/LICENSE.md), [this project's license](https://github.com/Open-Agriculture/AgIsoVirtualTerminal/blob/main/LICENSE), and any applicable licenses provided by dependencies such as AgIsoStack.
|
||||
|
||||
This software was not created to compete with any commercial or open-source software. It was created to help hobbyists and professionals alike learn about and experiment with ISOBUS.
|
||||
8
AgIsoVirtualTerminal/cmake/FindCAN_Stack.cmake
Normal file
8
AgIsoVirtualTerminal/cmake/FindCAN_Stack.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
if(NOT TARGET isobus::isobus)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
CAN_Stack
|
||||
GIT_REPOSITORY https://github.com/Open-Agriculture/AgIsoStack-plus-plus.git
|
||||
GIT_TAG a71c186efd189b45759364ddf790b5634b8ba878)
|
||||
FetchContent_MakeAvailable(CAN_Stack)
|
||||
endif()
|
||||
8
AgIsoVirtualTerminal/cmake/FindJUCE.cmake
Normal file
8
AgIsoVirtualTerminal/cmake/FindJUCE.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
if(NOT TARGET JUCE::JUCE)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
JUCE
|
||||
GIT_REPOSITORY https://github.com/juce-framework/JUCE.git
|
||||
GIT_TAG 7.0.8)
|
||||
FetchContent_MakeAvailable(JUCE)
|
||||
endif()
|
||||
BIN
AgIsoVirtualTerminal/doc/screenshot1.png
Normal file
BIN
AgIsoVirtualTerminal/doc/screenshot1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
AgIsoVirtualTerminal/doc/screenshot2.png
Normal file
BIN
AgIsoVirtualTerminal/doc/screenshot2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
AgIsoVirtualTerminal/doc/smallLogo.ico
Normal file
BIN
AgIsoVirtualTerminal/doc/smallLogo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
AgIsoVirtualTerminal/doc/smallLogo.png
Normal file
BIN
AgIsoVirtualTerminal/doc/smallLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
AgIsoVirtualTerminal/doc/smallLogo_for_windowicon.png
Normal file
BIN
AgIsoVirtualTerminal/doc/smallLogo_for_windowicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
31
AgIsoVirtualTerminal/include/ASCIILogFile.hpp
Normal file
31
AgIsoVirtualTerminal/include/ASCIILogFile.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file ASCIILogFile.hpp
|
||||
///
|
||||
/// @brief Defines a CAN logger that saves messages in a Vector .asc file.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef ASCII_LOG_FILE_HPP
|
||||
#define ASCII_LOG_FILE_HPP
|
||||
|
||||
#include "isobus/hardware_integration/can_hardware_interface.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
/// @brief Logs to Vector .asc file
|
||||
class ASCIILogFile
|
||||
{
|
||||
public:
|
||||
ASCIILogFile();
|
||||
|
||||
~ASCIILogFile() = default;
|
||||
|
||||
private:
|
||||
File logFile;
|
||||
isobus::EventCallbackHandle canFrameReceivedListener;
|
||||
isobus::EventCallbackHandle canFrameSentListener;
|
||||
Time initialTimestamp;
|
||||
};
|
||||
|
||||
#endif // ASCII_LOG_FILE_HPP
|
||||
16
AgIsoVirtualTerminal/include/AlarmMaskAudio.h
Normal file
16
AgIsoVirtualTerminal/include/AlarmMaskAudio.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/* (Auto-generated binary data file). */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AlarmMaskAudio
|
||||
{
|
||||
extern const char *alarmMaskHigh_mp3;
|
||||
const int alarmMaskHigh_mp3Size = 37281;
|
||||
|
||||
extern const char *alarmMaskLow_mp3;
|
||||
const int alarmMaskLow_mp3Size = 15393;
|
||||
|
||||
extern const char *alarmMaskMedium_mp3;
|
||||
const int alarmMaskMedium_mp3Size = 16488;
|
||||
|
||||
}
|
||||
34
AgIsoVirtualTerminal/include/AlarmMaskComponent.hpp
Normal file
34
AgIsoVirtualTerminal/include/AlarmMaskComponent.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//================================================================================================
|
||||
/// @file AlarmMaskComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a data mask.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef ALARM_MASK_COMPONENT_HPP
|
||||
#define ALARM_MASK_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class AlarmMaskComponent : public isobus::AlarmMask
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
AlarmMaskComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::AlarmMask sourceObject, int dataMaskSize);
|
||||
|
||||
void on_content_changed(bool initial = false);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AlarmMaskComponent)
|
||||
};
|
||||
|
||||
#endif // ALARM_MASK_COMPONENT_HPP
|
||||
12
AgIsoVirtualTerminal/include/AppImages.h
Normal file
12
AgIsoVirtualTerminal/include/AppImages.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* (Auto-generated binary data file). */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AppImages
|
||||
{
|
||||
extern const char *logo2_png;
|
||||
const int logo2_pngSize = 49015;
|
||||
|
||||
extern const char *logosmall_png;
|
||||
const int logosmall_pngSize = 21145;
|
||||
}
|
||||
36
AgIsoVirtualTerminal/include/ButtonComponent.hpp
Normal file
36
AgIsoVirtualTerminal/include/ButtonComponent.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
//================================================================================================
|
||||
/// @file ButtonComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a button.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef BUTTON_COMPONENT_HPP
|
||||
#define BUTTON_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ButtonComponent : public isobus::Button
|
||||
, public Button
|
||||
{
|
||||
public:
|
||||
ButtonComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Button sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
void paintButton(Graphics &g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
||||
|
||||
void set_options(std::uint8_t value) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ButtonComponent)
|
||||
};
|
||||
|
||||
#endif // BUTTON_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/ColourMapComponent.hpp
Normal file
31
AgIsoVirtualTerminal/include/ColourMapComponent.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file ColourMapComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a button.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef COLOR_MAP_COMPONENT_HPP
|
||||
#define COLOR_MAP_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ColourMapComponent : public isobus::ColourMap
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
ColourMapComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::ColourMap sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ColourMapComponent)
|
||||
};
|
||||
|
||||
#endif // COLOR_MAP_COMPONENT_HPP
|
||||
37
AgIsoVirtualTerminal/include/ConfigureHardwareComponent.hpp
Normal file
37
AgIsoVirtualTerminal/include/ConfigureHardwareComponent.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
//================================================================================================
|
||||
/// @file ConfigureHardwareComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component which allows selecting and configuring a hardware interface.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 The Open-Agriculture Contributors
|
||||
//================================================================================================
|
||||
#ifndef CONFIGURE_HARDWARE_COMPONENT_HPP
|
||||
#define CONFIGURE_HARDWARE_COMPONENT_HPP
|
||||
|
||||
#include "isobus/hardware_integration/can_hardware_interface.hpp"
|
||||
|
||||
#include <JuceHeader.h>
|
||||
|
||||
class ConfigureHardwareWindow;
|
||||
|
||||
class ConfigureHardwareComponent : public Component
|
||||
{
|
||||
public:
|
||||
ConfigureHardwareComponent(ConfigureHardwareWindow &parent, std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &canDrivers);
|
||||
|
||||
void paint(Graphics &graphics) override;
|
||||
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
ComboBox hardwareInterfaceSelector;
|
||||
TextEditor socketCANNameEditor;
|
||||
TextEditor touCANSerialEditor;
|
||||
TextButton okButton;
|
||||
std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &parentCANDrivers;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ConfigureHardwareComponent)
|
||||
};
|
||||
|
||||
#endif // CONFIGURE_HARDWARE_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/ConfigureHardwareWindow.hpp
Normal file
31
AgIsoVirtualTerminal/include/ConfigureHardwareWindow.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file ConfigureHardwareWindow.hpp
|
||||
///
|
||||
/// @brief Defines a GUI window which allows selecting and configuring a hardware interface.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 The Open-Agriculture Contributors
|
||||
//================================================================================================
|
||||
#ifndef CONFIGURE_HARDWARE_WINDOW_HPP
|
||||
#define CONFIGURE_HARDWARE_WINDOW_HPP
|
||||
|
||||
#include "ConfigureHardwareComponent.hpp"
|
||||
|
||||
class ServerMainComponent;
|
||||
|
||||
class ConfigureHardwareWindow : public DocumentWindow
|
||||
{
|
||||
public:
|
||||
ConfigureHardwareWindow(ServerMainComponent &parentComponent, std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &canDrivers);
|
||||
|
||||
void closeButtonPressed() override;
|
||||
|
||||
ServerMainComponent &parentServer;
|
||||
|
||||
private:
|
||||
ConfigureHardwareComponent content;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ConfigureHardwareWindow)
|
||||
};
|
||||
|
||||
#endif // CONFIGURE_HARDWARE_WINDOW_HPP
|
||||
32
AgIsoVirtualTerminal/include/ContainerComponent.hpp
Normal file
32
AgIsoVirtualTerminal/include/ContainerComponent.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//================================================================================================
|
||||
/// @file ContainerComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a container.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef CONTAINER_COMPONENT_HPP
|
||||
#define CONTAINER_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ContainerComponent : public isobus::Container
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
ContainerComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Container sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ContainerComponent)
|
||||
};
|
||||
|
||||
#endif // CONTAINER_COMPONENT_HPP
|
||||
34
AgIsoVirtualTerminal/include/DataMaskComponent.hpp
Normal file
34
AgIsoVirtualTerminal/include/DataMaskComponent.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//================================================================================================
|
||||
/// @file DataMaskComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a data mask.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef DATA_MASK_COMPONENT_HPP
|
||||
#define DATA_MASK_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class DataMaskComponent : public isobus::DataMask
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
DataMaskComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::DataMask sourceObject, int dataMaskSize);
|
||||
|
||||
void on_content_changed(bool initial = false);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DataMaskComponent)
|
||||
};
|
||||
|
||||
#endif // DATA_MASK_COMPONENT_HPP
|
||||
77
AgIsoVirtualTerminal/include/DataMaskRenderAreaComponent.hpp
Normal file
77
AgIsoVirtualTerminal/include/DataMaskRenderAreaComponent.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
//================================================================================================
|
||||
/// @file DataMaskRenderArea.hpp
|
||||
///
|
||||
/// @brief A component to hold all the data mask render components.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef DATA_MASK_RENDER_AREA_COMPONENT_HPP
|
||||
#define DATA_MASK_RENDER_AREA_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ServerMainComponent;
|
||||
|
||||
class DataMaskRenderAreaComponent : public Component
|
||||
{
|
||||
public:
|
||||
DataMaskRenderAreaComponent(ServerMainComponent &parentServer);
|
||||
|
||||
void on_change_active_mask(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet);
|
||||
|
||||
void on_working_set_disconnect(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
// Used to calculate button press events
|
||||
void mouseDown(const MouseEvent &event) override;
|
||||
|
||||
// Used to calculate button release events
|
||||
void mouseUp(const MouseEvent &event) override;
|
||||
|
||||
bool needsRepaint() const;
|
||||
|
||||
void set_has_started(bool started);
|
||||
|
||||
private:
|
||||
class InputNumberListener : public Slider::Listener
|
||||
{
|
||||
public:
|
||||
InputNumberListener() = default;
|
||||
void sliderValueChanged(Slider *slider) override;
|
||||
|
||||
std::uint32_t get_last_value() const;
|
||||
void set_last_value(std::uint32_t value);
|
||||
|
||||
std::shared_ptr<isobus::InputNumber> get_target();
|
||||
void set_target(std::shared_ptr<isobus::InputNumber> objectBeingModified);
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::InputNumber> targetObject;
|
||||
std::uint32_t lastValue = 0;
|
||||
};
|
||||
|
||||
std::shared_ptr<isobus::VTObject> getClickedChildRecursive(std::shared_ptr<isobus::VTObject> object, int x, int y);
|
||||
static bool objectCanBeClicked(std::shared_ptr<isobus::VTObject> object);
|
||||
static bool isClickWithinBounds(int clickXRelative, int clickYRelative, int objectX, int objectY, int objectWidth, int objectHeight);
|
||||
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::unique_ptr<AlertWindow> inputListModal;
|
||||
std::unique_ptr<AlertWindow> inputNumberModal;
|
||||
std::unique_ptr<AlertWindow> inputStringModal;
|
||||
std::unique_ptr<Slider> inputNumberSlider;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
std::vector<std::shared_ptr<Component>> currentModalComponentCache;
|
||||
ServerMainComponent &ownerServer;
|
||||
InputNumberListener inputNumberListener;
|
||||
bool needToRepaintActiveArea = false;
|
||||
bool hasStarted = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DataMaskRenderAreaComponent)
|
||||
};
|
||||
|
||||
#endif // DATA_MASK_RENDER_AREA_COMPONENT_HPP
|
||||
29
AgIsoVirtualTerminal/include/InputBooleanComponent.hpp
Normal file
29
AgIsoVirtualTerminal/include/InputBooleanComponent.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
//================================================================================================
|
||||
/// @file InputBooleanComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an input boolean.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef INPUT_BOOLEAN_COMPONENT_HPP
|
||||
#define INPUT_BOOLEAN_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class InputBooleanComponent : public isobus::InputBoolean
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
InputBooleanComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputBoolean sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
};
|
||||
|
||||
#endif // INPUT_BOOLEAN_COMPONENT_HPP
|
||||
35
AgIsoVirtualTerminal/include/InputListComponent.hpp
Normal file
35
AgIsoVirtualTerminal/include/InputListComponent.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
//================================================================================================
|
||||
/// @file InputListComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an input list.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef INPUT_LIST_COMPONENT_HPP
|
||||
#define INPUT_LIST_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class InputListComponent : public isobus::InputList
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
InputListComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputList sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
void paintOverChildren(Graphics &g) override;
|
||||
|
||||
void onChanged(bool initial);
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::shared_ptr<Component> childComponent;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InputListComponent)
|
||||
};
|
||||
|
||||
#endif // INPUT_LIST_COMPONENT_HPP
|
||||
33
AgIsoVirtualTerminal/include/InputNumberComponent.hpp
Normal file
33
AgIsoVirtualTerminal/include/InputNumberComponent.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//================================================================================================
|
||||
/// @file InputNumberComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an input number.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef INPUT_NUMBER_COMPONENT_HPP
|
||||
#define INPUT_NUMBER_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class InputNumberComponent : public isobus::InputNumber
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
InputNumberComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputNumber sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
static Justification convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification);
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InputNumberComponent)
|
||||
};
|
||||
|
||||
#endif // INPUT_NUMBER_COMPONENT_HPP
|
||||
33
AgIsoVirtualTerminal/include/InputStringComponent.hpp
Normal file
33
AgIsoVirtualTerminal/include/InputStringComponent.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//================================================================================================
|
||||
/// @file InputStringComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an input string.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef INPUT_STRING_COMPONENT_HPP
|
||||
#define INPUT_STRING_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class InputStringComponent : public isobus::InputString
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
InputStringComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputString sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
static Justification convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification);
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InputStringComponent)
|
||||
};
|
||||
|
||||
#endif // INPUT_STRING_COMPONENT_HPP
|
||||
39
AgIsoVirtualTerminal/include/JuceManagedWorkingSetCache.hpp
Normal file
39
AgIsoVirtualTerminal/include/JuceManagedWorkingSetCache.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
//================================================================================================
|
||||
/// @file JuceManagedWorkingSetCache.hpp
|
||||
///
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef JUCE_MANAGED_WORKING_SET_HPP
|
||||
#define JUCE_MANAGED_WORKING_SET_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
#include "SoftKeyMaskComponent.hpp"
|
||||
|
||||
class JuceManagedWorkingSetCache
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<Component> create_component(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, std::shared_ptr<isobus::VTObject> sourceObject);
|
||||
|
||||
static void set_softkey_mask_dimension_info(const SoftKeyMaskDimensions &info);
|
||||
|
||||
private:
|
||||
class ComponentCacheClass
|
||||
{
|
||||
public:
|
||||
ComponentCacheClass(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> associatedWorkingSet) :
|
||||
workingSet(associatedWorkingSet){};
|
||||
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet;
|
||||
//std::map<std::uint16_t, std::shared_ptr<Component>> componentLookup;
|
||||
};
|
||||
static std::vector<ComponentCacheClass> workingSetComponentCache;
|
||||
|
||||
static SoftKeyMaskDimensions softKeyDimensionInfo;
|
||||
static int dataAndAlarmMaskSize;
|
||||
};
|
||||
|
||||
#endif // JUCE_MANAGED_WORKING_SET_HPP
|
||||
32
AgIsoVirtualTerminal/include/KeyComponent.hpp
Normal file
32
AgIsoVirtualTerminal/include/KeyComponent.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//================================================================================================
|
||||
/// @file KeyComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a soft key.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef KEY_COMPONENT_HPP
|
||||
#define KEY_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class KeyComponent : public isobus::Key
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
KeyComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Key sourceObject, int keyWidth, int keyHeight);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(KeyComponent)
|
||||
};
|
||||
|
||||
#endif // KEY_COMPONENT_HPP
|
||||
0
AgIsoVirtualTerminal/include/KeyGroupComponent.hpp
Normal file
0
AgIsoVirtualTerminal/include/KeyGroupComponent.hpp
Normal file
42
AgIsoVirtualTerminal/include/LoggerComponent.hpp
Normal file
42
AgIsoVirtualTerminal/include/LoggerComponent.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//================================================================================================
|
||||
/// @file LoggerComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw log output.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef LOGGER_COMPONENT_HPP
|
||||
#define LOGGER_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/can_stack_logger.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
/// @brief Defines a GUI component that will draw log info sunk from the stack
|
||||
class LoggerComponent : public Component
|
||||
, public FileLogger
|
||||
, public isobus::CANStackLogger
|
||||
{
|
||||
public:
|
||||
LoggerComponent();
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
void sink_CAN_stack_log(LoggingLevel level, const std::string &logText) override;
|
||||
|
||||
private:
|
||||
struct LogData
|
||||
{
|
||||
String logText;
|
||||
isobus::CANStackLogger::LoggingLevel logLevel;
|
||||
};
|
||||
static constexpr std::size_t MAX_NUMBER_MESSAGES = 3000;
|
||||
std::deque<LogData> loggedMessages;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LoggerComponent)
|
||||
};
|
||||
|
||||
#endif // LOGGER_COMPONENT_HPP
|
||||
0
AgIsoVirtualTerminal/include/MacroComponent.hpp
Normal file
0
AgIsoVirtualTerminal/include/MacroComponent.hpp
Normal file
34
AgIsoVirtualTerminal/include/ObjectPointerComponent.hpp
Normal file
34
AgIsoVirtualTerminal/include/ObjectPointerComponent.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//================================================================================================
|
||||
/// @file ObjectPointerComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an object pointer.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OBJECT_POINTER_COMPONENT_HPP
|
||||
#define OBJECT_POINTER_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ObjectPointerComponent : public isobus::ObjectPointer
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
ObjectPointerComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::ObjectPointer sourceObject);
|
||||
|
||||
void on_content_changed(bool initial = false);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::shared_ptr<Component> childComponent;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ObjectPointerComponent)
|
||||
};
|
||||
|
||||
#endif // OBJECT_POINTER_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/OutputEllipseComponent.hpp
Normal file
31
AgIsoVirtualTerminal/include/OutputEllipseComponent.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file OutputEllipseComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an input number.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_ELLIPSE_COMPONENT_HPP
|
||||
#define OUTPUT_ELLIPSE_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputEllipseComponent : public isobus::OutputEllipse
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputEllipseComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputEllipse sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputEllipseComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_ELLIPSE_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/OutputLineComponent.hpp
Normal file
31
AgIsoVirtualTerminal/include/OutputLineComponent.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file OutputLineComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an output line.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_LINE_COMPONENT_HPP
|
||||
#define OUTPUT_LINE_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputLineComponent : public isobus::OutputLine
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputLineComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputLine sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputLineComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_LINE_COMPONENT_HPP
|
||||
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file OutputLinearBarGraphComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a linear bar graph.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_LINEAR_BAR_GRAPH_COMPONENT_HPP
|
||||
#define OUTPUT_LINEAR_BAR_GRAPH_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputLinearBarGraphComponent : public isobus::OutputLinearBarGraph
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputLinearBarGraphComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputLinearBarGraph sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputLinearBarGraphComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_LINEAR_BAR_GRAPH_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/OutputMeterComponent.hpp
Normal file
31
AgIsoVirtualTerminal/include/OutputMeterComponent.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file OutputMeterComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an output meter.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_METER_COMPONENT_HPP
|
||||
#define OUTPUT_METER_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputMeterComponent : public isobus::OutputMeter
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputMeterComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputMeter sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputMeterComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_METER_COMPONENT_HPP
|
||||
33
AgIsoVirtualTerminal/include/OutputNumberComponent.hpp
Normal file
33
AgIsoVirtualTerminal/include/OutputNumberComponent.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//================================================================================================
|
||||
/// @file OutputNumberComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an output number.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_NUMBER_COMPONENT_HPP
|
||||
#define OUTPUT_NUMBER_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputNumberComponent : public isobus::OutputNumber
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputNumberComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputNumber sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
static Justification convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification);
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputNumberComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_NUMBER_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/OutputPolygonComponent.hpp
Normal file
31
AgIsoVirtualTerminal/include/OutputPolygonComponent.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file OutputPolygonComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an output polygon.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_POLYGON_COMPONENT_HPP
|
||||
#define OUTPUT_POLYGON_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputPolygonComponent : public isobus::OutputPolygon
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputPolygonComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputPolygon sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputPolygonComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_POLYGON_COMPONENT_HPP
|
||||
31
AgIsoVirtualTerminal/include/OutputRectangleComponent.hpp
Normal file
31
AgIsoVirtualTerminal/include/OutputRectangleComponent.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//================================================================================================
|
||||
/// @file OutputRectangleComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an output rectangle.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_RECTANGLE_COMPONENT_HPP
|
||||
#define OUTPUT_RECTANGLE_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputRectangleComponent : public isobus::OutputRectangle
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputRectangleComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputRectangle sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputRectangleComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_RECTANGLE_COMPONENT_HPP
|
||||
33
AgIsoVirtualTerminal/include/OutputStringComponent.hpp
Normal file
33
AgIsoVirtualTerminal/include/OutputStringComponent.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//================================================================================================
|
||||
/// @file OutputStringComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw an output string.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef OUTPUT_STRING_COMPONENT_HPP
|
||||
#define OUTPUT_STRING_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class OutputStringComponent : public isobus::OutputString
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
OutputStringComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputString sourceObject);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
static Justification convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification);
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputStringComponent)
|
||||
};
|
||||
|
||||
#endif // OUTPUT_STRING_COMPONENT_HPP
|
||||
34
AgIsoVirtualTerminal/include/PictureGraphicComponent.hpp
Normal file
34
AgIsoVirtualTerminal/include/PictureGraphicComponent.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//================================================================================================
|
||||
/// @file PictureGraphicComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a picture graphic.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef PICTURE_GRAPHIC_COMPONENT_HPP
|
||||
#define PICTURE_GRAPHIC_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class PictureGraphicComponent : public isobus::PictureGraphic
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
PictureGraphicComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::PictureGraphic sourceObject);
|
||||
|
||||
void generate_and_store_image();
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
Image reconstructedImage;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PictureGraphicComponent)
|
||||
};
|
||||
|
||||
#endif // PICTURE_GRAPHIC_COMPONENT_HPP
|
||||
193
AgIsoVirtualTerminal/include/ServerMainComponent.hpp
Normal file
193
AgIsoVirtualTerminal/include/ServerMainComponent.hpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
|
||||
#include "ConfigureHardwareWindow.hpp"
|
||||
#include "DataMaskRenderAreaComponent.hpp"
|
||||
#include "LoggerComponent.hpp"
|
||||
#include "SoftKeyMaskComponent.hpp"
|
||||
#include "SoftKeyMaskRenderAreaComponent.hpp"
|
||||
#include "WorkingSetSelectorComponent.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
class ServerMainComponent : public juce::Component
|
||||
, public juce::KeyListener
|
||||
, public isobus::VirtualTerminalServer
|
||||
, public Timer
|
||||
, public ApplicationCommandTarget
|
||||
, public MenuBarModel
|
||||
{
|
||||
public:
|
||||
ServerMainComponent(std::shared_ptr<isobus::InternalControlFunction> serverControlFunction, std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &canDrivers);
|
||||
~ServerMainComponent() override;
|
||||
|
||||
bool get_is_enough_memory(std::uint32_t requestedMemory) const override;
|
||||
VTVersion get_version() const override;
|
||||
std::uint8_t get_number_of_navigation_soft_keys() const override;
|
||||
std::uint8_t get_soft_key_descriptor_x_pixel_width() const override;
|
||||
std::uint8_t get_soft_key_descriptor_y_pixel_height() const override;
|
||||
std::uint8_t get_number_of_possible_virtual_soft_keys_in_soft_key_mask() const override;
|
||||
std::uint8_t get_number_of_physical_soft_keys() const override;
|
||||
std::uint8_t get_physical_soft_key_rows() const;
|
||||
std::uint8_t get_physical_soft_key_columns() const;
|
||||
std::uint16_t get_data_mask_area_size_x_pixels() const override;
|
||||
std::uint16_t get_data_mask_area_size_y_pixels() const override;
|
||||
void suspend_working_set(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSetWithError) override;
|
||||
SupportedWideCharsErrorCode get_supported_wide_chars(std::uint8_t codePlane,
|
||||
std::uint16_t firstWideCharInInquiryRange,
|
||||
std::uint16_t lastWideCharInInquiryRange,
|
||||
std::uint8_t &numberOfRanges,
|
||||
std::vector<std::uint8_t> &wideCharRangeArray) override;
|
||||
|
||||
bool keyPressed(const juce::KeyPress &key, juce::Component *originatingComponent) override;
|
||||
bool keyStateChanged(bool isKeyDown, juce::Component *originatingComponent) override;
|
||||
|
||||
std::vector<std::array<std::uint8_t, 7>> get_versions(isobus::NAME clientNAME) override;
|
||||
std::vector<std::uint8_t> get_supported_objects() const override;
|
||||
|
||||
/// @brief This function is called when the client wants the server to load a previously stored object pool.
|
||||
/// If there exists in the VT's non-volatile memory an object pool matching the provided version label,
|
||||
/// return it. If one does not exist, return an empty vector.
|
||||
/// @param[in] versionLabel The object pool version to load for the given client NAME
|
||||
/// @param[in] clientNAME The client requesting the object pool
|
||||
/// @returns The requested object pool associated with the version label.
|
||||
std::vector<std::uint8_t> load_version(const std::vector<std::uint8_t> &versionLabel, isobus::NAME clientNAME) override;
|
||||
|
||||
/// @brief This function is called when the client wants the server to save an object pool
|
||||
/// to the VT's non-volatile memory.
|
||||
/// If the object pool is saved successfully, return true, otherwise return false.
|
||||
/// @note This may be called multiple times with the same version, but different data. When this
|
||||
/// happens, the expectation is that you will append each objectPool together into one large file.
|
||||
/// @param[in] objectPool The object pool data to save
|
||||
/// @param[in] versionLabel The object pool version to save for the given client NAME
|
||||
/// @param[in] clientNAME The client requesting the object pool
|
||||
/// @returns The requested object pool associated with the version label.
|
||||
bool save_version(const std::vector<std::uint8_t> &objectPool, const std::vector<std::uint8_t> &versionLabel, isobus::NAME clientNAME) override;
|
||||
|
||||
/// @brief This function is called when the client wants the server to delete a stored object pool.
|
||||
/// All object pool files matching the specified version label should then be deleted from the VT's
|
||||
/// non-volatile storage.
|
||||
/// @param[in] versionLabel The version label for the object pool(s) to delete
|
||||
/// @param[in] clientNAME The NAME of the client that is requesting deletion
|
||||
/// @returns True if the version was deleted from VT non-volatile storage, otherwise false.
|
||||
bool delete_version(const std::vector<std::uint8_t> &versionLabel, isobus::NAME clientNAME) override;
|
||||
|
||||
/// @brief This function is called when the client wants the server to delete ALL stored object pools associated to it's NAME.
|
||||
/// All object pool files matching the specified client NAME should then be deleted from the VT's
|
||||
/// non-volatile storage.
|
||||
/// @param[in] clientNAME The NAME of the client that is requesting deletion
|
||||
/// @returns True if all relevant object pools were deleted from VT non-volatile storage, otherwise false.
|
||||
bool delete_all_versions(isobus::NAME clientNAME) override;
|
||||
|
||||
/// @brief This function is called when the client wants the server to deactivate its object pool.
|
||||
/// You should treat this as a disconnection by the client, as it may be moving to another VT.
|
||||
/// @attention This does not mean to delete the pool from non-volatile memory!!! This only deactivates the active pool.
|
||||
/// @details This command is used to delete the entire object pool of this Working Set from volatile storage.
|
||||
/// This command can be used by an implement when it wants to move its object pool to another VT,
|
||||
/// or when it is shutting down or during the development of object pools.
|
||||
/// @param[in] clientNAME The NAME of the client that is requesting deletion
|
||||
/// @returns True if the client's active object pool was deactivated and removed from volatile storage, otherwise false.
|
||||
bool delete_object_pool(isobus::NAME clientNAME) override;
|
||||
|
||||
void timerCallback() override;
|
||||
|
||||
void paint(juce::Graphics &g) override;
|
||||
void resized() override;
|
||||
|
||||
ApplicationCommandTarget *getNextCommandTarget() override;
|
||||
void getAllCommands(juce::Array<juce::CommandID> &allCommands) override;
|
||||
void getCommandInfo(juce::CommandID commandID, ApplicationCommandInfo &result) override;
|
||||
bool perform(const InvocationInfo &info) override;
|
||||
StringArray getMenuBarNames() override;
|
||||
PopupMenu getMenuForIndex(int, const juce::String &) override;
|
||||
void menuItemSelected(int, int) override;
|
||||
|
||||
std::shared_ptr<isobus::ControlFunction> get_client_control_function_for_working_set(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet) const;
|
||||
|
||||
void change_selected_working_set(std::uint8_t index);
|
||||
|
||||
void set_button_held(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, std::uint16_t objectID, std::uint16_t maskObjectID, std::uint8_t keyCode, bool isSoftKey);
|
||||
void set_button_released(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, std::uint16_t objectID, std::uint16_t maskObjectID, std::uint8_t keyCode, bool isSoftKey);
|
||||
|
||||
void repaint_on_next_update();
|
||||
|
||||
void save_settings();
|
||||
|
||||
private:
|
||||
enum class CommandIDs : int
|
||||
{
|
||||
NoCommand = 0, /// 0 Is an invalid command ID
|
||||
About,
|
||||
ConfigureLanguageCommand,
|
||||
ConfigureReportedVersion,
|
||||
ConfigureReportedHardware,
|
||||
ConfigureLogging,
|
||||
ConfigureShortcuts,
|
||||
GenerateLogPackage,
|
||||
ClearISOData,
|
||||
ConfigureCANHardware,
|
||||
StartStop,
|
||||
AutoStart
|
||||
};
|
||||
|
||||
SoftKeyMaskDimensions softKeyMaskDimensions;
|
||||
|
||||
class LanguageCommandConfigClosed
|
||||
{
|
||||
public:
|
||||
void operator()(int result) const noexcept;
|
||||
ServerMainComponent &mParent;
|
||||
|
||||
private:
|
||||
};
|
||||
friend class LanguageCommandConfigClosed;
|
||||
|
||||
struct HeldButtonData
|
||||
{
|
||||
HeldButtonData(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, std::uint16_t objectID, std::uint16_t maskObjectID, std::uint8_t keyCode, bool isSoftKey);
|
||||
bool operator==(const HeldButtonData &other);
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> associatedWorkingSet;
|
||||
std::uint32_t timestamp_ms;
|
||||
std::uint16_t buttonObjectID;
|
||||
std::uint16_t activeMaskObjectID;
|
||||
std::uint8_t buttonKeyCode;
|
||||
bool isSoftKey;
|
||||
};
|
||||
|
||||
static VTVersion get_version_from_setting(std::uint8_t aVersion);
|
||||
|
||||
std::size_t number_of_iop_files_in_directory(std::filesystem::path path);
|
||||
|
||||
void on_change_active_mask_callback(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> affectedWorkingSet, std::uint16_t workingSet, std::uint16_t newMask);
|
||||
void repaint_data_and_soft_key_mask();
|
||||
void check_load_settings();
|
||||
void remove_working_set(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSetToRemove);
|
||||
void clear_iso_data();
|
||||
|
||||
const std::string ISO_DATA_PATH = "iso_data";
|
||||
|
||||
juce::ApplicationCommandManager mCommandManager;
|
||||
WorkingSetSelectorComponent workingSetSelector;
|
||||
DataMaskRenderAreaComponent dataMaskRenderer;
|
||||
SoftKeyMaskRenderAreaComponent softKeyMaskRenderer;
|
||||
MenuBarComponent menuBar;
|
||||
LoggerComponent logger;
|
||||
Viewport loggerViewport;
|
||||
SoundPlayer mSoundPlayer;
|
||||
AudioDeviceManager mAudioDeviceManager;
|
||||
std::unique_ptr<AlertWindow> popupMenu;
|
||||
std::unique_ptr<ConfigureHardwareWindow> configureHardwareWindow;
|
||||
std::shared_ptr<isobus::ControlFunction> alarmAckKeyWs;
|
||||
std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &parentCANDrivers;
|
||||
std::vector<HeldButtonData> heldButtons;
|
||||
std::uint32_t alarmAckKeyMaskId = isobus::NULL_OBJECT_ID;
|
||||
int alarmAckKeyCode = juce::KeyPress::escapeKey;
|
||||
std::uint8_t numberOfPoolsToRender = 0;
|
||||
VTVersion versionToReport = VTVersion::Version5;
|
||||
bool needToRepaint = false;
|
||||
bool autostart = false;
|
||||
bool hasStartBeenCalled = false;
|
||||
bool alarmAckKeyPressed = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ServerMainComponent)
|
||||
};
|
||||
34
AgIsoVirtualTerminal/include/ShortcutsWindow.hpp
Normal file
34
AgIsoVirtualTerminal/include/ShortcutsWindow.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//================================================================================================
|
||||
/// @file ShortcutsWindow.hpp
|
||||
///
|
||||
/// @brief Defines a dialog where keyboard shortcuts could be selected
|
||||
/// @author Miklos Marton
|
||||
///
|
||||
/// @copyright The Open-Agriculture Developers
|
||||
//================================================================================================
|
||||
#pragma once
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ShortcutsWindow : public juce::AlertWindow
|
||||
, public juce::KeyListener
|
||||
{
|
||||
public:
|
||||
ShortcutsWindow(int alarmAckKeyCode, Component *associatedComponent = nullptr);
|
||||
|
||||
void resized() override;
|
||||
bool keyPressed(const juce::KeyPress &key, juce::Component *originatingComponent) override;
|
||||
int alarmAckKeyCode() const;
|
||||
|
||||
private:
|
||||
juce::TextButton selectAlarmAckKeyButton;
|
||||
int alarmAckKey = juce::KeyPress::escapeKey;
|
||||
|
||||
bool keySelectionMode = false;
|
||||
|
||||
void updateAlarmAckButtonLabel(const juce::KeyPress &key);
|
||||
|
||||
void setAlarmAckKeySelection(bool isEnabled);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ShortcutsWindow)
|
||||
};
|
||||
60
AgIsoVirtualTerminal/include/SoftKeyMaskComponent.hpp
Normal file
60
AgIsoVirtualTerminal/include/SoftKeyMaskComponent.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
//================================================================================================
|
||||
/// @file SoftKeyMaskComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a soft key mask.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef SOFT_KEY_MASK_COMPONENT_HPP
|
||||
#define SOFT_KEY_MASK_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class SoftKeyMaskDimensions
|
||||
{
|
||||
public:
|
||||
SoftKeyMaskDimensions() = default;
|
||||
|
||||
/**
|
||||
* @brief total_width
|
||||
* @return The total width of the softkeymask (including inner and outer column paddings)
|
||||
*/
|
||||
int total_width() const;
|
||||
|
||||
/**
|
||||
* @brief key_count
|
||||
* @return the number of the possible key positions in the softkey mask
|
||||
*/
|
||||
int key_count() const;
|
||||
|
||||
int keyHeight = 60;
|
||||
int keyWidth = 60;
|
||||
int rowCount = 6;
|
||||
int columnCount = 1;
|
||||
int height = 480;
|
||||
static constexpr std::uint8_t PADDING = 10;
|
||||
};
|
||||
|
||||
class SoftKeyMaskComponent : public isobus::SoftKeyMask
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
SoftKeyMaskComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::SoftKeyMask sourceObject, SoftKeyMaskDimensions dimensions);
|
||||
|
||||
void on_content_changed(bool initial = false);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
SoftKeyMaskDimensions dimensionInfo;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SoftKeyMaskComponent)
|
||||
};
|
||||
|
||||
#endif // SOFT_KEY_MASK_COMPONENT_HPP
|
||||
@@ -0,0 +1,48 @@
|
||||
//================================================================================================
|
||||
/// @file SoftKeyMaskRenderAreaComponent.hpp
|
||||
///
|
||||
/// @brief A component to hold all the data mask render components.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef SOFT_KEY_MASK_RENDER_AREA_COMPONENT_HPP
|
||||
#define SOFT_KEY_MASK_RENDER_AREA_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class ServerMainComponent;
|
||||
|
||||
class SoftKeyMaskRenderAreaComponent : public Component
|
||||
{
|
||||
public:
|
||||
SoftKeyMaskRenderAreaComponent(ServerMainComponent &parentServer);
|
||||
|
||||
void on_change_active_mask(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet);
|
||||
|
||||
void on_working_set_disconnect(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
// Used to calculate button press events
|
||||
void mouseDown(const MouseEvent &event) override;
|
||||
|
||||
// Used to calculate button release events
|
||||
void mouseUp(const MouseEvent &event) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VTObject> getClickedChildRecursive(std::shared_ptr<isobus::VTObject> object, int x, int y);
|
||||
static bool objectCanBeClicked(std::shared_ptr<isobus::VTObject> object);
|
||||
static bool isClickWithinBounds(int clickXRelative, int clickYRelative, int objectX, int objectY, int objectWidth, int objectHeight);
|
||||
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
ServerMainComponent &ownerServer;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SoftKeyMaskRenderAreaComponent)
|
||||
};
|
||||
|
||||
#endif // SOFT_KEY_MASK_RENDER_AREA_COMPONENT_HPP
|
||||
26
AgIsoVirtualTerminal/include/StringEncodingConversions.hpp
Normal file
26
AgIsoVirtualTerminal/include/StringEncodingConversions.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//================================================================================================
|
||||
/// @file StringEncodingConversions.hpp
|
||||
///
|
||||
/// @brief Helper functions for converting ISO 11783's string encodings to UTF-8
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2024 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef STRING_ENCODING_CONVERSIONS_HPP
|
||||
#define STRING_ENCODING_CONVERSIONS_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class SourceEncoding
|
||||
{
|
||||
ISO8859_1,
|
||||
ISO8859_2,
|
||||
ISO8859_4,
|
||||
ISO8859_5,
|
||||
ISO8859_7,
|
||||
ISO8859_15
|
||||
};
|
||||
|
||||
void convert_string_to_utf_8(SourceEncoding encoding, const std::string &input, std::string &output, bool autoWrappingEnabled);
|
||||
|
||||
#endif // STRING_ENCODING_CONVERSIONS_HPP
|
||||
32
AgIsoVirtualTerminal/include/WorkingSetComponent.hpp
Normal file
32
AgIsoVirtualTerminal/include/WorkingSetComponent.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//================================================================================================
|
||||
/// @file WorkingSetComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component to draw a working set designator.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef WORKING_SET_COMPONENT_HPP
|
||||
#define WORKING_SET_COMPONENT_HPP
|
||||
|
||||
#include "isobus/isobus/isobus_virtual_terminal_objects.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
class WorkingSetComponent : public isobus::WorkingSet
|
||||
, public Component
|
||||
{
|
||||
public:
|
||||
WorkingSetComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::WorkingSet sourceObject, int keyHeight, int keyWidth);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> parentWorkingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WorkingSetComponent)
|
||||
};
|
||||
|
||||
#endif // WORKING_SET_COMPONENT_HPP
|
||||
46
AgIsoVirtualTerminal/include/WorkingSetSelectorComponent.hpp
Normal file
46
AgIsoVirtualTerminal/include/WorkingSetSelectorComponent.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//================================================================================================
|
||||
/// @file WorkingSetSelectorComponent.hpp
|
||||
///
|
||||
/// @brief Defines a GUI component allow selecting the active working set.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#ifndef WORKING_SET_SELECTOR_COMPONENT_HPP
|
||||
#define WORKING_SET_SELECTOR_COMPONENT_HPP
|
||||
|
||||
#include "WorkingSetComponent.hpp"
|
||||
#include "isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ServerMainComponent;
|
||||
|
||||
class WorkingSetSelectorComponent : public Component
|
||||
{
|
||||
public:
|
||||
explicit WorkingSetSelectorComponent(ServerMainComponent &server);
|
||||
|
||||
void update_drawn_working_sets(std::vector<std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet>> &managedWorkingSetList);
|
||||
|
||||
void paint(Graphics &g) override;
|
||||
void resized() override;
|
||||
void mouseUp(const MouseEvent &event) override;
|
||||
|
||||
void redraw();
|
||||
|
||||
private:
|
||||
struct SELECTOR_CHILD_OBJECTS_STRUCT
|
||||
{
|
||||
std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet;
|
||||
std::vector<std::shared_ptr<Component>> childComponents;
|
||||
};
|
||||
std::vector<SELECTOR_CHILD_OBJECTS_STRUCT> children;
|
||||
ServerMainComponent &parentServer;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WorkingSetSelectorComponent)
|
||||
};
|
||||
|
||||
#endif // WORKING_SET_SELECTOR_COMPONENT_HPP
|
||||
111
AgIsoVirtualTerminal/src/ASCIILogFile.cpp
Normal file
111
AgIsoVirtualTerminal/src/ASCIILogFile.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*******************************************************************************
|
||||
** @file ASCIILogFile.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "ASCIILogFile.hpp"
|
||||
|
||||
#include "isobus/utility/system_timing.hpp"
|
||||
#include "isobus/utility/to_string.hpp"
|
||||
|
||||
ASCIILogFile::ASCIILogFile()
|
||||
{
|
||||
auto currentTime = Time::getCurrentTime().toString(true, true, true, false);
|
||||
initialTimestamp = Time::getCurrentTime();
|
||||
auto fileNameTime = currentTime;
|
||||
fileNameTime = currentTime.replaceCharacter(' ', '_');
|
||||
fileNameTime = currentTime.replaceCharacter(':', '_');
|
||||
|
||||
logFile = File(File::getSpecialLocation(File::userApplicationDataDirectory).getFullPathName() +
|
||||
File::getSeparatorString() +
|
||||
"Open-Agriculture" +
|
||||
File::getSeparatorString() +
|
||||
"CANLog_" +
|
||||
fileNameTime +
|
||||
".asc");
|
||||
|
||||
// Prune old log files
|
||||
auto logDirectory = logFile.getParentDirectory();
|
||||
auto childFiles = logDirectory.findChildFiles(File::findFiles, false, "*.asc");
|
||||
|
||||
for (auto &file : childFiles)
|
||||
{
|
||||
if (file.getCreationTime() < Time::getCurrentTime() - RelativeTime::days(3))
|
||||
{
|
||||
file.deleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
// Write vector ascii header
|
||||
if (logFile.hasWriteAccess())
|
||||
{
|
||||
logFile.appendText("date " + currentTime + "\n");
|
||||
logFile.appendText("base hex timestamps absolute\n");
|
||||
logFile.appendText("no internal events logged\n");
|
||||
canFrameReceivedListener = isobus::CANHardwareInterface::get_can_frame_received_event_dispatcher().add_listener([this](const isobus::CANMessageFrame &canFrame) {
|
||||
logFile.appendText(" ");
|
||||
auto currentTime = Time::getCurrentTime() - initialTimestamp;
|
||||
auto milliseconds = isobus::to_string(currentTime.inMilliseconds() % 1000);
|
||||
|
||||
while (milliseconds.length() < 3)
|
||||
{
|
||||
milliseconds = "0" + milliseconds;
|
||||
}
|
||||
|
||||
logFile.appendText(isobus::to_string(std::floor(currentTime.inSeconds())) +
|
||||
"." +
|
||||
milliseconds +
|
||||
"000 1 " +
|
||||
String::toHexString(canFrame.identifier).toUpperCase().toStdString() +
|
||||
"x Rx d " +
|
||||
isobus::to_string(static_cast<int>(canFrame.dataLength)) +
|
||||
" ");
|
||||
|
||||
for (std::uint_fast8_t i = 0; i < canFrame.dataLength; i++)
|
||||
{
|
||||
logFile.appendText(String::toHexString(canFrame.data[i]).paddedLeft('0', 2).toUpperCase().toStdString() + " ");
|
||||
}
|
||||
|
||||
for (std::uint_fast8_t i = canFrame.dataLength; i < 8; i++)
|
||||
{
|
||||
logFile.appendText("00 ");
|
||||
}
|
||||
logFile.appendText("\n");
|
||||
});
|
||||
|
||||
canFrameSentListener = isobus::CANHardwareInterface::get_can_frame_transmitted_event_dispatcher().add_listener([this](const isobus::CANMessageFrame &canFrame) {
|
||||
logFile.appendText(" ");
|
||||
auto currentTime = Time::getCurrentTime() - initialTimestamp;
|
||||
auto milliseconds = isobus::to_string(currentTime.inMilliseconds() % 1000);
|
||||
|
||||
while (milliseconds.length() < 3)
|
||||
{
|
||||
milliseconds = "0" + milliseconds;
|
||||
}
|
||||
|
||||
logFile.appendText(isobus::to_string(std::floor(currentTime.inSeconds())) +
|
||||
"." +
|
||||
milliseconds +
|
||||
"000 1 " +
|
||||
String::toHexString(canFrame.identifier).toUpperCase().toStdString() +
|
||||
"x Tx d " +
|
||||
isobus::to_string(static_cast<int>(canFrame.dataLength)) +
|
||||
" ");
|
||||
|
||||
for (std::uint_fast8_t i = 0; i < canFrame.dataLength; i++)
|
||||
{
|
||||
logFile.appendText(String::toHexString(canFrame.data[i]).paddedLeft('0', 2).toUpperCase().toStdString() + " ");
|
||||
}
|
||||
|
||||
for (std::uint_fast8_t i = canFrame.dataLength; i < 8; i++)
|
||||
{
|
||||
logFile.appendText("00 ");
|
||||
}
|
||||
logFile.appendText("\n");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimePermissions::request(RuntimePermissions::writeExternalStorage, nullptr);
|
||||
}
|
||||
}
|
||||
12
AgIsoVirtualTerminal/src/AlarmMaskAudio.cpp
Normal file
12
AgIsoVirtualTerminal/src/AlarmMaskAudio.cpp
Normal file
File diff suppressed because one or more lines are too long
47
AgIsoVirtualTerminal/src/AlarmMaskComponent.cpp
Normal file
47
AgIsoVirtualTerminal/src/AlarmMaskComponent.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*******************************************************************************
|
||||
** @file AlarmMaskComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "AlarmMaskComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
AlarmMaskComponent::AlarmMaskComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::AlarmMask sourceObject, int dataMaskSize) :
|
||||
isobus::AlarmMask(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setOpaque(true);
|
||||
setBounds(0, 0, dataMaskSize, dataMaskSize);
|
||||
on_content_changed(true);
|
||||
}
|
||||
|
||||
void AlarmMaskComponent::on_content_changed(bool initial)
|
||||
{
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask != child->get_object_type()))
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
childComponents.back()->setTopLeftPosition(get_child_x(i), get_child_y(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmMaskComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
9
AgIsoVirtualTerminal/src/AppImages.cpp
Normal file
9
AgIsoVirtualTerminal/src/AppImages.cpp
Normal file
File diff suppressed because one or more lines are too long
75
AgIsoVirtualTerminal/src/ButtonComponent.cpp
Normal file
75
AgIsoVirtualTerminal/src/ButtonComponent.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
** @file ButtonComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "ButtonComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
ButtonComponent::ButtonComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Button sourceObject) :
|
||||
isobus::Button(sourceObject),
|
||||
juce::Button(""),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setOpaque(false);
|
||||
setSize(get_width(), get_height());
|
||||
|
||||
auto borderOffset = get_option(Options::NoBorder) ? 0 : 4;
|
||||
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
childComponents.back()->setTopLeftPosition(get_child_x(i) + borderOffset, get_child_y(i) + borderOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
|
||||
if (true == get_option(Options::TransparentBackground))
|
||||
{
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 0.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
|
||||
if (false == get_option(Options::NoBorder) && false == get_option(Options::SuppressBorder))
|
||||
{
|
||||
vtColour = parentWorkingSet->get_colour(get_border_colour());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
g.drawRect(0, 0, get_width(), get_height(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonComponent::paintButton(Graphics &, bool, bool)
|
||||
{
|
||||
}
|
||||
|
||||
void ButtonComponent::set_options(uint8_t value)
|
||||
{
|
||||
// adjust the position of the childs to the button face area if the NoBorder attribute is changed
|
||||
if ((value & static_cast<uint8_t>(Options::NoBorder)) != get_option(Options::NoBorder))
|
||||
{
|
||||
auto borderOffset = (0 != (value & static_cast<uint8_t>(Options::NoBorder))) ? -4 : 4;
|
||||
int i = 0;
|
||||
for (auto &child : childComponents)
|
||||
{
|
||||
child->setTopLeftPosition(get_child_x(i) + borderOffset, get_child_y(i) + borderOffset);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return isobus::Button::set_options(value);
|
||||
}
|
||||
130
AgIsoVirtualTerminal/src/ConfigureHardwareComponent.cpp
Normal file
130
AgIsoVirtualTerminal/src/ConfigureHardwareComponent.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*******************************************************************************
|
||||
** @file ConfigureHardwareComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "ConfigureHardwareComponent.hpp"
|
||||
|
||||
#include "ConfigureHardwareWindow.hpp"
|
||||
#include "ServerMainComponent.hpp"
|
||||
#include "isobus/isobus/can_stack_logger.hpp"
|
||||
#include "isobus/utility/to_string.hpp"
|
||||
|
||||
#ifdef JUCE_WINDOWS
|
||||
#include "isobus/hardware_integration/toucan_vscp_canal.hpp"
|
||||
#elif JUCE_LINUX
|
||||
#include "isobus/hardware_integration/socket_can_interface.hpp"
|
||||
#endif
|
||||
|
||||
ConfigureHardwareComponent::ConfigureHardwareComponent(ConfigureHardwareWindow &parent, std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &canDrivers) :
|
||||
okButton("OK"),
|
||||
parentCANDrivers(canDrivers)
|
||||
{
|
||||
setSize(400, 280);
|
||||
okButton.setSize(100, 30);
|
||||
okButton.setTopLeftPosition(getWidth() / 2 - okButton.getWidth() / 2, 200);
|
||||
addAndMakeVisible(okButton);
|
||||
|
||||
#ifdef JUCE_WINDOWS
|
||||
hardwareInterfaceSelector.setName("Hardware Interface");
|
||||
hardwareInterfaceSelector.setTextWhenNothingSelected("Select Hardware Interface");
|
||||
|
||||
#ifdef ISOBUS_WINDOWSINNOMAKERUSB2CAN_AVAILABLE
|
||||
hardwareInterfaceSelector.addItemList({ "PEAK PCAN USB", "Innomaker2CAN", "TouCAN", "SysTec" }, 1);
|
||||
#else
|
||||
hardwareInterfaceSelector.addItemList({ "PEAK PCAN USB", "Innomaker2CAN (not supported with mingw)", "TouCAN", "SysTec" }, 1);
|
||||
#endif
|
||||
int selectedID = 1;
|
||||
|
||||
for (std::uint8_t i = 0; i < parentCANDrivers.size(); i++)
|
||||
{
|
||||
if ((nullptr != parentCANDrivers.at(i)) &&
|
||||
(parentCANDrivers.at(i) == isobus::CANHardwareInterface::get_assigned_can_channel_frame_handler(0)))
|
||||
{
|
||||
selectedID = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hardwareInterfaceSelector.setSelectedId(selectedID);
|
||||
hardwareInterfaceSelector.setSize(getWidth() - 20, 30);
|
||||
hardwareInterfaceSelector.setTopLeftPosition(10, 80);
|
||||
hardwareInterfaceSelector.onChange = [this]() {
|
||||
if (3 == hardwareInterfaceSelector.getSelectedId())
|
||||
{
|
||||
touCANSerialEditor.setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
touCANSerialEditor.setVisible(false);
|
||||
}
|
||||
repaint();
|
||||
};
|
||||
addAndMakeVisible(hardwareInterfaceSelector);
|
||||
|
||||
auto inputFilter = new TextEditor::LengthAndCharacterRestriction(10, "1234567890");
|
||||
touCANSerialEditor.setName("TouCAN Serial Number");
|
||||
touCANSerialEditor.setText(isobus::to_string(std::static_pointer_cast<isobus::TouCANPlugin>(parentCANDrivers.at(2))->get_serial_number()));
|
||||
touCANSerialEditor.setSize(getWidth() - 20, 30);
|
||||
touCANSerialEditor.setTopLeftPosition(10, 140);
|
||||
touCANSerialEditor.setInputFilter(inputFilter, true);
|
||||
addChildComponent(touCANSerialEditor);
|
||||
#elif JUCE_LINUX
|
||||
socketCANNameEditor.setName("SocketCAN Interface Name");
|
||||
socketCANNameEditor.setText(std::static_pointer_cast<isobus::SocketCANInterface>(parentCANDrivers.at(0))->get_device_name());
|
||||
socketCANNameEditor.setSize(getWidth() - 20, 30);
|
||||
socketCANNameEditor.setTopLeftPosition(10, 80);
|
||||
addAndMakeVisible(socketCANNameEditor);
|
||||
#endif
|
||||
okButton.onClick = [this, &parent]() {
|
||||
parent.setVisible(false);
|
||||
|
||||
#ifdef JUCE_WINDOWS
|
||||
if (3 == hardwareInterfaceSelector.getSelectedId()) // TouCAN
|
||||
{
|
||||
int serial = touCANSerialEditor.getText().trim().getIntValue();
|
||||
std::static_pointer_cast<isobus::TouCANPlugin>(parentCANDrivers.at(hardwareInterfaceSelector.getSelectedId() - 1))->reconfigure(0, static_cast<std::uint32_t>(serial));
|
||||
}
|
||||
|
||||
if (nullptr != isobus::CANHardwareInterface::get_assigned_can_channel_frame_handler(0))
|
||||
{
|
||||
isobus::CANHardwareInterface::unassign_can_channel_frame_handler(0);
|
||||
}
|
||||
isobus::CANHardwareInterface::assign_can_channel_frame_handler(0, parentCANDrivers.at(hardwareInterfaceSelector.getSelectedId() - 1));
|
||||
isobus::CANStackLogger::info("Updated assigned CAN driver.");
|
||||
#elif JUCE_LINUX
|
||||
std::static_pointer_cast<isobus::SocketCANInterface>(parentCANDrivers.at(0))->set_name(socketCANNameEditor.getText().toStdString());
|
||||
isobus::CANStackLogger::info("Updated socket CAN interface name to: " + socketCANNameEditor.getText().toStdString());
|
||||
#endif
|
||||
parent.parentServer.save_settings();
|
||||
};
|
||||
}
|
||||
|
||||
void ConfigureHardwareComponent::paint(Graphics &graphics)
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
graphics.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
|
||||
graphics.setColour(getLookAndFeel().findColour(Label::textColourId));
|
||||
graphics.setFont(16.0f);
|
||||
#ifdef JUCE_WINDOWS
|
||||
graphics.drawFittedText("Select the CAN driver to use", 10, 10, bounds.getWidth() - 20, 54, Justification::centredTop, 3);
|
||||
#elif JUCE_LINUX
|
||||
graphics.drawFittedText("Enter the name of the CAN interface to use (like \"can0\")", 10, 10, bounds.getWidth() - 20, 54, Justification::centredTop, 3);
|
||||
#endif
|
||||
|
||||
graphics.setFont(12.0f);
|
||||
|
||||
#ifdef JUCE_WINDOWS
|
||||
graphics.drawFittedText("Hardware Driver", hardwareInterfaceSelector.getBounds().getX(), hardwareInterfaceSelector.getBounds().getY() - 14, hardwareInterfaceSelector.getBounds().getWidth(), 12, Justification::centredLeft, 1);
|
||||
|
||||
if (3 == hardwareInterfaceSelector.getSelectedId())
|
||||
{
|
||||
graphics.drawFittedText("TouCAN Serial Number", touCANSerialEditor.getBounds().getX(), touCANSerialEditor.getBounds().getY() - 14, touCANSerialEditor.getBounds().getWidth(), 12, Justification::centredLeft, 1);
|
||||
}
|
||||
#elif JUCE_LINUX
|
||||
graphics.drawFittedText("Socket CAN Interface Name", socketCANNameEditor.getBounds().getX(), socketCANNameEditor.getBounds().getY() - 14, socketCANNameEditor.getBounds().getWidth(), 12, Justification::centredLeft, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConfigureHardwareComponent::resized()
|
||||
{
|
||||
}
|
||||
23
AgIsoVirtualTerminal/src/ConfigureHardwareWindow.cpp
Normal file
23
AgIsoVirtualTerminal/src/ConfigureHardwareWindow.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
** @file ConfigureHardwareWindow.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
|
||||
#include "ConfigureHardwareWindow.hpp"
|
||||
|
||||
ConfigureHardwareWindow::ConfigureHardwareWindow(ServerMainComponent &parentComponent, std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> &canDrivers) :
|
||||
DocumentWindow("Configure Hardware", juce::Desktop::getInstance().getDefaultLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId), DocumentWindow::closeButton),
|
||||
parentServer(parentComponent),
|
||||
content(*this, canDrivers)
|
||||
{
|
||||
setOpaque(true);
|
||||
setSize(400, 280);
|
||||
content.setSize(400, 280);
|
||||
setContentNonOwned(&content, false);
|
||||
}
|
||||
|
||||
void ConfigureHardwareWindow::closeButtonPressed()
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
65
AgIsoVirtualTerminal/src/ContainerComponent.cpp
Normal file
65
AgIsoVirtualTerminal/src/ContainerComponent.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*******************************************************************************
|
||||
** @file ContainerComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "ContainerComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
ContainerComponent::ContainerComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Container sourceObject) :
|
||||
isobus::Container(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
setOpaque(false);
|
||||
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
if (get_hidden())
|
||||
{
|
||||
addChildComponent(*childComponents.back());
|
||||
}
|
||||
else
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
}
|
||||
childComponents.back()->setTopLeftPosition(get_child_x(i), get_child_y(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContainerComponent::paint(Graphics &)
|
||||
{
|
||||
// g.fillAll(Colour::fromFloatRGBA(0.0, 0.0, 0.0, 0.0));
|
||||
if (get_hidden())
|
||||
{
|
||||
for (auto &child : childComponents)
|
||||
{
|
||||
if (nullptr != child)
|
||||
{
|
||||
child->setVisible(false);
|
||||
}
|
||||
}
|
||||
this->setVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &child : childComponents)
|
||||
{
|
||||
if (nullptr != child)
|
||||
{
|
||||
child->setVisible(true);
|
||||
}
|
||||
}
|
||||
this->setVisible(true);
|
||||
}
|
||||
}
|
||||
47
AgIsoVirtualTerminal/src/DataMaskComponent.cpp
Normal file
47
AgIsoVirtualTerminal/src/DataMaskComponent.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*******************************************************************************
|
||||
** @file DataMaskComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "DataMaskComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
DataMaskComponent::DataMaskComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::DataMask sourceObject, int dataMaskSize) :
|
||||
isobus::DataMask(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setOpaque(true);
|
||||
setBounds(0, 0, dataMaskSize, dataMaskSize);
|
||||
on_content_changed(true);
|
||||
}
|
||||
|
||||
void DataMaskComponent::on_content_changed(bool initial)
|
||||
{
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask != child->get_object_type()))
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
childComponents.back()->setTopLeftPosition(get_child_x(i), get_child_y(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void DataMaskComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
671
AgIsoVirtualTerminal/src/DataMaskRenderAreaComponent.cpp
Normal file
671
AgIsoVirtualTerminal/src/DataMaskRenderAreaComponent.cpp
Normal file
@@ -0,0 +1,671 @@
|
||||
/*******************************************************************************
|
||||
** @file DataMaskRenderAreaComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "DataMaskRenderAreaComponent.hpp"
|
||||
#include "AppImages.h"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
#include "ServerMainComponent.hpp"
|
||||
|
||||
DataMaskRenderAreaComponent::DataMaskRenderAreaComponent(ServerMainComponent &parentServer) :
|
||||
ownerServer(parentServer)
|
||||
{
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::on_change_active_mask(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet)
|
||||
{
|
||||
needToRepaintActiveArea = false;
|
||||
childComponents.clear();
|
||||
parentWorkingSet = workingSet;
|
||||
|
||||
if (parentWorkingSet)
|
||||
{
|
||||
auto workingSetObject = std::static_pointer_cast<isobus::WorkingSet>(parentWorkingSet->get_working_set_object());
|
||||
|
||||
if ((nullptr != workingSetObject) && (isobus::NULL_OBJECT_ID != workingSetObject->get_active_mask()))
|
||||
{
|
||||
auto activeMask = parentWorkingSet->get_object_by_id(workingSetObject->get_active_mask());
|
||||
childComponents.emplace_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, activeMask));
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::on_working_set_disconnect(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet)
|
||||
{
|
||||
if ((nullptr != workingSet) && (parentWorkingSet == workingSet))
|
||||
{
|
||||
childComponents.clear();
|
||||
parentWorkingSet.reset();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::paint(Graphics &g)
|
||||
{
|
||||
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
|
||||
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
g.drawRect(0, 0, getWidth(), getHeight(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto logoImage = ImageCache::getFromMemory(AppImages::logo2_png, AppImages::logo2_pngSize);
|
||||
g.drawImage(logoImage, 0, 0, 400, 400, 0, 0, logoImage.getWidth(), logoImage.getHeight());
|
||||
g.setColour(Colours::white);
|
||||
g.drawText("No Working Sets Are Active", 0, 400, 400, 80, Justification::centredTop, true);
|
||||
|
||||
if (!hasStarted)
|
||||
{
|
||||
g.drawFittedText("To start the VT server, select \"Start/Stop\" from the control menu in the top left.", 0, 440, 400, 40, Justification::centredTop, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::mouseDown(const MouseEvent &event)
|
||||
{
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
// Do a top down search to see if they clicked on some interactable object
|
||||
auto workingSetObject = std::static_pointer_cast<isobus::WorkingSet>(parentWorkingSet->get_working_set_object());
|
||||
|
||||
if (nullptr != workingSetObject)
|
||||
{
|
||||
auto activeMask = parentWorkingSet->get_object_by_id(workingSetObject->get_active_mask());
|
||||
|
||||
auto relativeEvent = event.getEventRelativeTo(this);
|
||||
auto clickedObject = getClickedChildRecursive(activeMask, relativeEvent.getMouseDownX(), relativeEvent.getMouseDownY());
|
||||
|
||||
std::uint8_t keyCode = 1;
|
||||
|
||||
if (nullptr != clickedObject)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::Button == clickedObject->get_object_type())
|
||||
{
|
||||
keyCode = std::static_pointer_cast<isobus::Button>(clickedObject)->get_key_code();
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnKeyPress, isobus::VirtualTerminalObjectType::Button, parentWorkingSet);
|
||||
}
|
||||
else if (isobus::VirtualTerminalObjectType::Key == clickedObject->get_object_type())
|
||||
{
|
||||
keyCode = std::static_pointer_cast<isobus::Key>(clickedObject)->get_key_code();
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnKeyPress, isobus::VirtualTerminalObjectType::Key, parentWorkingSet);
|
||||
}
|
||||
|
||||
ownerServer.send_button_activation_message(isobus::VirtualTerminalBase::KeyActivationCode::ButtonPressedOrLatched,
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
ownerServer.get_active_working_set()->get_control_function());
|
||||
if (isobus::VirtualTerminalObjectType::Key == clickedObject->get_object_type() ||
|
||||
isobus::VirtualTerminalObjectType::Button == clickedObject->get_object_type())
|
||||
{
|
||||
ownerServer.set_button_held(ownerServer.get_active_working_set(),
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
(isobus::VirtualTerminalObjectType::Key == clickedObject->get_object_type()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used to calculate button release events
|
||||
void DataMaskRenderAreaComponent::mouseUp(const MouseEvent &event)
|
||||
{
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
// Do a top down search to see if they clicked on some interactable object
|
||||
auto workingSetObject = std::static_pointer_cast<isobus::WorkingSet>(parentWorkingSet->get_working_set_object());
|
||||
|
||||
if (nullptr != workingSetObject)
|
||||
{
|
||||
auto activeMask = parentWorkingSet->get_object_by_id(workingSetObject->get_active_mask());
|
||||
|
||||
auto relativeEvent = event.getEventRelativeTo(this);
|
||||
auto clickedObject = getClickedChildRecursive(activeMask, relativeEvent.getMouseDownX(), relativeEvent.getMouseDownY());
|
||||
|
||||
std::uint8_t keyCode = 1;
|
||||
|
||||
if (nullptr != clickedObject)
|
||||
{
|
||||
switch (clickedObject->get_object_type())
|
||||
{
|
||||
case isobus::VirtualTerminalObjectType::Button:
|
||||
{
|
||||
if (false == std::static_pointer_cast<isobus::Button>(clickedObject)->get_option(isobus::Button::Options::Disabled))
|
||||
{
|
||||
keyCode = std::static_pointer_cast<isobus::Button>(clickedObject)->get_key_code();
|
||||
ownerServer.send_button_activation_message(isobus::VirtualTerminalBase::KeyActivationCode::ButtonUnlatchedOrReleased,
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
ownerServer.get_active_working_set()->get_control_function());
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnKeyRelease, isobus::VirtualTerminalObjectType::Button, parentWorkingSet);
|
||||
ownerServer.set_button_released(ownerServer.get_active_working_set(),
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::Key:
|
||||
{
|
||||
keyCode = std::static_pointer_cast<isobus::Key>(clickedObject)->get_key_code();
|
||||
ownerServer.send_button_activation_message(isobus::VirtualTerminalBase::KeyActivationCode::ButtonUnlatchedOrReleased,
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
ownerServer.get_active_working_set()->get_control_function());
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnKeyRelease, isobus::VirtualTerminalObjectType::Key, parentWorkingSet);
|
||||
ownerServer.set_button_released(ownerServer.get_active_working_set(),
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
true);
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputList:
|
||||
{
|
||||
auto clickedList = std::static_pointer_cast<isobus::InputList>(clickedObject);
|
||||
|
||||
if ((clickedList->get_option(isobus::InputList::Options::Enabled)) &&
|
||||
(clickedList->get_number_children() > 0) &&
|
||||
clickedList->get_option(isobus::InputList::Options::Enabled))
|
||||
{
|
||||
// Need to display a modal combo selection
|
||||
inputListModal.reset(new AlertWindow("Input List Selection", "Select a List Item, then press OK.", MessageBoxIconType::QuestionIcon));
|
||||
inputListModal->addComboBox("Input List Combo", StringArray());
|
||||
currentModalComponentCache.clear();
|
||||
currentModalComponentCache.reserve(clickedList->get_number_children());
|
||||
|
||||
// In order to handle things that are not strings being allowed in an input list, grab the popup menu itself and shove custom components in there
|
||||
auto combo = inputListModal->getComboBoxComponent("Input List Combo");
|
||||
auto comboPopup = combo->getRootMenu();
|
||||
|
||||
auto selectedIndex = -1;
|
||||
|
||||
if (clickedList->get_variable_reference() != isobus::NULL_OBJECT_ID)
|
||||
{
|
||||
auto referencedVariable = clickedList->get_object_by_id(clickedList->get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != referencedVariable)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::NumberVariable == referencedVariable->get_object_type())
|
||||
{
|
||||
selectedIndex = std::static_pointer_cast<isobus::NumberVariable>(referencedVariable)->get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedIndex = clickedList->get_value();
|
||||
}
|
||||
|
||||
for (std::uint32_t i = 0; i < clickedList->get_number_children(); i++)
|
||||
{
|
||||
auto child = clickedList->get_object_by_id(clickedList->get_child_id(static_cast<std::uint16_t>(i)), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
currentModalComponentCache.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
auto text = "Object " + std::to_string(clickedList->get_child_id(static_cast<std::uint16_t>(i)));
|
||||
if (child && child->get_object_type() == isobus::VirtualTerminalObjectType::OutputString)
|
||||
{
|
||||
text = std::static_pointer_cast<isobus::OutputString>(child)->displayed_value(parentWorkingSet);
|
||||
}
|
||||
|
||||
comboPopup->addCustomItem(i + 1, *currentModalComponentCache.back().get(), currentModalComponentCache.back()->getWidth(), currentModalComponentCache.back()->getHeight(), true, nullptr, text);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex != -1)
|
||||
{
|
||||
combo->setSelectedItemIndex(selectedIndex);
|
||||
}
|
||||
|
||||
inputListModal->addButton("OK", 0);
|
||||
auto resultCallback = [this, clickedList](int result) {
|
||||
auto inputCombo = inputListModal->getComboBoxComponent("Input List Combo");
|
||||
result = inputCombo->getSelectedItemIndex();
|
||||
|
||||
// Remap the visible index to the actual index
|
||||
std::uint16_t numberOfNonNullsSeen = 0;
|
||||
for (std::uint16_t i = 0; i < clickedList->get_number_children(); i++)
|
||||
{
|
||||
if (isobus::NULL_OBJECT_ID != clickedList->get_child_id(i))
|
||||
{
|
||||
numberOfNonNullsSeen++;
|
||||
}
|
||||
|
||||
if (numberOfNonNullsSeen == result + 1)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != clickedList->get_variable_reference())
|
||||
{
|
||||
auto child = clickedList->get_object_by_id(clickedList->get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
|
||||
{
|
||||
if (std::static_pointer_cast<isobus::NumberVariable>(child)->get_value() != static_cast<std::uint32_t>(result))
|
||||
{
|
||||
std::static_pointer_cast<isobus::NumberVariable>(child)->set_value(result);
|
||||
ownerServer.send_change_numeric_value_message(child->get_id(), result, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(child, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::NumberVariable, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ownerServer.process_macro(clickedList, isobus::EventID::OnEntryOfAValue, isobus::VirtualTerminalObjectType::InputList, parentWorkingSet);
|
||||
if (clickedList->get_value() != result)
|
||||
{
|
||||
ownerServer.process_macro(clickedList, isobus::EventID::OnEntryOfANewValue, isobus::VirtualTerminalObjectType::InputList, parentWorkingSet);
|
||||
clickedList->set_value(static_cast<std::uint8_t>(result));
|
||||
ownerServer.send_change_numeric_value_message(clickedList->get_id(), result, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(clickedList, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::InputList, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
this->inputListModal->exitModalState();
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
parentWorkingSet->set_object_focus(isobus::NULL_OBJECT_ID);
|
||||
}
|
||||
ownerServer.repaint_on_next_update();
|
||||
ownerServer.process_macro(clickedList, isobus::EventID::OnInputFieldDeselection, isobus::VirtualTerminalObjectType::InputList, parentWorkingSet);
|
||||
inputListModal.reset();
|
||||
repaint();
|
||||
};
|
||||
inputListModal->enterModalState(true, ModalCallbackFunction::create(std::move(resultCallback)), false);
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
parentWorkingSet->set_object_focus(clickedObject->get_id());
|
||||
}
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnInputFieldSelection, isobus::VirtualTerminalObjectType::InputList, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputNumber:
|
||||
{
|
||||
auto clickedNumber = std::static_pointer_cast<isobus::InputNumber>(clickedObject);
|
||||
|
||||
if (clickedNumber->get_option2(isobus::InputNumber::Options2::Enabled))
|
||||
{
|
||||
inputNumberModal.reset(new AlertWindow("Input Number", "Enter a value for this input number, then press OK.", MessageBoxIconType::QuestionIcon));
|
||||
|
||||
float scaledValue = (clickedNumber->get_value() + clickedNumber->get_offset()) * clickedNumber->get_scale();
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != clickedNumber->get_variable_reference())
|
||||
{
|
||||
auto child = clickedNumber->get_object_by_id(clickedNumber->get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
|
||||
{
|
||||
scaledValue = (std::static_pointer_cast<isobus::NumberVariable>(child)->get_value() + clickedNumber->get_offset()) * clickedNumber->get_scale();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputNumberSlider.reset(new Slider(Slider::SliderStyle::LinearHorizontal, Slider::TextBoxAbove));
|
||||
inputNumberSlider->setRange((static_cast<float>(clickedNumber->get_minimum_value()) + clickedNumber->get_offset()) * clickedNumber->get_scale(),
|
||||
(static_cast<float>(clickedNumber->get_maximum_value()) + clickedNumber->get_offset()) * clickedNumber->get_scale());
|
||||
inputNumberSlider->setNumDecimalPlacesToDisplay(clickedNumber->get_number_of_decimals());
|
||||
inputNumberSlider->setValue(scaledValue, NotificationType::dontSendNotification);
|
||||
inputNumberSlider->setSize(400, 80);
|
||||
|
||||
inputNumberListener.set_last_value(inputNumberSlider->getValue());
|
||||
inputNumberListener.set_target(clickedNumber);
|
||||
inputNumberSlider->addListener(&inputNumberListener);
|
||||
|
||||
inputNumberModal->addCustomComponent(inputNumberSlider.get());
|
||||
inputNumberModal->addButton("OK", 0);
|
||||
inputNumberModal->addButton("Cancel", 1); // TODO catch ESC as cancel
|
||||
auto resultCallback = [this, clickedNumber](int result) {
|
||||
this->inputNumberModal->exitModalState();
|
||||
|
||||
std::uint16_t varNumID = 0xFFFF;
|
||||
if (0 == result)
|
||||
{
|
||||
ownerServer.process_macro(clickedNumber, isobus::EventID::OnEntryOfAValue, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != clickedNumber->get_variable_reference())
|
||||
{
|
||||
auto child = clickedNumber->get_object_by_id(clickedNumber->get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type()))
|
||||
{
|
||||
varNumID = child->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != varNumID)
|
||||
{
|
||||
if (std::static_pointer_cast<isobus::NumberVariable>(clickedNumber->get_object_by_id(clickedNumber->get_variable_reference(), parentWorkingSet->get_object_tree()))->get_value() != inputNumberListener.get_last_value())
|
||||
{
|
||||
ownerServer.process_macro(clickedNumber, isobus::EventID::OnEntryOfANewValue, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
}
|
||||
std::static_pointer_cast<isobus::NumberVariable>(clickedNumber->get_object_by_id(clickedNumber->get_variable_reference(), parentWorkingSet->get_object_tree()))->set_value(inputNumberListener.get_last_value());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (clickedNumber->get_value() != inputNumberListener.get_last_value())
|
||||
{
|
||||
ownerServer.process_macro(clickedNumber, isobus::EventID::OnEntryOfANewValue, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
clickedNumber->set_value(inputNumberListener.get_last_value());
|
||||
ownerServer.process_macro(clickedNumber, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
|
||||
this->needToRepaintActiveArea = true;
|
||||
}
|
||||
inputNumberListener.set_target(nullptr);
|
||||
inputNumberModal.reset();
|
||||
inputNumberSlider.reset();
|
||||
ownerServer.send_select_input_object_message(clickedNumber->get_id(), false, false, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
|
||||
if (0 == result)
|
||||
{
|
||||
if (0xFFFF != varNumID)
|
||||
{
|
||||
ownerServer.send_change_numeric_value_message(varNumID, std::static_pointer_cast<isobus::NumberVariable>(clickedNumber->get_object_by_id(clickedNumber->get_variable_reference(), parentWorkingSet->get_object_tree()))->get_value(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(clickedNumber->get_object_by_id(clickedNumber->get_variable_reference(), parentWorkingSet->get_object_tree()), isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::NumberVariable, parentWorkingSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
ownerServer.send_change_numeric_value_message(clickedNumber->get_id(), clickedNumber->get_value(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(clickedNumber, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO ESC
|
||||
}
|
||||
|
||||
if (parentWorkingSet)
|
||||
{
|
||||
parentWorkingSet->set_object_focus(isobus::NULL_OBJECT_ID);
|
||||
}
|
||||
ownerServer.process_macro(clickedNumber, isobus::EventID::OnInputFieldDeselection, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
};
|
||||
inputNumberModal->enterModalState(true, ModalCallbackFunction::create(std::move(resultCallback)), false);
|
||||
ownerServer.send_select_input_object_message(clickedNumber->get_id(), true, true, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
if (parentWorkingSet)
|
||||
{
|
||||
parentWorkingSet->set_object_focus(clickedObject->get_id());
|
||||
}
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnInputFieldSelection, isobus::VirtualTerminalObjectType::InputNumber, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputBoolean:
|
||||
{
|
||||
auto clickedBool = std::static_pointer_cast<isobus::InputBoolean>(clickedObject);
|
||||
|
||||
if (clickedBool->get_enabled())
|
||||
{
|
||||
bool hasNumberVariable = false;
|
||||
ownerServer.process_macro(clickedBool, isobus::EventID::OnEntryOfAValue, isobus::VirtualTerminalObjectType::InputBoolean, parentWorkingSet);
|
||||
ownerServer.process_macro(clickedBool, isobus::EventID::OnEntryOfANewValue, isobus::VirtualTerminalObjectType::InputBoolean, parentWorkingSet);
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != clickedBool->get_variable_reference())
|
||||
{
|
||||
auto child = clickedBool->get_object_by_id(clickedBool->get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
|
||||
{
|
||||
hasNumberVariable = true;
|
||||
std::static_pointer_cast<isobus::NumberVariable>(child)->set_value(!(0 != std::static_pointer_cast<isobus::NumberVariable>(child)->get_value()));
|
||||
ownerServer.send_change_numeric_value_message(child->get_id(), std::static_pointer_cast<isobus::NumberVariable>(child)->get_value(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(child, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::NumberVariable, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasNumberVariable)
|
||||
{
|
||||
clickedBool->set_value(~clickedBool->get_value());
|
||||
ownerServer.send_change_numeric_value_message(clickedBool->get_id(), clickedBool->get_value(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(clickedBool, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::InputBoolean, parentWorkingSet);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputString:
|
||||
{
|
||||
auto clickedString = std::static_pointer_cast<isobus::InputString>(clickedObject);
|
||||
std::shared_ptr<isobus::StringVariable> stringVariable;
|
||||
|
||||
if (clickedString->get_enabled())
|
||||
{
|
||||
bool hasStringVariable = false;
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != clickedString->get_variable_reference())
|
||||
{
|
||||
auto child = clickedString->get_object_by_id(clickedString->get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::StringVariable == child->get_object_type())
|
||||
{
|
||||
hasStringVariable = true;
|
||||
stringVariable = std::static_pointer_cast<isobus::StringVariable>(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputStringModal.reset(new AlertWindow("Input String", "Enter a value for this input string, then press OK.", MessageBoxIconType::QuestionIcon));
|
||||
inputStringModal->addTextEditor("Input String", hasStringVariable ? stringVariable->get_value() : clickedString->get_value());
|
||||
inputStringModal->addButton("OK", 0);
|
||||
inputStringModal->addButton("Cancel", 1); // TODO catch ESC as cancel
|
||||
auto resultCallback = [this, clickedString, stringVariable](int result) {
|
||||
this->inputStringModal->exitModalState();
|
||||
ownerServer.send_select_input_object_message(clickedString->get_id(), false, false, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
|
||||
if (0 == result) //OK
|
||||
{
|
||||
String newContent = this->inputStringModal->getTextEditor("Input String")->getText();
|
||||
ownerServer.process_macro(clickedString, isobus::EventID::OnEntryOfAValue, isobus::VirtualTerminalObjectType::InputString, parentWorkingSet);
|
||||
|
||||
if (nullptr != stringVariable)
|
||||
{
|
||||
// It seems common practice to pad the string value out to the length in the object pool.
|
||||
while (newContent.length() < stringVariable->get_value().length())
|
||||
{
|
||||
newContent.append(" ", 1);
|
||||
}
|
||||
stringVariable->set_value(newContent.toStdString());
|
||||
ownerServer.send_change_string_value_message(stringVariable->get_id(), newContent.toStdString(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(stringVariable, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::StringVariable, parentWorkingSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It seems common practice to pad the string value out to the length in the object pool.
|
||||
while (newContent.length() < clickedString->get_value().length())
|
||||
{
|
||||
newContent.append(" ", 1);
|
||||
}
|
||||
if (clickedString->get_value() != newContent)
|
||||
{
|
||||
ownerServer.process_macro(clickedString, isobus::EventID::OnEntryOfANewValue, isobus::VirtualTerminalObjectType::InputString, parentWorkingSet);
|
||||
}
|
||||
clickedString->set_value(newContent.toStdString());
|
||||
ownerServer.send_change_string_value_message(clickedString->get_id(), newContent.toStdString(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
ownerServer.process_macro(clickedString, isobus::EventID::OnChangeValue, isobus::VirtualTerminalObjectType::InputString, parentWorkingSet);
|
||||
}
|
||||
needToRepaintActiveArea = true;
|
||||
}
|
||||
inputStringModal->exitModalState();
|
||||
inputStringModal.reset();
|
||||
if (parentWorkingSet)
|
||||
{
|
||||
parentWorkingSet->set_object_focus(isobus::NULL_OBJECT_ID);
|
||||
}
|
||||
ownerServer.process_macro(clickedString, isobus::EventID::OnInputFieldDeselection, isobus::VirtualTerminalObjectType::InputString, parentWorkingSet);
|
||||
};
|
||||
inputStringModal->enterModalState(true, ModalCallbackFunction::create(std::move(resultCallback)), false);
|
||||
ownerServer.send_select_input_object_message(clickedString->get_id(), true, true, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
|
||||
if (parentWorkingSet)
|
||||
{
|
||||
parentWorkingSet->set_object_focus(clickedObject->get_id());
|
||||
}
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnInputFieldSelection, isobus::VirtualTerminalObjectType::InputString, parentWorkingSet);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DataMaskRenderAreaComponent::needsRepaint() const
|
||||
{
|
||||
return needToRepaintActiveArea;
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::set_has_started(bool started)
|
||||
{
|
||||
hasStarted = started;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::InputNumberListener::sliderValueChanged(Slider *slider)
|
||||
{
|
||||
if ((nullptr != slider) && (nullptr != targetObject) && (0 != targetObject->get_scale()))
|
||||
{
|
||||
float scaledValue = (slider->getValue() / targetObject->get_scale()) - targetObject->get_offset();
|
||||
lastValue = static_cast<std::uint32_t>(scaledValue);
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t DataMaskRenderAreaComponent::InputNumberListener::get_last_value() const
|
||||
{
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::InputNumberListener::set_last_value(std::uint32_t value)
|
||||
{
|
||||
lastValue = value;
|
||||
}
|
||||
|
||||
std::shared_ptr<isobus::InputNumber> DataMaskRenderAreaComponent::InputNumberListener::get_target()
|
||||
{
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
void DataMaskRenderAreaComponent::InputNumberListener::set_target(std::shared_ptr<isobus::InputNumber> objectBeingModified)
|
||||
{
|
||||
targetObject = objectBeingModified;
|
||||
}
|
||||
|
||||
std::shared_ptr<isobus::VTObject> DataMaskRenderAreaComponent::getClickedChildRecursive(std::shared_ptr<isobus::VTObject> object, int x, int y)
|
||||
{
|
||||
std::shared_ptr<isobus::VTObject> retVal;
|
||||
|
||||
if ((nullptr == object) ||
|
||||
(nullptr == parentWorkingSet) ||
|
||||
((isobus::VirtualTerminalObjectType::ObjectPointer != object->get_object_type()) &&
|
||||
(0 == object->get_number_children())))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isobus::VirtualTerminalObjectType::ObjectPointer == object->get_object_type())
|
||||
{
|
||||
auto child = object->get_object_by_id(std::static_pointer_cast<isobus::ObjectPointer>(object)->get_value(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) &&
|
||||
(objectCanBeClicked(child)) &&
|
||||
(isClickWithinBounds(x, y, 0, 0, child->get_width(), child->get_height())))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
else if (!objectCanBeClicked(child))
|
||||
{
|
||||
retVal = getClickedChildRecursive(child, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::uint16_t i = 0; i < object->get_number_children(); i++)
|
||||
{
|
||||
auto child = object->get_object_by_id(object->get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) &&
|
||||
(objectCanBeClicked(child)) &&
|
||||
(isClickWithinBounds(x, y, object->get_child_x(i), object->get_child_y(i), child->get_width(), child->get_height())))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
else if (!objectCanBeClicked(child))
|
||||
{
|
||||
retVal = getClickedChildRecursive(child, x - object->get_child_x(i), y - object->get_child_y(i));
|
||||
|
||||
if (nullptr != retVal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool DataMaskRenderAreaComponent::objectCanBeClicked(std::shared_ptr<isobus::VTObject> object)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
||||
if (nullptr != object)
|
||||
{
|
||||
switch (object->get_object_type())
|
||||
{
|
||||
case isobus::VirtualTerminalObjectType::Button:
|
||||
case isobus::VirtualTerminalObjectType::InputList:
|
||||
case isobus::VirtualTerminalObjectType::Key:
|
||||
case isobus::VirtualTerminalObjectType::InputNumber:
|
||||
case isobus::VirtualTerminalObjectType::InputBoolean:
|
||||
case isobus::VirtualTerminalObjectType::InputString:
|
||||
{
|
||||
retVal = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
retVal = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool DataMaskRenderAreaComponent::isClickWithinBounds(int clickXRelative, int clickYRelative, int objectX, int objectY, int objectWidth, int objectHeight)
|
||||
{
|
||||
return ((clickXRelative >= objectX) && (clickXRelative <= (objectX + objectWidth))) &&
|
||||
((clickYRelative >= objectY) && (clickYRelative <= (objectY + objectHeight)));
|
||||
}
|
||||
61
AgIsoVirtualTerminal/src/InputBooleanComponent.cpp
Normal file
61
AgIsoVirtualTerminal/src/InputBooleanComponent.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*******************************************************************************
|
||||
** @file InputBooleanComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "InputBooleanComponent.hpp"
|
||||
|
||||
InputBooleanComponent::InputBooleanComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputBoolean sourceObject) :
|
||||
isobus::InputBoolean(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setOpaque(false);
|
||||
setSize(get_width(), get_height());
|
||||
|
||||
setEnabled(get_enabled());
|
||||
}
|
||||
|
||||
void InputBooleanComponent::paint(Graphics &g)
|
||||
{
|
||||
// Draw background
|
||||
auto vtColour = parentWorkingSet->get_colour(get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
g.fillRect(0, 0, static_cast<int>(get_width()), static_cast<int>(get_height()));
|
||||
|
||||
g.setColour(Colour::fromFloatRGBA(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
// Change colour to foreground colour if present
|
||||
if (isobus::NULL_OBJECT_ID != get_foreground_colour_object_id())
|
||||
{
|
||||
auto child = get_object_by_id(get_foreground_colour_object_id(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::FontAttributes == child->get_object_type()))
|
||||
{
|
||||
vtColour = parentWorkingSet->get_colour(std::static_pointer_cast<isobus::FontAttributes>(child)->get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
bool isChecked = (0 != get_value());
|
||||
// Change use number variable if one was provided
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto child = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type()))
|
||||
{
|
||||
isChecked = std::static_pointer_cast<isobus::NumberVariable>(child)->get_value();
|
||||
}
|
||||
}
|
||||
|
||||
if (isChecked)
|
||||
{
|
||||
g.drawLine(0, get_height() / 2, get_width() / 2, get_height());
|
||||
g.drawLine(get_width() / 2, get_height(), get_width(), 0);
|
||||
}
|
||||
|
||||
// If disabled, try and show that by drawing some semi-transparent grey
|
||||
if (!get_enabled())
|
||||
{
|
||||
g.fillAll(Colour::fromFloatRGBA(0.5f, 0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
67
AgIsoVirtualTerminal/src/InputListComponent.cpp
Normal file
67
AgIsoVirtualTerminal/src/InputListComponent.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
** @file InputListComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "InputListComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
InputListComponent::InputListComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputList sourceObject) :
|
||||
isobus::InputList(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
setOpaque(false);
|
||||
onChanged(true);
|
||||
}
|
||||
|
||||
void InputListComponent::paint(Graphics &)
|
||||
{
|
||||
}
|
||||
|
||||
void InputListComponent::paintOverChildren(Graphics &g)
|
||||
{
|
||||
if (!get_option(Options::Enabled))
|
||||
{
|
||||
g.fillAll(Colour::fromFloatRGBA(0.5f, 0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
void InputListComponent::onChanged(bool initial)
|
||||
{
|
||||
childComponent.reset();
|
||||
|
||||
std::uint32_t selectedIndex = get_value();
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto child = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
|
||||
{
|
||||
selectedIndex = std::static_pointer_cast<isobus::NumberVariable>(child)->get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((get_number_children() > 0) &&
|
||||
(selectedIndex < static_cast<std::uint32_t>(get_number_children())))
|
||||
{
|
||||
// The number variable will always be the first one
|
||||
auto listItem = get_object_by_id(get_child_id(static_cast<std::uint16_t>(selectedIndex)), parentWorkingSet->get_object_tree());
|
||||
childComponent = JuceManagedWorkingSetCache::create_component(parentWorkingSet, listItem);
|
||||
|
||||
if (nullptr != childComponent)
|
||||
{
|
||||
addAndMakeVisible(*childComponent);
|
||||
childComponent->setTopLeftPosition(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
171
AgIsoVirtualTerminal/src/InputNumberComponent.cpp
Normal file
171
AgIsoVirtualTerminal/src/InputNumberComponent.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*******************************************************************************
|
||||
** @file InputNumberComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "InputNumberComponent.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
InputNumberComponent::InputNumberComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputNumber sourceObject) :
|
||||
isobus::InputNumber(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
|
||||
if (get_option(Options::Transparent))
|
||||
{
|
||||
setOpaque(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
setOpaque(true);
|
||||
}
|
||||
}
|
||||
|
||||
void InputNumberComponent::paint(Graphics &g)
|
||||
{
|
||||
if (isOpaque())
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
|
||||
float scaledValue = (get_value() + get_offset()) * get_scale();
|
||||
g.setColour(getLookAndFeel().findColour(ListBox::textColourId));
|
||||
|
||||
// Get font data
|
||||
if (isobus::NULL_OBJECT_ID != get_font_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_font_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) &&
|
||||
(isobus::VirtualTerminalObjectType::FontAttributes == child->get_object_type()))
|
||||
{
|
||||
auto font = std::static_pointer_cast<isobus::FontAttributes>(child);
|
||||
auto colour = parentWorkingSet->get_colour(font->get_colour());
|
||||
Font juceFont(Font::getDefaultMonospacedFontName(), font->get_font_height_pixels(), Font::FontStyleFlags::plain);
|
||||
auto fontWidth = juceFont.getStringWidthFloat("1");
|
||||
juceFont.setHorizontalScale(static_cast<float>(font->get_font_width_pixels()) / fontWidth);
|
||||
g.setColour(Colour::fromFloatRGBA(colour.r, colour.g, colour.b, 1.0f));
|
||||
g.setFont(juceFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto child = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) &&
|
||||
(isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type()))
|
||||
{
|
||||
scaledValue = (std::static_pointer_cast<isobus::NumberVariable>(child)->get_value() + get_offset()) * get_scale();
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream valueText;
|
||||
valueText << std::fixed << std::setprecision(get_number_of_decimals()) << scaledValue;
|
||||
g.drawText(valueText.str(), 0, 0, get_width(), get_height(), convert_justification(get_horizontal_justification(), get_vertical_justification()), false);
|
||||
}
|
||||
|
||||
Justification InputNumberComponent::convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification)
|
||||
{
|
||||
Justification retVal = Justification::topLeft;
|
||||
|
||||
switch (horizontalJustification)
|
||||
{
|
||||
case HorizontalJustification::PositionLeft:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionMiddle:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::centredTop;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centred;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::centredBottom;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionRight:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
272
AgIsoVirtualTerminal/src/InputStringComponent.cpp
Normal file
272
AgIsoVirtualTerminal/src/InputStringComponent.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/*******************************************************************************
|
||||
** @file InputStringComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "InputStringComponent.hpp"
|
||||
|
||||
#include "StringEncodingConversions.hpp"
|
||||
|
||||
InputStringComponent::InputStringComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputString sourceObject) :
|
||||
isobus::InputString(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
void InputStringComponent::paint(Graphics &g)
|
||||
{
|
||||
std::string value = get_value();
|
||||
std::uint8_t fontHeight = 0;
|
||||
auto fontType = isobus::FontAttributes::FontType::ISO8859_1;
|
||||
|
||||
if (!get_option(Options::Transparent))
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(get_background_color());
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
|
||||
g.setColour(getLookAndFeel().findColour(ListBox::textColourId));
|
||||
|
||||
// Get font data
|
||||
if (isobus::NULL_OBJECT_ID != get_font_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_font_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::FontAttributes == child->get_object_type())
|
||||
{
|
||||
auto font = std::static_pointer_cast<isobus::FontAttributes>(child);
|
||||
fontType = font->get_type();
|
||||
|
||||
auto colour = parentWorkingSet->get_colour(font->get_colour());
|
||||
Font juceFont;
|
||||
int fontStyleFlags = Font::FontStyleFlags::plain;
|
||||
|
||||
if (font->get_style(isobus::FontAttributes::FontStyleBits::Bold))
|
||||
{
|
||||
fontStyleFlags |= Font::FontStyleFlags::bold;
|
||||
}
|
||||
|
||||
if (font->get_style(isobus::FontAttributes::FontStyleBits::Italic))
|
||||
{
|
||||
fontStyleFlags |= Font::FontStyleFlags::italic;
|
||||
}
|
||||
|
||||
if (font->get_style(isobus::FontAttributes::FontStyleBits::Underlined))
|
||||
{
|
||||
fontStyleFlags |= Font::FontStyleFlags::underlined;
|
||||
}
|
||||
|
||||
juceFont = Font(Font::getDefaultMonospacedFontName(), font->get_font_height_pixels(), fontStyleFlags);
|
||||
|
||||
auto fontWidth = juceFont.getStringWidthFloat("a");
|
||||
fontHeight = font->get_font_width_pixels();
|
||||
juceFont.setHorizontalScale(static_cast<float>(font->get_font_width_pixels()) / fontWidth);
|
||||
g.setColour(Colour::fromFloatRGBA(colour.r, colour.g, colour.b, 1.0f));
|
||||
g.setFont(juceFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto child = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::StringVariable == child->get_object_type()))
|
||||
{
|
||||
value = std::static_pointer_cast<isobus::StringVariable>(child)->get_value();
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == fontHeight)
|
||||
{
|
||||
fontHeight = 8;
|
||||
}
|
||||
|
||||
String decodedValue(value);
|
||||
|
||||
if ((value.length() >= 2) &&
|
||||
(0xFF == static_cast<std::uint8_t>(value.at(0))) &&
|
||||
(0xFE == static_cast<std::uint8_t>(value.at(1))))
|
||||
{
|
||||
// String is UTF-16 encoded.
|
||||
if (0 != (value.length() % 2))
|
||||
{
|
||||
// If the length attribute does not indicate an even number of bytes the last byte is ignored
|
||||
value.pop_back();
|
||||
}
|
||||
decodedValue = String::createStringFromData(value.c_str(), value.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (fontType)
|
||||
{
|
||||
case isobus::FontAttributes::FontType::ISO8859_1:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_1, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_15:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_15, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_2:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_2, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_4:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_4, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_5:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_5, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_7:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_7, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_option(Options::AutoWrap)) // TODO need to figure out proper font clipping
|
||||
{
|
||||
g.drawFittedText(decodedValue, 0, 0, get_width(), get_height(), convert_justification(get_horizontal_justification(), get_vertical_justification()), static_cast<int>(std::floor((static_cast<float>(get_height()) + 0.1f) / fontHeight)), 0.8f);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.drawFittedText(decodedValue, 0, 0, get_width(), get_height(), convert_justification(get_horizontal_justification(), get_vertical_justification()), static_cast<int>(std::floor((static_cast<float>(get_height()) + 0.1f) / fontHeight)), 0.8f);
|
||||
}
|
||||
|
||||
// If disabled, try and show that by drawing some semi-transparent grey
|
||||
if (!get_enabled())
|
||||
{
|
||||
g.fillAll(Colour::fromFloatRGBA(0.5f, 0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
Justification InputStringComponent::convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification)
|
||||
{
|
||||
Justification retVal = Justification::topLeft;
|
||||
|
||||
switch (horizontalJustification)
|
||||
{
|
||||
case HorizontalJustification::PositionLeft:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionMiddle:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::centredTop;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centred;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::centredBottom;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionRight:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
235
AgIsoVirtualTerminal/src/JuceManagedWorkingSetCache.cpp
Normal file
235
AgIsoVirtualTerminal/src/JuceManagedWorkingSetCache.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*******************************************************************************
|
||||
** @file JuceManagedWorkingSetCache.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
#include "AlarmMaskComponent.hpp"
|
||||
#include "ButtonComponent.hpp"
|
||||
#include "ColourMapComponent.hpp"
|
||||
#include "ContainerComponent.hpp"
|
||||
#include "DataMaskComponent.hpp"
|
||||
#include "ExtendedInputAttributesComponent.hpp"
|
||||
#include "FillAttributesComponent.hpp"
|
||||
#include "InputBooleanComponent.hpp"
|
||||
#include "InputListComponent.hpp"
|
||||
#include "InputNumberComponent.hpp"
|
||||
#include "InputStringComponent.hpp"
|
||||
#include "KeyComponent.hpp"
|
||||
#include "KeyGroupComponent.hpp"
|
||||
#include "LineAttributesComponent.hpp"
|
||||
#include "MacroComponent.hpp"
|
||||
#include "NumberVariableComponent.hpp"
|
||||
#include "ObjectPointerComponent.hpp"
|
||||
#include "OutputArchedBarGraphComponent.hpp"
|
||||
#include "OutputEllipseComponent.hpp"
|
||||
#include "OutputLineComponent.hpp"
|
||||
#include "OutputLinearBarGraphComponent.hpp"
|
||||
#include "OutputListComponent.hpp"
|
||||
#include "OutputMeterComponent.hpp"
|
||||
#include "OutputNumberComponent.hpp"
|
||||
#include "OutputPolygonComponent.hpp"
|
||||
#include "OutputRectangleComponent.hpp"
|
||||
#include "OutputStringComponent.hpp"
|
||||
#include "PictureGraphicComponent.hpp"
|
||||
#include "SoftKeyMaskComponent.hpp"
|
||||
#include "StringVariableComponent.hpp"
|
||||
#include "WorkingSetComponent.hpp"
|
||||
|
||||
std::vector<JuceManagedWorkingSetCache::ComponentCacheClass> JuceManagedWorkingSetCache::workingSetComponentCache;
|
||||
int JuceManagedWorkingSetCache::dataAndAlarmMaskSize = 480;
|
||||
SoftKeyMaskDimensions JuceManagedWorkingSetCache::softKeyDimensionInfo = SoftKeyMaskDimensions();
|
||||
|
||||
std::shared_ptr<Component> JuceManagedWorkingSetCache::create_component(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, std::shared_ptr<isobus::VTObject> sourceObject)
|
||||
{
|
||||
std::shared_ptr<Component> retVal;
|
||||
bool isWorkingSetKnown = false;
|
||||
|
||||
for (auto &knownWorkingSet : workingSetComponentCache)
|
||||
{
|
||||
if (knownWorkingSet.workingSet == workingSet)
|
||||
{
|
||||
isWorkingSetKnown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isWorkingSetKnown)
|
||||
{
|
||||
workingSetComponentCache.emplace_back(workingSet);
|
||||
}
|
||||
|
||||
if (nullptr != sourceObject)
|
||||
{
|
||||
switch (sourceObject->get_object_type())
|
||||
{
|
||||
case isobus::VirtualTerminalObjectType::AlarmMask:
|
||||
{
|
||||
retVal = std::make_shared<AlarmMaskComponent>(workingSet, *std::static_pointer_cast<isobus::AlarmMask>(sourceObject), dataAndAlarmMaskSize);
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::DataMask:
|
||||
{
|
||||
retVal = std::make_shared<DataMaskComponent>(workingSet, *std::static_pointer_cast<isobus::DataMask>(sourceObject), dataAndAlarmMaskSize);
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::Container:
|
||||
{
|
||||
retVal = std::make_shared<ContainerComponent>(workingSet, *std::static_pointer_cast<isobus::Container>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::WindowMask:
|
||||
{
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::SoftKeyMask:
|
||||
{
|
||||
retVal = std::make_shared<SoftKeyMaskComponent>(workingSet,
|
||||
*std::static_pointer_cast<isobus::SoftKeyMask>(sourceObject),
|
||||
softKeyDimensionInfo);
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::Key:
|
||||
{
|
||||
retVal = std::make_shared<KeyComponent>(workingSet, *std::static_pointer_cast<isobus::Key>(sourceObject), softKeyDimensionInfo.keyWidth, softKeyDimensionInfo.keyHeight);
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::Button:
|
||||
{
|
||||
retVal = std::make_shared<ButtonComponent>(workingSet, *std::static_pointer_cast<isobus::Button>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputBoolean:
|
||||
{
|
||||
retVal = std::make_shared<InputBooleanComponent>(workingSet, *std::static_pointer_cast<isobus::InputBoolean>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::KeyGroup:
|
||||
{
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputString:
|
||||
{
|
||||
retVal = std::make_shared<InputStringComponent>(workingSet, *std::static_pointer_cast<isobus::InputString>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputNumber:
|
||||
{
|
||||
retVal = std::make_shared<InputNumberComponent>(workingSet, *std::static_pointer_cast<isobus::InputNumber>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::InputList:
|
||||
{
|
||||
retVal = std::make_shared<InputListComponent>(workingSet, *std::static_pointer_cast<isobus::InputList>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputString:
|
||||
{
|
||||
retVal = std::make_shared<OutputStringComponent>(workingSet, *std::static_pointer_cast<isobus::OutputString>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputNumber:
|
||||
{
|
||||
retVal = std::make_shared<OutputNumberComponent>(workingSet, *std::static_pointer_cast<isobus::OutputNumber>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputList:
|
||||
{
|
||||
//retVal = std::make_shared<OutputListComponent>(workingSet, *std::static_pointer_cast<isobus::OutputList>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputLine:
|
||||
{
|
||||
retVal = std::make_shared<OutputLineComponent>(workingSet, *std::static_pointer_cast<isobus::OutputLine>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputRectangle:
|
||||
{
|
||||
retVal = std::make_shared<OutputRectangleComponent>(workingSet, *std::static_pointer_cast<isobus::OutputRectangle>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputEllipse:
|
||||
{
|
||||
retVal = std::make_shared<OutputEllipseComponent>(workingSet, *std::static_pointer_cast<isobus::OutputEllipse>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputPolygon:
|
||||
{
|
||||
retVal = std::make_shared<OutputPolygonComponent>(workingSet, *std::static_pointer_cast<isobus::OutputPolygon>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputMeter:
|
||||
{
|
||||
retVal = std::make_shared<OutputMeterComponent>(workingSet, *std::static_pointer_cast<isobus::OutputMeter>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputLinearBarGraph:
|
||||
{
|
||||
retVal = std::make_shared<OutputLinearBarGraphComponent>(workingSet, *std::static_pointer_cast<isobus::OutputLinearBarGraph>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::OutputArchedBarGraph:
|
||||
case isobus::VirtualTerminalObjectType::GraphicsContext:
|
||||
case isobus::VirtualTerminalObjectType::Animation:
|
||||
{
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::PictureGraphic:
|
||||
{
|
||||
retVal = std::make_shared<PictureGraphicComponent>(workingSet, *std::static_pointer_cast<isobus::PictureGraphic>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::ObjectPointer:
|
||||
{
|
||||
retVal = std::make_shared<ObjectPointerComponent>(workingSet, *std::static_pointer_cast<isobus::ObjectPointer>(sourceObject));
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::VirtualTerminalObjectType::WorkingSet:
|
||||
{
|
||||
retVal = std::make_shared<WorkingSetComponent>(workingSet, *std::static_pointer_cast<isobus::WorkingSet>(sourceObject), softKeyDimensionInfo.keyHeight, softKeyDimensionInfo.keyWidth);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullptr != retVal)
|
||||
{
|
||||
retVal->setInterceptsMouseClicks(false, false);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void JuceManagedWorkingSetCache::set_softkey_mask_dimension_info(const SoftKeyMaskDimensions &info)
|
||||
{
|
||||
softKeyDimensionInfo = info;
|
||||
}
|
||||
39
AgIsoVirtualTerminal/src/KeyComponent.cpp
Normal file
39
AgIsoVirtualTerminal/src/KeyComponent.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
** @file KeyComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "KeyComponent.hpp"
|
||||
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
KeyComponent::KeyComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Key sourceObject, int keyWidth, int keyHeight) :
|
||||
isobus::Key(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(keyWidth, keyHeight);
|
||||
setOpaque(true);
|
||||
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
childComponents.back()->setTopLeftPosition(get_child_x(i), get_child_y(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
87
AgIsoVirtualTerminal/src/LoggerComponent.cpp
Normal file
87
AgIsoVirtualTerminal/src/LoggerComponent.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
//================================================================================================
|
||||
/// @file LoggerComponent.cpp
|
||||
///
|
||||
/// @brief Implements a GUI component to draw log output.
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2023 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#include "LoggerComponent.hpp"
|
||||
|
||||
LoggerComponent::LoggerComponent() :
|
||||
FileLogger(File(File::getSpecialLocation(File::userApplicationDataDirectory).getFullPathName() + "/Open-Agriculture/AgISOVirtualTerminalLog.txt"), "Starting AgIsoVirtualTerminal", 1024000)
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
setBounds(10, 10, bounds.getWidth() - 10, bounds.getHeight() - 10);
|
||||
}
|
||||
|
||||
void LoggerComponent::paint(Graphics &g)
|
||||
{
|
||||
g.fillAll(Colours::black);
|
||||
g.setFont(14.0f);
|
||||
|
||||
int numberOfLinesFitted = getHeight() / 14;
|
||||
|
||||
for (std::size_t i = 0; i < static_cast<int>(loggedMessages.size()) && i < numberOfLinesFitted; i++)
|
||||
{
|
||||
const auto &message = loggedMessages.at(i);
|
||||
|
||||
switch (message.logLevel)
|
||||
{
|
||||
case LoggingLevel::Info:
|
||||
{
|
||||
g.setColour(Colours::white);
|
||||
}
|
||||
break;
|
||||
|
||||
case LoggingLevel::Warning:
|
||||
{
|
||||
g.setColour(Colours::yellow);
|
||||
}
|
||||
break;
|
||||
|
||||
case LoggingLevel::Error:
|
||||
case LoggingLevel::Critical:
|
||||
{
|
||||
g.setColour(Colours::red);
|
||||
}
|
||||
break;
|
||||
|
||||
case LoggingLevel::Debug:
|
||||
{
|
||||
g.setColour(Colours::blueviolet);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
g.setColour(Colours::white);
|
||||
}
|
||||
break;
|
||||
}
|
||||
g.drawFittedText(message.logText, 0, static_cast<int>(i) * 14, getWidth(), 14, Justification::centredLeft, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void LoggerComponent::sink_CAN_stack_log(LoggingLevel level, const std::string &logText)
|
||||
{
|
||||
const auto mmLock = MessageManagerLock();
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
loggedMessages.push_front({ logText, level });
|
||||
|
||||
if (loggedMessages.size() > MAX_NUMBER_MESSAGES)
|
||||
{
|
||||
loggedMessages.pop_back();
|
||||
}
|
||||
|
||||
int newSize = static_cast<int>(loggedMessages.size()) * 14;
|
||||
|
||||
if (newSize < getHeight())
|
||||
{
|
||||
newSize = getHeight();
|
||||
}
|
||||
setSize(bounds.getWidth(), newSize);
|
||||
repaint();
|
||||
logMessage(logText);
|
||||
}
|
||||
159
AgIsoVirtualTerminal/src/Main.cpp
Normal file
159
AgIsoVirtualTerminal/src/Main.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*******************************************************************************
|
||||
** @file Main.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "isobus/hardware_integration/available_can_drivers.hpp"
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "ASCIILogFile.hpp"
|
||||
#include "AppImages.h"
|
||||
#include "ServerMainComponent.hpp"
|
||||
#include "isobus/hardware_integration/can_hardware_interface.hpp"
|
||||
#include "isobus/isobus/can_internal_control_function.hpp"
|
||||
#include "isobus/isobus/can_network_manager.hpp"
|
||||
|
||||
//==============================================================================
|
||||
class AgISOVirtualTerminalApplication : public juce::JUCEApplication
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
AgISOVirtualTerminalApplication() {}
|
||||
|
||||
const juce::String getApplicationName() override
|
||||
{
|
||||
return ProjectInfo::projectName;
|
||||
}
|
||||
const juce::String getApplicationVersion() override
|
||||
{
|
||||
return ProjectInfo::versionString;
|
||||
}
|
||||
bool moreThanOneInstanceAllowed() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialise(const juce::String &) override
|
||||
{
|
||||
// This method is where you should put your application's initialisation code..
|
||||
|
||||
mainWindow.reset(new MainWindow(getApplicationName()));
|
||||
}
|
||||
|
||||
void shutdown() override
|
||||
{
|
||||
// Add your application's shutdown code here..
|
||||
|
||||
mainWindow = nullptr; // (deletes our window)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit() override
|
||||
{
|
||||
// This is called when the app is being asked to quit: you can ignore this
|
||||
// request and let the app carry on running, or call quit() to allow the app to close.
|
||||
quit();
|
||||
}
|
||||
|
||||
void anotherInstanceStarted(const juce::String &) override
|
||||
{
|
||||
// When another instance of the app is launched while this one is running,
|
||||
// this method is invoked, and the commandLine parameter tells you what
|
||||
// the other instance's command-line arguments were.
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/*
|
||||
This class implements the desktop window that contains an instance of
|
||||
our MainComponent class.
|
||||
*/
|
||||
class MainWindow : public juce::DocumentWindow
|
||||
{
|
||||
public:
|
||||
MainWindow(juce::String name) :
|
||||
DocumentWindow(name,
|
||||
juce::Desktop::getInstance().getDefaultLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId),
|
||||
DocumentWindow::allButtons)
|
||||
{
|
||||
#ifdef JUCE_WINDOWS
|
||||
canDrivers.push_back(std::make_shared<isobus::PCANBasicWindowsPlugin>(static_cast<WORD>(PCAN_USBBUS1)));
|
||||
#ifdef ISOBUS_WINDOWSINNOMAKERUSB2CAN_AVAILABLE
|
||||
canDrivers.push_back(std::make_shared<isobus::InnoMakerUSB2CANWindowsPlugin>(0));
|
||||
#else
|
||||
canDrivers.push_back(nullptr);
|
||||
#endif
|
||||
canDrivers.push_back(std::make_shared<isobus::TouCANPlugin>(static_cast<std::int16_t>(0), 0));
|
||||
canDrivers.push_back(std::make_shared<isobus::SysTecWindowsPlugin>());
|
||||
#elif defined(JUCE_MAC)
|
||||
canDrivers.push_back(std::make_shared<isobus::MacCANPCANPlugin>(PCAN_USBBUS1));
|
||||
#else
|
||||
canDrivers.push_back(std::make_shared<isobus::SocketCANInterface>("can0"));
|
||||
#endif
|
||||
|
||||
jassert(!canDrivers.empty()); // You need some kind of CAN interface to run this program!
|
||||
isobus::CANHardwareInterface::set_number_of_can_channels(1);
|
||||
|
||||
#ifndef JUCE_WINDOWS
|
||||
isobus::CANHardwareInterface::assign_can_channel_frame_handler(0, canDrivers.at(0));
|
||||
#endif
|
||||
|
||||
isobus::NAME serverNAME(0);
|
||||
serverNAME.set_arbitrary_address_capable(true);
|
||||
serverNAME.set_function_code(static_cast<std::uint8_t>(isobus::NAME::Function::VirtualTerminal));
|
||||
serverNAME.set_industry_group(2);
|
||||
serverNAME.set_manufacturer_code(1407);
|
||||
serverInternalControlFunction = isobus::CANNetworkManager::CANNetwork.create_internal_control_function(serverNAME, 0, 0x26);
|
||||
setUsingNativeTitleBar(true);
|
||||
setContentOwned(new ServerMainComponent(serverInternalControlFunction, canDrivers), true);
|
||||
|
||||
#if JUCE_IOS || JUCE_ANDROID
|
||||
setFullScreen(true);
|
||||
#else
|
||||
setResizable(true, true);
|
||||
centreWithSize(getWidth(), getHeight());
|
||||
#endif
|
||||
|
||||
setIcon(ImageCache::getFromMemory(AppImages::logosmall_png, AppImages::logosmall_pngSize));
|
||||
#if JUCE_LINUX
|
||||
// this hack is needed on Linux
|
||||
ComponentPeer *peer = getPeer();
|
||||
if (peer)
|
||||
{
|
||||
peer->setIcon(ImageCache::getFromMemory(AppImages::logosmall_png, AppImages::logosmall_pngSize));
|
||||
}
|
||||
#endif
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void closeButtonPressed() override
|
||||
{
|
||||
// This is called when the user tries to close this window. Here, we'll just
|
||||
// ask the app to quit when this happens, but you can change this to do
|
||||
// whatever you need.
|
||||
isobus::CANHardwareInterface::stop();
|
||||
JUCEApplication::getInstance()->systemRequestedQuit();
|
||||
}
|
||||
|
||||
/* Note: Be careful if you override any DocumentWindow methods - the base
|
||||
class uses a lot of them, so by overriding you might break its functionality.
|
||||
It's best to do all your work in your content component instead, but if
|
||||
you really have to override any DocumentWindow methods, make sure your
|
||||
subclass also calls the superclass's method.
|
||||
*/
|
||||
|
||||
private:
|
||||
std::shared_ptr<isobus::InternalControlFunction> serverInternalControlFunction;
|
||||
std::vector<std::shared_ptr<isobus::CANHardwarePlugin>> canDrivers;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow)
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<MainWindow> mainWindow;
|
||||
ASCIILogFile logFile;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// This macro generates the main() routine that launches the app.
|
||||
START_JUCE_APPLICATION(AgISOVirtualTerminalApplication)
|
||||
41
AgIsoVirtualTerminal/src/ObjectPointerComponent.cpp
Normal file
41
AgIsoVirtualTerminal/src/ObjectPointerComponent.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
** @file ObjectPointerComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "ObjectPointerComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
ObjectPointerComponent::ObjectPointerComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::ObjectPointer sourceObject) :
|
||||
isobus::ObjectPointer(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
on_content_changed(true);
|
||||
}
|
||||
|
||||
void ObjectPointerComponent::on_content_changed(bool initial)
|
||||
{
|
||||
childComponent.reset();
|
||||
auto child = get_object_by_id(get_value(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
childComponent = JuceManagedWorkingSetCache::create_component(parentWorkingSet, child);
|
||||
|
||||
if (nullptr != childComponent)
|
||||
{
|
||||
addAndMakeVisible(*childComponent);
|
||||
childComponent->setTopLeftPosition(get_child_x(0), get_child_y(0));
|
||||
setSize(child->get_width(), child->get_height());
|
||||
}
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectPointerComponent::paint(Graphics &)
|
||||
{
|
||||
}
|
||||
46
AgIsoVirtualTerminal/src/OutputEllipseComponent.cpp
Normal file
46
AgIsoVirtualTerminal/src/OutputEllipseComponent.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputEllipseComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputEllipseComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
OutputEllipseComponent::OutputEllipseComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputEllipse sourceObject) :
|
||||
isobus::OutputEllipse(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
}
|
||||
|
||||
void OutputEllipseComponent::paint(Graphics &g)
|
||||
{
|
||||
// Ensure we fill first, then draw the outline if needed
|
||||
if (isobus::NULL_OBJECT_ID != get_fill_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_fill_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::FillAttributes == child->get_object_type()))
|
||||
{
|
||||
auto fill = std::static_pointer_cast<isobus::FillAttributes>(child);
|
||||
|
||||
auto vtColour = parentWorkingSet->get_colour(fill->get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
g.fillEllipse(0, 0, get_width(), get_height());
|
||||
}
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_line_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_line_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::LineAttributes == child->get_object_type()))
|
||||
{
|
||||
auto line = std::static_pointer_cast<isobus::LineAttributes>(child);
|
||||
|
||||
auto vtColour = parentWorkingSet->get_colour(line->get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
g.drawEllipse(0, 0, get_width(), get_height(), line->get_width());
|
||||
}
|
||||
}
|
||||
}
|
||||
49
AgIsoVirtualTerminal/src/OutputLineComponent.cpp
Normal file
49
AgIsoVirtualTerminal/src/OutputLineComponent.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputLineComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputLineComponent.hpp"
|
||||
|
||||
OutputLineComponent::OutputLineComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputLine sourceObject) :
|
||||
isobus::OutputLine(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
}
|
||||
|
||||
void OutputLineComponent::paint(Graphics &g)
|
||||
{
|
||||
if (isobus::NULL_OBJECT_ID != get_line_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_line_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::LineAttributes == child->get_object_type()))
|
||||
{
|
||||
if ((0 != get_width()) && (0 != get_height()))
|
||||
{
|
||||
auto line = std::static_pointer_cast<isobus::LineAttributes>(child);
|
||||
|
||||
auto vtColour = parentWorkingSet->get_colour(line->get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
|
||||
if (1 == get_height())
|
||||
{
|
||||
g.drawHorizontalLine(0, 0, get_width());
|
||||
}
|
||||
else if (1 == get_width())
|
||||
{
|
||||
g.drawVerticalLine(0, 0, get_height());
|
||||
}
|
||||
else if (LineDirection::BottomLeftToTopRight == get_line_direction())
|
||||
{
|
||||
g.drawLine(0, get_height(), get_width(), 0, line->get_width() + 0.5f);
|
||||
}
|
||||
else // LineDirection::TopLeftToBottomRight
|
||||
{
|
||||
g.drawLine(0, 0, get_width(), get_height(), line->get_width() + 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
155
AgIsoVirtualTerminal/src/OutputLinearBarGraphComponent.cpp
Normal file
155
AgIsoVirtualTerminal/src/OutputLinearBarGraphComponent.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputLinearBarGraphComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputLinearBarGraphComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
OutputLinearBarGraphComponent::OutputLinearBarGraphComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputLinearBarGraph sourceObject) :
|
||||
isobus::OutputLinearBarGraph(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
void OutputLinearBarGraphComponent::paint(Graphics &g)
|
||||
{
|
||||
float valueRatioToMax = static_cast<float>(get_value()) / static_cast<float>(get_max_value());
|
||||
float targetRatioToMax = static_cast<float>(get_target_value()) / static_cast<float>(get_max_value());
|
||||
auto vtBackgroundColour = parentWorkingSet->get_colour(get_colour());
|
||||
auto vtTargetLineColour = parentWorkingSet->get_colour(get_target_line_colour());
|
||||
g.setColour(Colour::fromFloatRGBA(vtBackgroundColour.r, vtBackgroundColour.g, vtBackgroundColour.b, 1.0));
|
||||
|
||||
if (get_option(Options::DrawBorder))
|
||||
{
|
||||
g.drawRect(0, 0, getWidth(), getHeight(), 3);
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto child = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type()))
|
||||
{
|
||||
valueRatioToMax = static_cast<float>(std::static_pointer_cast<isobus::NumberVariable>(child)->get_value()) / static_cast<float>(get_max_value());
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out what kind of bar graph we are
|
||||
if (get_option(Options::BarGraphType))
|
||||
{
|
||||
// Not filled, but has value line
|
||||
|
||||
if (get_option(Options::AxisOrientation))
|
||||
{
|
||||
// X Axis
|
||||
if (get_option(Options::Direction))
|
||||
{
|
||||
// From left
|
||||
g.drawLine(static_cast<float>(get_width()) * valueRatioToMax, 0.0f, static_cast<float>(get_width()) * valueRatioToMax, static_cast<float>(get_height()), 3);
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawVerticalLine(static_cast<float>(get_width()) * targetRatioToMax, 0.0f, static_cast<float>(get_height()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// From right
|
||||
g.drawLine(static_cast<float>(get_width()) * (1.0f - valueRatioToMax), 0.0f, static_cast<float>(get_width()) * (1.0f - valueRatioToMax), static_cast<float>(get_height()), 3);
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawVerticalLine(static_cast<float>(get_width()) * (1.0f - targetRatioToMax), 0.0f, static_cast<float>(get_height()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Y Axis
|
||||
if (get_option(Options::Direction))
|
||||
{
|
||||
// From bottom
|
||||
g.drawLine(0, (1.0f - valueRatioToMax) * getHeight(), getWidth(), (1.0f - valueRatioToMax) * getHeight(), 3);
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawHorizontalLine(static_cast<float>(get_height() * (1.0f - targetRatioToMax)), 0.0f, static_cast<float>(get_width()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// From top
|
||||
g.drawLine(0, valueRatioToMax * getHeight(), getWidth(), valueRatioToMax * getHeight(), 3);
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawHorizontalLine(static_cast<float>(get_height() * targetRatioToMax), 0.0f, static_cast<float>(get_width()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Filled
|
||||
|
||||
if (get_option(Options::AxisOrientation))
|
||||
{
|
||||
// X Axis
|
||||
if (get_option(Options::Direction))
|
||||
{
|
||||
// From left
|
||||
g.fillRect(0.0f, 0.0f, static_cast<float>(get_width()) * valueRatioToMax, static_cast<float>(get_height()));
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawVerticalLine(static_cast<float>(get_width()) * targetRatioToMax, 0.0f, static_cast<float>(get_height()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// From right
|
||||
g.fillRect(static_cast<float>(get_width()) * (1 - valueRatioToMax), 0.0f, static_cast<float>(get_width()) * valueRatioToMax, static_cast<float>(get_height()));
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawVerticalLine(static_cast<float>(get_width()) * (1 - targetRatioToMax), 0.0f, static_cast<float>(get_height()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Y Axis
|
||||
if (get_option(Options::Direction))
|
||||
{
|
||||
// From bottom
|
||||
g.fillRect(0.0f, static_cast<float>(get_height() * (1 - valueRatioToMax)), static_cast<float>(get_width()), static_cast<float>(get_height()) * valueRatioToMax);
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawHorizontalLine(static_cast<float>(get_height() * (1 - targetRatioToMax)), 0.0f, static_cast<float>(get_width()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// From top
|
||||
g.fillRect(0.0f, 0.0f, static_cast<float>(get_width()), static_cast<float>(get_height()) * valueRatioToMax);
|
||||
|
||||
if (get_option(Options::DrawTargetLine))
|
||||
{
|
||||
g.setColour(Colour::fromFloatRGBA(vtTargetLineColour.r, vtTargetLineColour.g, vtTargetLineColour.b, 1.0));
|
||||
g.drawHorizontalLine(static_cast<float>(get_height() * targetRatioToMax), 0.0f, static_cast<float>(get_width()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
AgIsoVirtualTerminal/src/OutputMeterComponent.cpp
Normal file
112
AgIsoVirtualTerminal/src/OutputMeterComponent.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputMeterComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputMeterComponent.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
OutputMeterComponent::OutputMeterComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputMeter sourceObject) :
|
||||
isobus::OutputMeter(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
void OutputMeterComponent::paint(Graphics &g)
|
||||
{
|
||||
if (get_option(Options::DrawBorder))
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(get_border_colour());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
g.drawRect(0, 0, static_cast<int>(get_width()), static_cast<int>(get_height()), 1);
|
||||
}
|
||||
if (get_option(Options::DrawArc))
|
||||
{
|
||||
Path p;
|
||||
PathStrokeType pathStroke(1.0f, PathStrokeType::JointStyle::curved);
|
||||
|
||||
float startVtAngle = get_start_angle() * 2.0f * 0.0174533f;
|
||||
float endVtAngle = get_end_angle() * 2.0f * 0.0174533f;
|
||||
float ellipseRotation = 3.14159f / 2.0f;
|
||||
|
||||
if (endVtAngle < startVtAngle)
|
||||
{
|
||||
endVtAngle += (2.0f * 3.14159f);
|
||||
}
|
||||
|
||||
if (startVtAngle < endVtAngle)
|
||||
{
|
||||
ellipseRotation = -ellipseRotation;
|
||||
}
|
||||
|
||||
p.addCentredArc(static_cast<float>(get_width()) / 2.0f, static_cast<float>(get_height()) / 2.0f, static_cast<float>(get_width()) / 2.0f, static_cast<float>(get_height()) / 2.0f, ellipseRotation, startVtAngle, endVtAngle, true);
|
||||
g.setColour(Colours::black);
|
||||
g.strokePath(p, pathStroke);
|
||||
}
|
||||
|
||||
std::uint32_t needleValue = get_value();
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto varNum = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != varNum) && (isobus::VirtualTerminalObjectType::NumberVariable == varNum->get_object_type()))
|
||||
{
|
||||
needleValue = std::static_pointer_cast<isobus::NumberVariable>(varNum)->get_value();
|
||||
}
|
||||
}
|
||||
auto vtColour = parentWorkingSet->get_colour(get_needle_colour());
|
||||
Path needlePath;
|
||||
float endVtAngleDeg = get_end_angle() * 2.0f;
|
||||
float startVtAngleDeg = get_start_angle() * 2.0f;
|
||||
|
||||
if (endVtAngleDeg < startVtAngleDeg)
|
||||
{
|
||||
endVtAngleDeg += (360);
|
||||
}
|
||||
|
||||
float theta = (static_cast<float>(needleValue) / get_max_value()) * (startVtAngleDeg - endVtAngleDeg);
|
||||
float needleEndAngle = 0.0f;
|
||||
|
||||
if (true == get_option(Options::DeflectionDirection))
|
||||
{
|
||||
// clockwise
|
||||
needleEndAngle = (endVtAngleDeg + theta);
|
||||
}
|
||||
else
|
||||
{
|
||||
// counter clockwise
|
||||
needleEndAngle = (endVtAngleDeg - theta);
|
||||
}
|
||||
|
||||
float xOffset = (get_width() / 2.0f) * std::cos(needleEndAngle * 3.14159265f / 180.0f);
|
||||
float yOffset = -(get_width() / 2.0f) * std::sin(needleEndAngle * 3.14159265f / 180.0f);
|
||||
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
g.drawLine((get_width() / 2.0f) + xOffset, (get_width() / 2.0f) + yOffset, get_width() / 2.0f, get_height() / 2.0f, 3.0f);
|
||||
|
||||
g.setColour(Colours::black);
|
||||
if ((get_option(Options::DrawTicks)) && (get_number_of_ticks() > 0))
|
||||
{
|
||||
//float degreesPerTick = ((get_start_angle() * 2.0f) - (get_end_angle() * 2.0f)) / static_cast<float>(get_number_of_ticks());
|
||||
|
||||
//for (std::uint8_t i = 0; i < get_number_of_ticks(); i++)
|
||||
//{
|
||||
// if (true == get_option(Options::DeflectionDirection))
|
||||
// {
|
||||
// // clockwise
|
||||
// needleEndAngle = (get_end_angle() * 2.0f) + (degreesPerTick * i);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // counter clockwise
|
||||
// needleEndAngle = (get_end_angle() * 2.0f) - (degreesPerTick * i);
|
||||
// }
|
||||
// xCoord = (get_width() / 2.0f) * std::cos(needleEndAngle * 3.14159265f / 180.0f);
|
||||
// yCoord = (get_width() / 2.0f) * std::sin(needleEndAngle * 3.14159265f / 180.0f);
|
||||
// g.drawLine((get_width() / 2) + xCoord, (get_height() / 2) + yCoord, (get_width() / 2) * 0.9f + xCoord, (get_height() / 2) *0.9f + yCoord, 3.0f);
|
||||
//}
|
||||
}
|
||||
}
|
||||
174
AgIsoVirtualTerminal/src/OutputNumberComponent.cpp
Normal file
174
AgIsoVirtualTerminal/src/OutputNumberComponent.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputNumberComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputNumberComponent.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
OutputNumberComponent::OutputNumberComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputNumber sourceObject) :
|
||||
isobus::OutputNumber(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
|
||||
if (get_option(Options::Transparent))
|
||||
{
|
||||
setOpaque(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
setOpaque(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OutputNumberComponent::paint(Graphics &g)
|
||||
{
|
||||
if (isOpaque())
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
|
||||
float scaledValue = (get_value() + get_offset()) * get_scale();
|
||||
g.setColour(getLookAndFeel().findColour(ListBox::textColourId));
|
||||
|
||||
// Get font data
|
||||
if (isobus::NULL_OBJECT_ID != get_font_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_font_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::FontAttributes == child->get_object_type()))
|
||||
{
|
||||
auto font = std::static_pointer_cast<isobus::FontAttributes>(child);
|
||||
|
||||
auto colour = parentWorkingSet->get_colour(font->get_colour());
|
||||
Font juceFont(Font::getDefaultMonospacedFontName(), font->get_font_height_pixels(), Font::FontStyleFlags::plain);
|
||||
auto fontWidth = juceFont.getStringWidthFloat("1");
|
||||
juceFont.setHorizontalScale(static_cast<float>(font->get_font_width_pixels()) / fontWidth);
|
||||
g.setColour(Colour::fromFloatRGBA(colour.r, colour.g, colour.b, 1.0f));
|
||||
g.setFont(juceFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_variable_reference())
|
||||
{
|
||||
auto child = get_object_by_id(get_variable_reference(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type()))
|
||||
{
|
||||
std::int64_t offsetValue = static_cast<std::int64_t>(std::static_pointer_cast<isobus::NumberVariable>(child)->get_value()) + get_offset();
|
||||
scaledValue = offsetValue * get_scale();
|
||||
}
|
||||
}
|
||||
|
||||
if (get_option(isobus::OutputNumber::Options::DisplayZeroAsBlank) && scaledValue == 0.0f)
|
||||
{
|
||||
// When this option bit is set, a blank field is displayed if and only if the displayed value of the object is exactly zero.
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream valueText;
|
||||
valueText << std::fixed << std::setprecision(get_number_of_decimals()) << scaledValue;
|
||||
g.drawText(valueText.str(), 0, 0, get_width(), get_height(), convert_justification(get_horizontal_justification(), get_vertical_justification()), false);
|
||||
}
|
||||
|
||||
Justification OutputNumberComponent::convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification)
|
||||
{
|
||||
Justification retVal = Justification::topLeft;
|
||||
|
||||
switch (horizontalJustification)
|
||||
{
|
||||
case HorizontalJustification::PositionLeft:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionMiddle:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::centredTop;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centred;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::centredBottom;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionRight:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomRight;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
77
AgIsoVirtualTerminal/src/OutputPolygonComponent.cpp
Normal file
77
AgIsoVirtualTerminal/src/OutputPolygonComponent.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputPolygonComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputPolygonComponent.hpp"
|
||||
|
||||
OutputPolygonComponent::OutputPolygonComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputPolygon sourceObject) :
|
||||
isobus::OutputPolygon(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
}
|
||||
|
||||
void OutputPolygonComponent::paint(Graphics &g)
|
||||
{
|
||||
// 3 Points MUST exist or the object cannot be drawn
|
||||
if (get_number_of_points() >= 3)
|
||||
{
|
||||
Path polygonPath;
|
||||
float lineWidth = 0.0f;
|
||||
auto lineColour = Colour::fromFloatRGBA(0.0f, 0.0f, 0.0f, 1.0);
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_line_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_line_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::LineAttributes == child->get_object_type()))
|
||||
{
|
||||
auto line = std::static_pointer_cast<isobus::LineAttributes>(child);
|
||||
lineWidth = line->get_width();
|
||||
auto lineAttributeColour = parentWorkingSet->get_colour(line->get_background_color());
|
||||
|
||||
lineColour = Colour::fromFloatRGBA(lineAttributeColour.r, lineAttributeColour.g, lineAttributeColour.b, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::uint16_t i = 0; i < get_number_of_points() - 1; i++)
|
||||
{
|
||||
const auto thisPoint = get_point(static_cast<std::uint8_t>(i));
|
||||
const auto nextPoint = get_point(static_cast<std::uint8_t>(i + 1));
|
||||
|
||||
if (0 == i)
|
||||
{
|
||||
polygonPath.startNewSubPath(static_cast<float>(thisPoint.xValue), static_cast<float>(thisPoint.yValue));
|
||||
}
|
||||
polygonPath.lineTo(static_cast<float>(nextPoint.xValue), static_cast<float>(nextPoint.yValue));
|
||||
}
|
||||
|
||||
// If the polygon type is not open, it must be closed by us
|
||||
if (PolygonType::Open != get_type())
|
||||
{
|
||||
const auto thisPoint = get_point(static_cast<std::uint8_t>(get_number_of_points() - 1));
|
||||
const auto nextPoint = get_point(0U);
|
||||
|
||||
polygonPath.closeSubPath();
|
||||
}
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_fill_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_fill_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::FillAttributes == child->get_object_type()))
|
||||
{
|
||||
auto fill = std::static_pointer_cast<isobus::FillAttributes>(child);
|
||||
|
||||
auto vtColour = parentWorkingSet->get_colour(fill->get_background_color());
|
||||
g.setFillType(FillType(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f)));
|
||||
g.fillPath(polygonPath);
|
||||
}
|
||||
}
|
||||
|
||||
g.resetToDefaultState();
|
||||
g.setColour(lineColour);
|
||||
g.strokePath(polygonPath, PathStrokeType(lineWidth));
|
||||
}
|
||||
}
|
||||
114
AgIsoVirtualTerminal/src/OutputRectangleComponent.cpp
Normal file
114
AgIsoVirtualTerminal/src/OutputRectangleComponent.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputRectangleComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputRectangleComponent.hpp"
|
||||
|
||||
OutputRectangleComponent::OutputRectangleComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputRectangle sourceObject) :
|
||||
isobus::OutputRectangle(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
}
|
||||
|
||||
void OutputRectangleComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
bool isOpaque = false;
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_fill_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_fill_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::FillAttributes == child->get_object_type()))
|
||||
{
|
||||
auto fill = std::static_pointer_cast<isobus::FillAttributes>(child);
|
||||
|
||||
vtColour = parentWorkingSet->get_colour(fill->get_background_color());
|
||||
switch (std::static_pointer_cast<isobus::FillAttributes>(child)->get_type())
|
||||
{
|
||||
case isobus::FillAttributes::FillType::FillWithPatternGivenByFillPatternAttribute:
|
||||
{
|
||||
// @todo
|
||||
isOpaque = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FillAttributes::FillType::FillWithLineColor:
|
||||
{
|
||||
auto childLineAttributes = get_object_by_id(get_line_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != childLineAttributes) && (isobus::VirtualTerminalObjectType::LineAttributes == childLineAttributes->get_object_type()))
|
||||
{
|
||||
auto line = std::static_pointer_cast<isobus::LineAttributes>(childLineAttributes);
|
||||
vtColour = parentWorkingSet->get_colour(line->get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0));
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
break;
|
||||
}
|
||||
isOpaque = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FillAttributes::FillType::FillWithSpecifiedColorInFillColorAttribute:
|
||||
{
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
isOpaque = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FillAttributes::FillType::NoFill:
|
||||
default:
|
||||
{
|
||||
// No fill
|
||||
isOpaque = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setOpaque(isOpaque);
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != get_line_attributes())
|
||||
{
|
||||
auto child = get_object_by_id(get_line_attributes(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::LineAttributes == child->get_object_type()))
|
||||
{
|
||||
auto line = std::static_pointer_cast<isobus::LineAttributes>(child);
|
||||
|
||||
if (0 != line->get_width())
|
||||
{
|
||||
bool anyLineSuppressed = (0 != get_line_suppression_bitfield());
|
||||
vtColour = parentWorkingSet->get_colour(line->get_background_color());
|
||||
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0));
|
||||
|
||||
if (!anyLineSuppressed)
|
||||
{
|
||||
g.drawRect(0, 0, static_cast<int>(get_width()), static_cast<int>(get_height()), line->get_width());
|
||||
}
|
||||
else // Something is suppressed
|
||||
{
|
||||
if (0 == ((0x01 << static_cast<std::uint8_t>(LineSuppressionOption::SuppressTopLine)) & get_line_suppression_bitfield()))
|
||||
{
|
||||
g.drawLine(0, 0, get_width(), 0, line->get_width());
|
||||
}
|
||||
if (0 == ((0x01 << static_cast<std::uint8_t>(LineSuppressionOption::SuppressLeftSideLine)) & get_line_suppression_bitfield()))
|
||||
{
|
||||
g.drawLine(0, 0, 0, get_height(), line->get_width());
|
||||
}
|
||||
if (0 == ((0x01 << static_cast<std::uint8_t>(LineSuppressionOption::SuppressRightSideLine)) & get_line_suppression_bitfield()))
|
||||
{
|
||||
g.drawLine(get_width(), 0, get_width(), get_height(), line->get_width());
|
||||
}
|
||||
if (0 == ((0x01 << static_cast<std::uint8_t>(LineSuppressionOption::SuppressBottomLine)) & get_line_suppression_bitfield()))
|
||||
{
|
||||
g.drawLine(0, get_height(), get_width(), get_height(), line->get_width());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
262
AgIsoVirtualTerminal/src/OutputStringComponent.cpp
Normal file
262
AgIsoVirtualTerminal/src/OutputStringComponent.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*******************************************************************************
|
||||
** @file OutputStringComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "OutputStringComponent.hpp"
|
||||
|
||||
#include "StringEncodingConversions.hpp"
|
||||
|
||||
OutputStringComponent::OutputStringComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::OutputString sourceObject) :
|
||||
isobus::OutputString(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(get_width(), get_height());
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
void OutputStringComponent::paint(Graphics &g)
|
||||
{
|
||||
std::string value = displayed_value(parentWorkingSet);
|
||||
|
||||
std::size_t pos = value.find('\0');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
value = value.substr(0, pos);
|
||||
}
|
||||
|
||||
std::uint8_t fontHeight = 0;
|
||||
auto fontType = isobus::FontAttributes::FontType::ISO8859_1;
|
||||
|
||||
if (!get_option(Options::Transparent))
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(get_background_color());
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
|
||||
g.setColour(getLookAndFeel().findColour(ListBox::textColourId));
|
||||
|
||||
// Get font data
|
||||
auto fontAttrID = get_font_attributes();
|
||||
|
||||
if (isobus::NULL_OBJECT_ID != fontAttrID)
|
||||
{
|
||||
auto child = get_object_by_id(fontAttrID, parentWorkingSet->get_object_tree());
|
||||
|
||||
if (isobus::VirtualTerminalObjectType::FontAttributes == child->get_object_type())
|
||||
{
|
||||
auto font = std::static_pointer_cast<isobus::FontAttributes>(child);
|
||||
|
||||
fontType = font->get_type();
|
||||
auto colour = parentWorkingSet->get_colour(font->get_colour());
|
||||
Font juceFont;
|
||||
int fontStyleFlags = Font::FontStyleFlags::plain;
|
||||
|
||||
if (font->get_style(isobus::FontAttributes::FontStyleBits::Bold))
|
||||
{
|
||||
fontStyleFlags |= Font::FontStyleFlags::bold;
|
||||
}
|
||||
|
||||
if (font->get_style(isobus::FontAttributes::FontStyleBits::Italic))
|
||||
{
|
||||
fontStyleFlags |= Font::FontStyleFlags::italic;
|
||||
}
|
||||
|
||||
if (font->get_style(isobus::FontAttributes::FontStyleBits::Underlined))
|
||||
{
|
||||
fontStyleFlags |= Font::FontStyleFlags::underlined;
|
||||
}
|
||||
|
||||
juceFont = Font(Font::getDefaultMonospacedFontName(), font->get_font_height_pixels(), fontStyleFlags);
|
||||
|
||||
auto fontWidth = juceFont.getStringWidthFloat("a");
|
||||
fontHeight = font->get_font_width_pixels();
|
||||
juceFont.setHorizontalScale(static_cast<float>(font->get_font_width_pixels()) / fontWidth);
|
||||
g.setColour(Colour::fromFloatRGBA(colour.r, colour.g, colour.b, 1.0f));
|
||||
g.setFont(juceFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == fontHeight)
|
||||
{
|
||||
fontHeight = 8;
|
||||
}
|
||||
|
||||
String decodedValue(value);
|
||||
|
||||
if ((value.length() >= 2) &&
|
||||
(0xFF == static_cast<std::uint8_t>(value.at(0))) &&
|
||||
(0xFE == static_cast<std::uint8_t>(value.at(1))))
|
||||
{
|
||||
// String is UTF-16 encoded, font type is ignored.
|
||||
if (0 != (value.length() % 2))
|
||||
{
|
||||
// If the length attribute does not indicate an even number of bytes the last byte is ignored
|
||||
value.pop_back();
|
||||
}
|
||||
decodedValue = String::createStringFromData(value.c_str(), value.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (fontType)
|
||||
{
|
||||
case isobus::FontAttributes::FontType::ISO8859_1:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_1, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_15:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_15, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_2:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_2, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_4:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_4, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_5:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_5, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
|
||||
case isobus::FontAttributes::FontType::ISO8859_7:
|
||||
{
|
||||
std::string utf8String;
|
||||
convert_string_to_utf_8(SourceEncoding::ISO8859_7, value, utf8String, get_option(Options::AutoWrap));
|
||||
decodedValue = utf8String;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_option(Options::AutoWrap)) // TODO need to figure out proper font clipping
|
||||
{
|
||||
g.drawFittedText(decodedValue, 0, 0, get_width(), get_height(), convert_justification(get_horizontal_justification(), get_vertical_justification()), static_cast<int>(std::floor((static_cast<float>(get_height()) + 0.1f) / fontHeight)), 0.8f);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.drawFittedText(decodedValue, 0, 0, get_width(), get_height(), convert_justification(get_horizontal_justification(), get_vertical_justification()), static_cast<int>(std::floor((static_cast<float>(get_height()) + 0.1f) / fontHeight)), 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
Justification OutputStringComponent::convert_justification(HorizontalJustification horizontalJustification, VerticalJustification verticalJustification)
|
||||
{
|
||||
Justification retVal = Justification::topLeft;
|
||||
|
||||
switch (horizontalJustification)
|
||||
{
|
||||
case HorizontalJustification::PositionLeft:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomLeft;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionMiddle:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::centredTop;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centred;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::centredBottom;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HorizontalJustification::PositionRight:
|
||||
{
|
||||
switch (verticalJustification)
|
||||
{
|
||||
case VerticalJustification::PositionTop:
|
||||
{
|
||||
retVal = Justification::topRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionMiddle:
|
||||
{
|
||||
retVal = Justification::centredRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::PositionBottom:
|
||||
{
|
||||
retVal = Justification::bottomRight;
|
||||
}
|
||||
break;
|
||||
|
||||
case VerticalJustification::Reserved:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
49
AgIsoVirtualTerminal/src/PictureGraphicComponent.cpp
Normal file
49
AgIsoVirtualTerminal/src/PictureGraphicComponent.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
** @file PictureGraphicComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "PictureGraphicComponent.hpp"
|
||||
|
||||
PictureGraphicComponent::PictureGraphicComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::PictureGraphic sourceObject) :
|
||||
isobus::PictureGraphic(sourceObject),
|
||||
parentWorkingSet(workingSet),
|
||||
reconstructedImage(Image::PixelFormat::ARGB, get_actual_width(), get_actual_height(), true)
|
||||
{
|
||||
generate_and_store_image();
|
||||
setSize(PictureGraphic::get_width(), PictureGraphic::get_height());
|
||||
}
|
||||
|
||||
void PictureGraphicComponent::generate_and_store_image()
|
||||
{
|
||||
auto &rawPictureGraphicData = get_raw_data();
|
||||
std::size_t pixelIndex = 0;
|
||||
bool transparencyEnabled = get_option(Options::Transparent);
|
||||
|
||||
for (std::uint_fast16_t i = 0; i < get_actual_height(); i++)
|
||||
{
|
||||
for (std::uint_fast16_t j = 0; j < get_actual_width(); j++)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(rawPictureGraphicData.at(pixelIndex));
|
||||
if (transparencyEnabled)
|
||||
{
|
||||
reconstructedImage.setPixelAt(j, i, Colour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, rawPictureGraphicData.at(pixelIndex) == this->get_transparency_colour() ? 0.0f : 1.0f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
reconstructedImage.setPixelAt(j, i, Colour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f)));
|
||||
}
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((get_actual_height() != get_height()) || (get_actual_width() != get_width()))
|
||||
{
|
||||
reconstructedImage = reconstructedImage.rescaled(get_width(), get_height());
|
||||
}
|
||||
}
|
||||
|
||||
void PictureGraphicComponent::paint(Graphics &g)
|
||||
{
|
||||
g.drawImage(reconstructedImage, getLocalBounds().toFloat());
|
||||
}
|
||||
1724
AgIsoVirtualTerminal/src/ServerMainComponent.cpp
Normal file
1724
AgIsoVirtualTerminal/src/ServerMainComponent.cpp
Normal file
File diff suppressed because it is too large
Load Diff
71
AgIsoVirtualTerminal/src/ShortcutsWindow.cpp
Normal file
71
AgIsoVirtualTerminal/src/ShortcutsWindow.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*******************************************************************************
|
||||
** @file ShortcutsWindow.cpp
|
||||
** @author Miklos Marton
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "ShortcutsWindow.hpp"
|
||||
|
||||
ShortcutsWindow::ShortcutsWindow(int alarmAckKeyCode, Component *associatedComponent) :
|
||||
juce::AlertWindow("Keyboard shortcuts", "", MessageBoxIconType::NoIcon, associatedComponent),
|
||||
alarmAckKey(alarmAckKeyCode)
|
||||
{
|
||||
juce::KeyPress alarmAckKey(alarmAckKeyCode);
|
||||
addCustomComponent(&selectAlarmAckKeyButton);
|
||||
selectAlarmAckKeyButton.onClick = [this]() { setAlarmAckKeySelection(true); };
|
||||
updateAlarmAckButtonLabel(alarmAckKey);
|
||||
|
||||
addButton("OK", 5, KeyPress(KeyPress::returnKey, 0, 0));
|
||||
addButton("Cancel", 0);
|
||||
|
||||
setAlarmAckKeySelection(false);
|
||||
}
|
||||
|
||||
void ShortcutsWindow::resized()
|
||||
{
|
||||
auto area = getLocalBounds();
|
||||
auto customArea = area.removeFromTop(40).removeFromLeft(area.getWidth() / 1.2);
|
||||
selectAlarmAckKeyButton.setBounds(customArea);
|
||||
}
|
||||
|
||||
bool ShortcutsWindow::keyPressed(const KeyPress &key, Component *originatingComponent)
|
||||
{
|
||||
if (keySelectionMode)
|
||||
{
|
||||
alarmAckKey = key.getKeyCode();
|
||||
setAlarmAckKeySelection(false);
|
||||
updateAlarmAckButtonLabel(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ShortcutsWindow::alarmAckKeyCode() const
|
||||
{
|
||||
return alarmAckKey;
|
||||
}
|
||||
|
||||
void ShortcutsWindow::updateAlarmAckButtonLabel(const KeyPress &key)
|
||||
{
|
||||
selectAlarmAckKeyButton.setButtonText("Alarm acknowledge key: " + key.getTextDescription());
|
||||
}
|
||||
|
||||
void ShortcutsWindow::setAlarmAckKeySelection(bool isEnabled)
|
||||
{
|
||||
keySelectionMode = isEnabled;
|
||||
selectAlarmAckKeyButton.setEnabled(!isEnabled);
|
||||
if (isEnabled)
|
||||
{
|
||||
selectAlarmAckKeyButton.setButtonText("Alarm acknowledge key: press one key...");
|
||||
|
||||
setWantsKeyboardFocus(true);
|
||||
addKeyListener(this);
|
||||
grabKeyboardFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
setWantsKeyboardFocus(false);
|
||||
removeKeyListener(this);
|
||||
if (hasKeyboardFocus(false))
|
||||
giveAwayKeyboardFocus();
|
||||
}
|
||||
}
|
||||
78
AgIsoVirtualTerminal/src/SoftKeyMaskComponent.cpp
Normal file
78
AgIsoVirtualTerminal/src/SoftKeyMaskComponent.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
** @file SoftKeyMaskComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "SoftKeyMaskComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
#include "SoftKeyMaskRenderAreaComponent.hpp"
|
||||
|
||||
SoftKeyMaskComponent::SoftKeyMaskComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::SoftKeyMask sourceObject, SoftKeyMaskDimensions dimensions) :
|
||||
isobus::SoftKeyMask(sourceObject),
|
||||
parentWorkingSet(workingSet),
|
||||
dimensionInfo(dimensions)
|
||||
{
|
||||
setOpaque(true);
|
||||
setBounds(0, 0, dimensions.total_width(), dimensions.height);
|
||||
on_content_changed(true);
|
||||
}
|
||||
|
||||
void SoftKeyMaskComponent::on_content_changed(bool initial)
|
||||
{
|
||||
int row = 0;
|
||||
int x = dimensionInfo.PADDING + (dimensionInfo.columnCount - 1) * (dimensionInfo.PADDING + dimensionInfo.keyWidth);
|
||||
int y = dimensionInfo.PADDING;
|
||||
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (isobus::VirtualTerminalObjectType::ObjectPointer == child->get_object_type())
|
||||
{
|
||||
childComponents.back()->setSize(dimensionInfo.keyWidth, dimensionInfo.keyHeight);
|
||||
}
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
childComponents.back()->setTopLeftPosition(x, y);
|
||||
y += (dimensionInfo.PADDING + dimensionInfo.keyWidth);
|
||||
|
||||
row++;
|
||||
if (row >= dimensionInfo.rowCount)
|
||||
{
|
||||
row = 0;
|
||||
x -= (dimensionInfo.PADDING + dimensionInfo.keyWidth);
|
||||
y = dimensionInfo.PADDING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void SoftKeyMaskComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(backgroundColor);
|
||||
|
||||
g.fillAll(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
|
||||
}
|
||||
|
||||
int SoftKeyMaskDimensions::key_count() const
|
||||
{
|
||||
return columnCount * rowCount;
|
||||
}
|
||||
|
||||
int SoftKeyMaskDimensions::total_width() const
|
||||
{
|
||||
return PADDING + (columnCount * (keyWidth + PADDING));
|
||||
}
|
||||
290
AgIsoVirtualTerminal/src/SoftkeyMaskRenderArea.cpp
Normal file
290
AgIsoVirtualTerminal/src/SoftkeyMaskRenderArea.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
/*******************************************************************************
|
||||
** @file SoftKeyMaskRenderAreaComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
#include "ServerMainComponent.hpp"
|
||||
#include "SoftKeyMaskRenderAreaComponent.hpp"
|
||||
|
||||
SoftKeyMaskRenderAreaComponent::SoftKeyMaskRenderAreaComponent(ServerMainComponent &parentServer) :
|
||||
ownerServer(parentServer)
|
||||
{
|
||||
//addMouseListener(this, true);
|
||||
}
|
||||
|
||||
void SoftKeyMaskRenderAreaComponent::on_change_active_mask(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet)
|
||||
{
|
||||
childComponents.clear();
|
||||
parentWorkingSet = workingSet;
|
||||
|
||||
if (parentWorkingSet)
|
||||
{
|
||||
auto workingSetObject = std::static_pointer_cast<isobus::WorkingSet>(parentWorkingSet->get_working_set_object());
|
||||
|
||||
if ((nullptr != workingSetObject) && (isobus::NULL_OBJECT_ID != workingSetObject->get_active_mask()))
|
||||
{
|
||||
auto activeMask = parentWorkingSet->get_object_by_id(workingSetObject->get_active_mask());
|
||||
|
||||
if (nullptr != activeMask)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::AlarmMask == activeMask->get_object_type())
|
||||
{
|
||||
auto child = activeMask->get_object_by_id(std::static_pointer_cast<isobus::AlarmMask>(activeMask)->get_soft_key_mask(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask == child->get_object_type()))
|
||||
{
|
||||
childComponents.emplace_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
}
|
||||
}
|
||||
else if (isobus::VirtualTerminalObjectType::DataMask == activeMask->get_object_type())
|
||||
{
|
||||
auto child = activeMask->get_object_by_id(std::static_pointer_cast<isobus::DataMask>(activeMask)->get_soft_key_mask(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask == child->get_object_type()))
|
||||
{
|
||||
childComponents.emplace_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
void SoftKeyMaskRenderAreaComponent::on_working_set_disconnect(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet)
|
||||
{
|
||||
if ((nullptr != workingSet) && (workingSet == parentWorkingSet))
|
||||
{
|
||||
parentWorkingSet = nullptr;
|
||||
childComponents.clear();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void SoftKeyMaskRenderAreaComponent::paint(Graphics &g)
|
||||
{
|
||||
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
|
||||
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
g.drawRect(0, 0, getWidth(), getHeight(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void SoftKeyMaskRenderAreaComponent::mouseDown(const MouseEvent &event)
|
||||
{
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
// Do a top down search to see if they clicked on some interactable object
|
||||
auto workingSetObject = std::static_pointer_cast<isobus::WorkingSet>(parentWorkingSet->get_working_set_object());
|
||||
|
||||
if (nullptr != workingSetObject)
|
||||
{
|
||||
auto activeMask = parentWorkingSet->get_object_by_id(workingSetObject->get_active_mask());
|
||||
auto parentMask = activeMask;
|
||||
|
||||
if (isobus::VirtualTerminalObjectType::AlarmMask == activeMask->get_object_type())
|
||||
{
|
||||
auto child = activeMask->get_object_by_id(std::static_pointer_cast<isobus::AlarmMask>(activeMask)->get_soft_key_mask(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask == child->get_object_type()))
|
||||
{
|
||||
activeMask = child;
|
||||
}
|
||||
}
|
||||
else if (isobus::VirtualTerminalObjectType::DataMask == activeMask->get_object_type())
|
||||
{
|
||||
auto child = activeMask->get_object_by_id(std::static_pointer_cast<isobus::DataMask>(activeMask)->get_soft_key_mask(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask == child->get_object_type()))
|
||||
{
|
||||
activeMask = child;
|
||||
}
|
||||
}
|
||||
|
||||
auto relativeEvent = event.getEventRelativeTo(this);
|
||||
auto clickedObject = getClickedChildRecursive(activeMask, relativeEvent.getMouseDownX(), relativeEvent.getMouseDownY());
|
||||
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnKeyPress, isobus::VirtualTerminalObjectType::Key, parentWorkingSet);
|
||||
|
||||
std::uint8_t keyCode = 1;
|
||||
|
||||
if (nullptr != clickedObject)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::Key == clickedObject->get_object_type())
|
||||
{
|
||||
keyCode = std::static_pointer_cast<isobus::Key>(clickedObject)->get_key_code();
|
||||
}
|
||||
|
||||
ownerServer.send_soft_key_activation_message(isobus::VirtualTerminalBase::KeyActivationCode::ButtonPressedOrLatched,
|
||||
clickedObject->get_id(),
|
||||
parentMask->get_id(),
|
||||
keyCode,
|
||||
ownerServer.get_active_working_set()->get_control_function());
|
||||
ownerServer.set_button_held(ownerServer.get_active_working_set(),
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoftKeyMaskRenderAreaComponent::mouseUp(const MouseEvent &event)
|
||||
{
|
||||
if (nullptr != parentWorkingSet)
|
||||
{
|
||||
// Do a top down search to see if they clicked on some interactable object
|
||||
auto workingSetObject = std::static_pointer_cast<isobus::WorkingSet>(parentWorkingSet->get_working_set_object());
|
||||
|
||||
if (nullptr != workingSetObject)
|
||||
{
|
||||
auto activeMask = parentWorkingSet->get_object_by_id(workingSetObject->get_active_mask());
|
||||
auto parentMask = activeMask;
|
||||
|
||||
if (isobus::VirtualTerminalObjectType::AlarmMask == activeMask->get_object_type())
|
||||
{
|
||||
auto child = activeMask->get_object_by_id(std::static_pointer_cast<isobus::AlarmMask>(activeMask)->get_soft_key_mask(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask == child->get_object_type()))
|
||||
{
|
||||
activeMask = child;
|
||||
}
|
||||
}
|
||||
else if (isobus::VirtualTerminalObjectType::DataMask == activeMask->get_object_type())
|
||||
{
|
||||
auto child = activeMask->get_object_by_id(std::static_pointer_cast<isobus::DataMask>(activeMask)->get_soft_key_mask(), parentWorkingSet->get_object_tree());
|
||||
|
||||
if ((nullptr != child) && (isobus::VirtualTerminalObjectType::SoftKeyMask == child->get_object_type()))
|
||||
{
|
||||
activeMask = child;
|
||||
}
|
||||
}
|
||||
|
||||
auto relativeEvent = event.getEventRelativeTo(this);
|
||||
auto clickedObject = getClickedChildRecursive(activeMask, relativeEvent.getPosition().x, relativeEvent.getPosition().y);
|
||||
|
||||
ownerServer.process_macro(clickedObject, isobus::EventID::OnKeyRelease, isobus::VirtualTerminalObjectType::Key, parentWorkingSet);
|
||||
|
||||
std::uint8_t keyCode = 1;
|
||||
|
||||
if (nullptr != clickedObject)
|
||||
{
|
||||
if (isobus::VirtualTerminalObjectType::Key == clickedObject->get_object_type())
|
||||
{
|
||||
keyCode = std::static_pointer_cast<isobus::Key>(clickedObject)->get_key_code();
|
||||
}
|
||||
|
||||
ownerServer.send_soft_key_activation_message(isobus::VirtualTerminalBase::KeyActivationCode::ButtonUnlatchedOrReleased,
|
||||
clickedObject->get_id(),
|
||||
parentMask->get_id(),
|
||||
keyCode,
|
||||
ownerServer.get_active_working_set()->get_control_function());
|
||||
ownerServer.set_button_released(ownerServer.get_active_working_set(),
|
||||
clickedObject->get_id(),
|
||||
activeMask->get_id(),
|
||||
keyCode,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<isobus::VTObject> SoftKeyMaskRenderAreaComponent::getClickedChildRecursive(std::shared_ptr<isobus::VTObject> object, int x, int y)
|
||||
{
|
||||
std::shared_ptr<isobus::VTObject> retVal;
|
||||
|
||||
if ((nullptr == object) ||
|
||||
((isobus::VirtualTerminalObjectType::ObjectPointer != object->get_object_type()) &&
|
||||
(0 == object->get_number_children())))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isobus::VirtualTerminalObjectType::ObjectPointer == object->get_object_type())
|
||||
{
|
||||
auto child = object->get_object_by_id(std::static_pointer_cast<isobus::ObjectPointer>(object)->get_value(), parentWorkingSet->get_object_tree());
|
||||
|
||||
// Knowing the location requires some knowledge of how the mask is displaying each key...
|
||||
|
||||
if ((nullptr != child) &&
|
||||
(objectCanBeClicked(child)) &&
|
||||
(isClickWithinBounds(x, y, 0, 0, ownerServer.get_soft_key_descriptor_x_pixel_width(), ownerServer.get_soft_key_descriptor_y_pixel_height())))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
else if (!objectCanBeClicked(child))
|
||||
{
|
||||
retVal = getClickedChildRecursive(child, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int row = 0, col = (ownerServer.get_physical_soft_key_columns() - 1);
|
||||
for (std::uint16_t i = 0; i < object->get_number_children(); i++)
|
||||
{
|
||||
auto child = object->get_object_by_id(object->get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
// Knowing the location requires some knowledge of how the mask is displaying each key...
|
||||
|
||||
int colX = SoftKeyMaskDimensions::PADDING + col * (ownerServer.get_soft_key_descriptor_x_pixel_width() + SoftKeyMaskDimensions::PADDING);
|
||||
int rowY = SoftKeyMaskDimensions::PADDING + row * (ownerServer.get_soft_key_descriptor_y_pixel_height() + SoftKeyMaskDimensions::PADDING);
|
||||
if ((nullptr != child) &&
|
||||
(objectCanBeClicked(child)) &&
|
||||
(isClickWithinBounds(x, y, colX, rowY, ownerServer.get_soft_key_descriptor_x_pixel_width(), ownerServer.get_soft_key_descriptor_y_pixel_height())))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
else if (!objectCanBeClicked(child))
|
||||
{
|
||||
retVal = getClickedChildRecursive(child, x - colX, y - rowY);
|
||||
|
||||
if (nullptr != retVal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
row++;
|
||||
if (row >= ownerServer.get_physical_soft_key_rows())
|
||||
{
|
||||
row = 0;
|
||||
col--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool SoftKeyMaskRenderAreaComponent::objectCanBeClicked(std::shared_ptr<isobus::VTObject> object)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
||||
if (nullptr != object)
|
||||
{
|
||||
switch (object->get_object_type())
|
||||
{
|
||||
case isobus::VirtualTerminalObjectType::Key:
|
||||
{
|
||||
retVal = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
retVal = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool SoftKeyMaskRenderAreaComponent::isClickWithinBounds(int clickXRelative, int clickYRelative, int objectX, int objectY, int objectWidth, int objectHeight)
|
||||
{
|
||||
return ((clickXRelative >= objectX) && (clickXRelative <= (objectX + objectWidth))) &&
|
||||
((clickYRelative >= objectY) && (clickYRelative <= (objectY + objectHeight)));
|
||||
}
|
||||
239
AgIsoVirtualTerminal/src/StringEncodingConversions.cpp
Normal file
239
AgIsoVirtualTerminal/src/StringEncodingConversions.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
//================================================================================================
|
||||
/// @file StringEncodingConversions.cpp
|
||||
///
|
||||
/// @brief Helper functions for converting ISO 11783's string encodings to UTF-8
|
||||
/// @author Adrian Del Grosso
|
||||
///
|
||||
/// @copyright 2024 Adrian Del Grosso
|
||||
//================================================================================================
|
||||
#include "StringEncodingConversions.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Tables below courtesy of Tutf8e, used under MIT License
|
||||
// https://github.com/nigels-com/tutf8e
|
||||
|
||||
// clang-format off
|
||||
constexpr std::uint16_t iso_8859_1_utf8[256] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
|
||||
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
|
||||
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
|
||||
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
|
||||
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
|
||||
0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
|
||||
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
|
||||
};
|
||||
|
||||
constexpr std::uint16_t iso_8859_15_utf8[256] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
|
||||
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0160, 0x00a7, 0x0161, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
|
||||
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x017d, 0x00b5, 0x00b6, 0x00b7, 0x017e, 0x00b9, 0x00ba, 0x00bb, 0x0152, 0x0153, 0x0178, 0x00bf,
|
||||
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
|
||||
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
|
||||
0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
|
||||
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
|
||||
};
|
||||
|
||||
constexpr std::uint16_t iso_8859_2_utf8[256] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
|
||||
0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7, 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b,
|
||||
0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7, 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c,
|
||||
0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
|
||||
0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
|
||||
0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
|
||||
0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
|
||||
};
|
||||
|
||||
constexpr std::uint16_t iso_8859_4_utf8[256] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
|
||||
0x00a0, 0x0104, 0x0138, 0x0156, 0x00a4, 0x0128, 0x013b, 0x00a7, 0x00a8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00ad, 0x017d, 0x00af,
|
||||
0x00b0, 0x0105, 0x02db, 0x0157, 0x00b4, 0x0129, 0x013c, 0x02c7, 0x00b8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014a, 0x017e, 0x014b,
|
||||
0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x012a,
|
||||
0x0110, 0x0145, 0x014c, 0x0136, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x0168, 0x016a, 0x00df,
|
||||
0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x012b,
|
||||
0x0111, 0x0146, 0x014d, 0x0137, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x0169, 0x016b, 0x02d9,
|
||||
};
|
||||
|
||||
constexpr std::uint16_t iso_8859_5_utf8[256] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
|
||||
0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f,
|
||||
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
|
||||
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
|
||||
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
|
||||
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
|
||||
0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f,
|
||||
};
|
||||
|
||||
constexpr std::uint16_t iso_8859_7_utf8[256] =
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
|
||||
0x00a0, 0x2018, 0x2019, 0x00a3, 0x20ac, 0x20af, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x037a, 0x00ab, 0x00ac, 0x00ad, 0xffff, 0x2015,
|
||||
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x0385, 0x0386, 0x00b7, 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,
|
||||
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
|
||||
0x03a0, 0x03a1, 0xffff, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
|
||||
0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
|
||||
0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0xffff,
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
static const uint16_t *getTable(SourceEncoding encoding)
|
||||
{
|
||||
const uint16_t *retVal = nullptr;
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case SourceEncoding::ISO8859_1:
|
||||
{
|
||||
retVal = iso_8859_1_utf8;
|
||||
}
|
||||
break;
|
||||
|
||||
case SourceEncoding::ISO8859_2:
|
||||
{
|
||||
retVal = iso_8859_2_utf8;
|
||||
}
|
||||
break;
|
||||
|
||||
case SourceEncoding::ISO8859_4:
|
||||
{
|
||||
retVal = iso_8859_4_utf8;
|
||||
}
|
||||
break;
|
||||
|
||||
case SourceEncoding::ISO8859_5:
|
||||
{
|
||||
retVal = iso_8859_5_utf8;
|
||||
}
|
||||
break;
|
||||
|
||||
case SourceEncoding::ISO8859_7:
|
||||
{
|
||||
retVal = iso_8859_7_utf8;
|
||||
}
|
||||
break;
|
||||
|
||||
case SourceEncoding::ISO8859_15:
|
||||
{
|
||||
retVal = iso_8859_15_utf8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void add_character(uint16_t character, std::string &output)
|
||||
{
|
||||
if (character < 0x80)
|
||||
{
|
||||
output.push_back(character);
|
||||
}
|
||||
else if (character < 0x800)
|
||||
{
|
||||
output.push_back(0xC0 | (character >> 6));
|
||||
output.push_back(0x80 | (character & 0x3F));
|
||||
}
|
||||
else if (character < 0xFFFF)
|
||||
{
|
||||
output.push_back(0xe0 | (character >> 12));
|
||||
output.push_back(0x80 | ((character >> 6) & 0x3F));
|
||||
output.push_back(0x80 | (character & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
void convert_string_to_utf_8(SourceEncoding encoding, const std::string &input, std::string &output, bool autoWrappingEnabled)
|
||||
{
|
||||
auto table = getTable(encoding);
|
||||
auto input_length = input.size();
|
||||
output.reserve(input_length);
|
||||
|
||||
for (const unsigned char encodedChar : input)
|
||||
{
|
||||
uint16_t newCharacter = table[encodedChar];
|
||||
|
||||
if (((static_cast<std::uint8_t>(encodedChar) >= 0x7F) &&
|
||||
(static_cast<std::uint8_t>(encodedChar) <= 0xA0)) ||
|
||||
((static_cast<std::uint8_t>(encodedChar) < 0x20) &&
|
||||
(0x0A != static_cast<std::uint8_t>(encodedChar)) &&
|
||||
(0x0D != static_cast<std::uint8_t>(encodedChar))))
|
||||
{
|
||||
// We ignore the character because unsupported control characters are not supposed to take
|
||||
// up any room in the presentation of a string
|
||||
}
|
||||
else if (0xAD == (static_cast<std::uint8_t>(encodedChar))) // // Soft Hyphen wraps in ISO 11783
|
||||
{
|
||||
if (autoWrappingEnabled)
|
||||
{
|
||||
add_character(newCharacter, output); // The soft hyphen is drawn when wrapping on it occurs
|
||||
add_character(table[0x0A], output); // Line feed
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not wrapping, the soft hyphen is not shown
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
add_character(newCharacter, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
AgIsoVirtualTerminal/src/WorkingSetComponent.cpp
Normal file
39
AgIsoVirtualTerminal/src/WorkingSetComponent.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
** @file WorkingSetComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "WorkingSetComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
|
||||
WorkingSetComponent::WorkingSetComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::WorkingSet sourceObject, int keyHeight, int keyWidth) :
|
||||
isobus::WorkingSet(sourceObject),
|
||||
parentWorkingSet(workingSet)
|
||||
{
|
||||
setSize(keyWidth, keyHeight);
|
||||
setOpaque(false);
|
||||
|
||||
for (std::uint16_t i = 0; i < this->get_number_children(); i++)
|
||||
{
|
||||
auto child = get_object_by_id(get_child_id(i), parentWorkingSet->get_object_tree());
|
||||
|
||||
if (nullptr != child)
|
||||
{
|
||||
childComponents.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
|
||||
|
||||
if (nullptr != childComponents.back())
|
||||
{
|
||||
addAndMakeVisible(*childComponents.back());
|
||||
childComponents.back()->setTopLeftPosition(get_child_x(i), get_child_y(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkingSetComponent::paint(Graphics &g)
|
||||
{
|
||||
auto vtColour = parentWorkingSet->get_colour(get_background_color());
|
||||
auto background = Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f);
|
||||
g.setColour(background);
|
||||
g.fillAll();
|
||||
}
|
||||
100
AgIsoVirtualTerminal/src/WorkingSetSelectorComponent.cpp
Normal file
100
AgIsoVirtualTerminal/src/WorkingSetSelectorComponent.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*******************************************************************************
|
||||
** @file WorkingSetSelectorComponent.cpp
|
||||
** @author Adrian Del Grosso
|
||||
** @copyright The Open-Agriculture Developers
|
||||
*******************************************************************************/
|
||||
#include "WorkingSetSelectorComponent.hpp"
|
||||
#include "JuceManagedWorkingSetCache.hpp"
|
||||
#include "ServerMainComponent.hpp"
|
||||
#include "isobus/utility/system_timing.hpp"
|
||||
|
||||
WorkingSetSelectorComponent::WorkingSetSelectorComponent(ServerMainComponent &server) :
|
||||
parentServer(server)
|
||||
{
|
||||
setOpaque(false);
|
||||
setBounds(0, 0, 100, 600);
|
||||
}
|
||||
|
||||
void WorkingSetSelectorComponent::update_drawn_working_sets(std::vector<std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet>> &managedWorkingSetList)
|
||||
{
|
||||
children.clear();
|
||||
|
||||
for (std::size_t i = 0; i < managedWorkingSetList.size(); i++)
|
||||
{
|
||||
children.push_back({ managedWorkingSetList.at(i) });
|
||||
|
||||
if ((isobus::VirtualTerminalServerManagedWorkingSet::ObjectPoolProcessingThreadState::Joined == managedWorkingSetList.at(i)->get_object_pool_processing_state()) &&
|
||||
(!isobus::SystemTiming::time_expired_ms(managedWorkingSetList.at(i)->get_working_set_maintenance_message_timestamp_ms(), 3000)) &&
|
||||
(!managedWorkingSetList.at(i)->is_deletion_requested()))
|
||||
{
|
||||
auto workingSetObject = managedWorkingSetList.at(i)->get_working_set_object();
|
||||
|
||||
if (nullptr != workingSetObject)
|
||||
{
|
||||
auto workingSetComponent = JuceManagedWorkingSetCache::create_component(managedWorkingSetList.at(i), workingSetObject);
|
||||
children.back().childComponents.push_back(workingSetComponent);
|
||||
workingSetComponent->setTopLeftPosition(4 + 15, (static_cast<int>(i)) * 80 + 10 + 7);
|
||||
addAndMakeVisible(*workingSetComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void WorkingSetSelectorComponent::paint(Graphics &g)
|
||||
{
|
||||
g.setColour(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
|
||||
g.fillAll();
|
||||
|
||||
// Not sure if this is helpful...
|
||||
/*int numberOfSquares = 0;
|
||||
|
||||
for (auto ws = children.begin(); ws != children.end(); ws++)
|
||||
{
|
||||
g.setColour(getLookAndFeel().findColour(ResizableWindow::backgroundColourId).brighter());
|
||||
g.drawRoundedRectangle(8.0f, 8.0f + (numberOfSquares * 80), 80, 80, 6, 1);
|
||||
numberOfSquares++;
|
||||
}*/
|
||||
}
|
||||
|
||||
void WorkingSetSelectorComponent::resized()
|
||||
{
|
||||
auto parentBounds = getLocalBounds();
|
||||
setBounds(0, 0, 100, parentBounds.getHeight());
|
||||
}
|
||||
|
||||
void WorkingSetSelectorComponent::redraw()
|
||||
{
|
||||
int workingSetIndex = 0;
|
||||
for (auto &workingSet : children)
|
||||
{
|
||||
workingSet.childComponents.clear();
|
||||
auto workingSetObject = workingSet.workingSet->get_working_set_object();
|
||||
|
||||
if (nullptr != workingSetObject)
|
||||
{
|
||||
auto workingSetComponent = JuceManagedWorkingSetCache::create_component(workingSet.workingSet, workingSetObject);
|
||||
workingSet.childComponents.push_back(workingSetComponent);
|
||||
workingSetComponent->setTopLeftPosition(4 + 15, (static_cast<int>(workingSetIndex)) * 80 + 10 + 7);
|
||||
addAndMakeVisible(*workingSetComponent);
|
||||
}
|
||||
workingSetIndex++;
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
void WorkingSetSelectorComponent::mouseUp(const MouseEvent &event)
|
||||
{
|
||||
auto relativeEvent = event.getEventRelativeTo(this);
|
||||
|
||||
if ((relativeEvent.getMouseDownX() >= 19) && (relativeEvent.getMouseDownX() < 99) && (relativeEvent.getMouseDownY() > 17) && (relativeEvent.getMouseDownY() < 17 + children.size() * 80))
|
||||
{
|
||||
int workingSetIndex = (relativeEvent.getMouseDownY() - 17) / 80;
|
||||
|
||||
if (workingSetIndex <= 255)
|
||||
{
|
||||
parentServer.change_selected_working_set(static_cast<std::uint8_t>(workingSetIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
5
ESP-VI/.gitignore
vendored
Normal file
5
ESP-VI/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
10
ESP-VI/.vscode/extensions.json
vendored
Normal file
10
ESP-VI/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
6
ESP-VI/CMakeLists.txt
Normal file
6
ESP-VI/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(seeder_example)
|
||||
1
ESP-VI/README.md
Normal file
1
ESP-VI/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# ESP32_EVB_ISOBUS_ECU
|
||||
39
ESP-VI/include/README
Normal file
39
ESP-VI/include/README
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
12
ESP-VI/include/network_manager.h
Normal file
12
ESP-VI/include/network_manager.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef NETWORK_MANAGER_H
|
||||
#define NETWORK_MANAGER_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_event.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
void wifi_init_sta(void);
|
||||
void mqtt_app_start(void);
|
||||
|
||||
#endif // NETWORK_MANAGER_H
|
||||
15
ESP-VI/include/objectPoolObjects.h
Normal file
15
ESP-VI/include/objectPoolObjects.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#define EXAMPLE_WORKINGSET 256 //
|
||||
#define DM_1000 1000 //
|
||||
#define TEXT_TITLE 1001 //
|
||||
#define BUTTON_FLASHY 1002 //
|
||||
#define TEXT_WORKINGSETTITLE 1004 //
|
||||
#define OS_1005 1005 //
|
||||
#define OS_1006 1006 //
|
||||
#define BUTTON_2 1007 //
|
||||
#define FONT_8X12B 1008 //
|
||||
#define OS_1009 1009 //
|
||||
#define TEXT_FLASHY 1010 //
|
||||
#define FNT_1011 1011 //
|
||||
#define TEXT_BUTTON2 1012 //
|
||||
#define BMP_1013 1013 //
|
||||
#define OS_1014 1014 //
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user