Compare commits
55 Commits
731566e7d1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bb800f1e7 | |||
|
|
7647b01d62 | ||
| 37fcc5e888 | |||
|
|
ab4abd214e | ||
| 07c235afa2 | |||
|
|
4f44c588fa | ||
|
|
0d802fcec3 | ||
|
|
8639529bbe | ||
| 4309d2231e | |||
| 093b90fab6 | |||
| 6aec85418a | |||
| c6c058279a | |||
| 291695bcb9 | |||
|
|
95dd9d18e6 | ||
| beae1c1b3d | |||
|
|
c0ce6a81e3 | ||
| 9b1a1233f9 | |||
| 5c919e4d55 | |||
| 25e752e83b | |||
| 9c35c9ea42 | |||
| 6232b560b5 | |||
| d3c62335b1 | |||
| 7780657d82 | |||
| aa4b2a1b84 | |||
| cb553cf928 | |||
| dc3669f513 | |||
| 9f0382965f | |||
| 653aa49a7b | |||
| 2547ed6e1c | |||
| c81c38f780 | |||
| 1fc551d7d1 | |||
| 53b4d6e041 | |||
| 95765226e9 | |||
| d6da7aac9a | |||
| 6b03797600 | |||
|
|
f19a33cc5f | ||
| c40f288aaa | |||
| 23695bc7ef | |||
|
|
3bdc491830 | ||
| 7d43b0a694 | |||
| 407e2e41ed | |||
| 398d50c45c | |||
| 4dd278dbf7 | |||
| be44a70a57 | |||
| a325cc3826 | |||
| 6f5b8d8df6 | |||
| 50c82bca43 | |||
| a8a947ff0b | |||
| 221e0bc8c2 | |||
| e5f7ba569a | |||
| a57b45e21a | |||
| 1a2d815634 | |||
| 6c15d99119 | |||
| c21bb2cf4e | |||
| 5c52b1e936 |
47
.gitignore
vendored
@@ -1,22 +1,25 @@
|
||||
BionxControl.pro.user
|
||||
build/
|
||||
bcvalue.cpp.autosave
|
||||
.qtcreator/BionxControl.pro.user
|
||||
.user
|
||||
|
||||
# Objektdateien ignorieren
|
||||
*.o
|
||||
|
||||
.qtc_clangd/
|
||||
|
||||
# Von Qt generierte MOC-Dateien (Meta-Object Compiler) ignorieren
|
||||
moc_*
|
||||
|
||||
# Von Qt generierte Ressourcen-Dateien ignorieren
|
||||
qrc_*
|
||||
|
||||
BionxControl
|
||||
Makefile
|
||||
ui_*
|
||||
|
||||
.qmake.stash
|
||||
BionxControl.pro.user
|
||||
build/
|
||||
bcvalue.cpp.autosave
|
||||
.qtcreator/BionxControl.pro.user
|
||||
.user
|
||||
|
||||
# Objektdateien ignorieren
|
||||
*.o
|
||||
|
||||
.qtc_clangd/
|
||||
|
||||
# Von Qt generierte MOC-Dateien (Meta-Object Compiler) ignorieren
|
||||
moc_*
|
||||
|
||||
# Von Qt generierte Ressourcen-Dateien ignorieren
|
||||
qrc_*
|
||||
|
||||
BionxControl
|
||||
Makefile
|
||||
ui_*
|
||||
|
||||
.qmake.stash
|
||||
.vs/
|
||||
debug/
|
||||
release/
|
||||
|
||||
@@ -37,6 +37,7 @@ li
|
||||
windows
|
||||
{
|
||||
#LIBS += -L$$PWD/can_api -lmhstcan -lAdvapi32
|
||||
message("Konfiguration für Windows.")
|
||||
}
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
@@ -44,15 +45,19 @@ windows
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
aalegacy.cpp \
|
||||
bc.cpp \
|
||||
bcanimateddelegate.cpp \
|
||||
bcdelightpmwidget.cpp \
|
||||
bcdeviceview.cpp \
|
||||
bcdriver.cpp \
|
||||
bcdriverstatewidget.cpp \
|
||||
bcdrivertinycan.cpp \
|
||||
bcguihelpers.cpp \
|
||||
bcsliderstyle.cpp \
|
||||
bcthemeswitchbutton.cpp \
|
||||
bctoggleswitch.cpp \
|
||||
bctransmitter.cpp \
|
||||
bcvalue.cpp \
|
||||
bcvaluedelegate.cpp \
|
||||
bcvalueeditor.cpp \
|
||||
bcvaluemodel.cpp \
|
||||
bcxmlloader.cpp \
|
||||
libwin/can_drv_win.c \
|
||||
@@ -62,19 +67,25 @@ SOURCES += \
|
||||
|
||||
HEADERS += \
|
||||
bc.h \
|
||||
bcanimateddelegate.h \
|
||||
bcdelightpmwidget.h \
|
||||
bcdeviceview.h \
|
||||
bcdriver.h \
|
||||
bcdriverstatewidget.h \
|
||||
bcdrivertinycan.h \
|
||||
bcguihelpers.h \
|
||||
bcmainwindow.h \
|
||||
bcsliderstyle.h \
|
||||
bcthemeswitchbutton.h \
|
||||
bctoggleswitch.h \
|
||||
bctransmitter.h \
|
||||
bcvalue.h \
|
||||
bcvaluedelegate.h \
|
||||
bcvalueeditor.h \
|
||||
bcvaluemodel.h \
|
||||
bcxmlloader.h
|
||||
|
||||
FORMS += \
|
||||
bcmainwindow.ui
|
||||
bcmainwindow.ui \
|
||||
bcvalueeditor.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
|
||||
7483
BionxControl.qtvscr
Normal file
6
BionxControl.slnx
Normal file
@@ -0,0 +1,6 @@
|
||||
<Solution>
|
||||
<Configurations>
|
||||
<Platform Name="x64" />
|
||||
</Configurations>
|
||||
<Project Path="BionxControl.vcxproj" Id="4294daef-a666-3d4c-a433-ace7fb2b0c2f" />
|
||||
</Solution>
|
||||
299
BionxControl.vcxproj
Normal file
@@ -0,0 +1,299 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{4294DAEF-A666-3D4C-A433-ACE7FB2B0C2F}</ProjectGuid>
|
||||
<RootNamespace>BionxControl</RootNamespace>
|
||||
<Keyword>QtVS_v304</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.26100.0</WindowsTargetPlatformMinVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<OutputDirectory>release\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<IntermediateDirectory>release\</IntermediateDirectory>
|
||||
<PrimaryOutput>BionxControl</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<OutputDirectory>debug\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<IntermediateDirectory>debug\</IntermediateDirectory>
|
||||
<PrimaryOutput>BionxControl</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" Condition="Exists('$(QtMsBuild)\qt_defaults.props')" />
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<QtInstall>6.10.1_msvc2022_64</QtInstall>
|
||||
<QtModules>core;gui;widgets;svg</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<QtInstall>6.10.1_msvc2022_64</QtInstall>
|
||||
<QtModules>core;gui;widgets;svg</QtModules>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') OR !Exists('$(QtMsBuild)\Qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
<Import Project="$(QtMsBuild)\Qt.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
<Import Project="$(QtMsBuild)\Qt.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">release\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">release\</IntDir>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">BionxControl</TargetName>
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">debug\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">debug\</IntDir>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">BionxControl</TargetName>
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;libwin;release;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -permissive- -Zc:__cplusplus -Zc:externConstexpr -std=c++23 -utf-8 -w34100 -w34189 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AssemblerListingLocation>release\</AssemblerListingLocation>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<ObjectFileName>release\</ObjectFileName>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<ProgramDataBaseFileName>
|
||||
</ProgramDataBaseFileName>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<UseFullPaths>false</UseFullPaths>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(QTDIR)\lib\Qt6EntryPoint.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<OutputFile>$(OutDir)\BionxControl.exe</OutputFile>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Link>
|
||||
<Midl>
|
||||
<DefaultCharType>Unsigned</DefaultCharType>
|
||||
<EnableErrorChecks>None</EnableErrorChecks>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<InitFuncName>bionxcontrol</InitFuncName>
|
||||
<Compression>default</Compression>
|
||||
<NoZstd>true</NoZstd>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
<QtUic>
|
||||
<ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription>
|
||||
<QtUicDir>$(ProjectDir)</QtUicDir>
|
||||
<QtUicFileName>ui_%(Filename).h</QtUicFileName>
|
||||
</QtUic>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;libwin;debug;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -permissive- -Zc:__cplusplus -Zc:externConstexpr -std=c++23 -utf-8 -w34100 -w34189 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AssemblerListingLocation>debug\</AssemblerListingLocation>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<ObjectFileName>debug\</ObjectFileName>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<UseFullPaths>false</UseFullPaths>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(QTDIR)\lib\Qt6EntryPointd.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<OutputFile>$(OutDir)\BionxControl.exe</OutputFile>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Link>
|
||||
<Midl>
|
||||
<DefaultCharType>Unsigned</DefaultCharType>
|
||||
<EnableErrorChecks>None</EnableErrorChecks>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<InitFuncName>bionxcontrol</InitFuncName>
|
||||
<Compression>default</Compression>
|
||||
<NoZstd>true</NoZstd>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
<QtUic>
|
||||
<ExecutionDescription>Uic'ing %(Identity)...</ExecutionDescription>
|
||||
<QtUicDir>$(ProjectDir)</QtUicDir>
|
||||
<QtUicFileName>ui_%(Filename).h</QtUicFileName>
|
||||
</QtUic>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bc.cpp" />
|
||||
<ClCompile Include="bcdelightpmwidget.cpp" />
|
||||
<ClCompile Include="bcdeviceview.cpp" />
|
||||
<ClCompile Include="bcdriver.cpp" />
|
||||
<ClCompile Include="bcdriverstatewidget.cpp" />
|
||||
<ClCompile Include="bcdrivertinycan.cpp" />
|
||||
<ClCompile Include="bcmainwindow.cpp" />
|
||||
<ClCompile Include="bcsliderstyle.cpp" />
|
||||
<ClCompile Include="bcthemeswitchbutton.cpp" />
|
||||
<ClCompile Include="bctoggleswitch.cpp" />
|
||||
<ClCompile Include="bctransmitter.cpp" />
|
||||
<ClCompile Include="bcvalue.cpp" />
|
||||
<ClCompile Include="bcvaluedelegate.cpp" />
|
||||
<ClCompile Include="bcvalueeditor.cpp" />
|
||||
<ClCompile Include="bcvaluemodel.cpp" />
|
||||
<ClCompile Include="bcxmlloader.cpp" />
|
||||
<ClCompile Include="libwin\can_drv_win.c" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="bc.h" />
|
||||
<QtMoc Include="bcdelightpmwidget.h" />
|
||||
<QtMoc Include="bcdeviceview.h" />
|
||||
<QtMoc Include="bcdriver.h" />
|
||||
<QtMoc Include="bcdriverstatewidget.h" />
|
||||
<ClInclude Include="bcdrivertinycan.h" />
|
||||
<QtMoc Include="bcmainwindow.h" />
|
||||
<ClInclude Include="bcsliderstyle.h" />
|
||||
<QtMoc Include="bcthemeswitchbutton.h" />
|
||||
<QtMoc Include="bctoggleswitch.h" />
|
||||
<QtMoc Include="bctransmitter.h" />
|
||||
<QtMoc Include="bcvalue.h" />
|
||||
<QtMoc Include="bcvaluedelegate.h" />
|
||||
<QtMoc Include="bcvalueeditor.h" />
|
||||
<QtMoc Include="bcvaluemodel.h" />
|
||||
<QtMoc Include="bcxmlloader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
<FileType>Document</FileType>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -permissive- -Zc:__cplusplus -Zc:externConstexpr -std=c++23 -Zi -MDd -std:c++latest -utf-8 -W3 -w34100 -w34189 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >$(IntDir)\moc_predefs.h</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generate moc_predefs.h</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\moc_predefs.h;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="release\moc_predefs.h.cbt">
|
||||
<FileType>Document</FileType>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -permissive- -Zc:__cplusplus -Zc:externConstexpr -std=c++23 -O2 -MD -std:c++latest -utf-8 -W3 -w34100 -w34189 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >$(IntDir)\moc_predefs.h</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generate moc_predefs.h</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\moc_predefs.h;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="bcmainwindow.ui" />
|
||||
<QtUic Include="bcvalueeditor.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\bc_dark.qss" />
|
||||
<None Include="resources\bc_light.qss" />
|
||||
<None Include="resources\bikeinfo.xml" />
|
||||
<None Include="resources\bionx_akku.png" />
|
||||
<None Include="resources\bionx_console.png" />
|
||||
<None Include="resources\bionx_motor.png" />
|
||||
<QtRcc Include="bionxcontrol.qrc" />
|
||||
<None Include="resources\connect.png" />
|
||||
<None Include="resources\exit.png" />
|
||||
<None Include="resources\exit_red.png" />
|
||||
<None Include="resources\smile\face-angel.png" />
|
||||
<None Include="resources\smile\face-angry.png" />
|
||||
<None Include="resources\smile\face-cool.png" />
|
||||
<None Include="resources\smile\face-crying.png" />
|
||||
<None Include="resources\smile\face-embarrassed.png" />
|
||||
<None Include="resources\smile\face-glasses.png" />
|
||||
<None Include="resources\smile\face-kiss.png" />
|
||||
<None Include="resources\smile\face-laugh.png" />
|
||||
<None Include="resources\smile\face-monkey.png" />
|
||||
<None Include="resources\smile\face-plain.png" />
|
||||
<None Include="resources\smile\face-raspberry.png" />
|
||||
<None Include="resources\smile\face-sad.png" />
|
||||
<None Include="resources\smile\face-sick.png" />
|
||||
<None Include="resources\smile\face-smile-big.png" />
|
||||
<None Include="resources\smile\face-smile.png" />
|
||||
<None Include="resources\smile\face-smirk.png" />
|
||||
<None Include="resources\smile\face-surprise.png" />
|
||||
<None Include="resources\sync.png" />
|
||||
<None Include="resources\sync_green.png" />
|
||||
<None Include="resources\sync_yellow.png" />
|
||||
<None Include="resources\update.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="$(QtMsBuild)\qt.targets" Condition="Exists('$(QtMsBuild)\qt.targets')" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
266
BionxControl.vcxproj.filters
Normal file
@@ -0,0 +1,266 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Form Files">
|
||||
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
|
||||
<Extensions>ui</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Form Files">
|
||||
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
|
||||
<Extensions>ui</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;moc;h;def;odl;idl;res;</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;moc;h;def;odl;idl;res;</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
|
||||
<Extensions>qrc;*</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
|
||||
<Extensions>qrc;*</Extensions>
|
||||
<ParseFiles>false</ParseFiles>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcdelightpmwidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcdeviceview.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcdriver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcdriverstatewidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcdrivertinycan.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcmainwindow.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcsliderstyle.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcthemeswitchbutton.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bctoggleswitch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bctransmitter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcvalue.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcvaluedelegate.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcvalueeditor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcvaluemodel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bcxmlloader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="libwin\can_drv_win.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="bc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcdelightpmwidget.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcdeviceview.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcdriver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcdriverstatewidget.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<ClInclude Include="bcdrivertinycan.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<QtMoc Include="bcmainwindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<ClInclude Include="bcsliderstyle.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<QtMoc Include="bcthemeswitchbutton.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bctoggleswitch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bctransmitter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcvalue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcvaluedelegate.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcvalueeditor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcvaluemodel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="bcxmlloader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
<Filter>Generated Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="release\moc_predefs.h.cbt">
|
||||
<Filter>Generated Files</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="bcmainwindow.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="bcvalueeditor.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources\bc_dark.qss">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\bc_light.qss">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\bikeinfo.xml">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\bionx_akku.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\bionx_console.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\bionx_motor.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<QtRcc Include="bionxcontrol.qrc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</QtRcc>
|
||||
<None Include="resources\connect.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\exit.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\exit_red.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-angel.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-angry.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-cool.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-crying.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-embarrassed.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-glasses.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-kiss.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-laugh.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-monkey.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-plain.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-raspberry.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-sad.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-sick.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-smile-big.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-smile.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-smirk.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\smile\face-surprise.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\sync.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\sync_green.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\sync_yellow.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resources\update.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
12
BionxControl.vcxproj.user
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<QtTouchProperty>
|
||||
</QtTouchProperty>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<QtTouchProperty>
|
||||
</QtTouchProperty>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
744
aalegacy.cpp
@@ -1,744 +0,0 @@
|
||||
/* BigXionFlasher.c */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2011-2013 by Thomas König <info@bigxionflasher.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the
|
||||
* BigXionFlasher Project. (http://www.bigxionflasher.org/)"
|
||||
*
|
||||
* 4. The name "BigXionFlasher" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* info@bigxionflasher.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "BigXionFlasher"
|
||||
* nor may "BigXionFlasher" appear in their names without prior written
|
||||
* permission of the BigXionFlasher Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the
|
||||
* BigXionFlasher Project. (http://www.bigxionflasher.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE BigXionFlasher PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE BigXionFlasher PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#ifdef __WIN32__
|
||||
#include <conio.h>
|
||||
#define DEVICE_OPEN NULL
|
||||
#define TREIBER_NAME "mhstcan.dll"
|
||||
#define _NL "\n\r"
|
||||
#define _DEGREE_SIGN "o"
|
||||
#else
|
||||
#define DEVICE_OPEN NULL
|
||||
#define TREIBER_NAME "libmhstcan.so"
|
||||
#define _NL "\n"
|
||||
#define _DEGREE_SIGN "°"
|
||||
#endif
|
||||
#include "can_drv.h"
|
||||
|
||||
#define __DOSTR(v) #v
|
||||
#define __STR(v) __DOSTR(v)
|
||||
|
||||
#define __BXF_VERSION__ "V 0.2.4 rev. 97"
|
||||
|
||||
#define UNLIMITED_SPEED_VALUE 70 /* Km/h */
|
||||
#define UNLIMITED_MIN_SPEED_VALUE 30 /* Km/h */
|
||||
#define MAX_THROTTLE_SPEED_VALUE 70 /* Km/h */
|
||||
|
||||
//#include "registers.h"
|
||||
|
||||
#define TIMEOUT_VALUE 80
|
||||
#define TIMEOUT_US 10000 // 10ms
|
||||
|
||||
|
||||
|
||||
#define BATTERY_REF_HW 1
|
||||
#define BATTERY_REF_SW 1
|
||||
#define BATTERY_SN_PN_HI 1
|
||||
#define BATTERY_SN_PN_LO 1
|
||||
#define BATTERY_SN_ITEM_HI 1
|
||||
#define BATTERY_SN_ITEM_LO 1
|
||||
#define BATTERY_STATUS_VBATT_HI 1
|
||||
#define BATTERY_STATUS_VBATT_LO 1
|
||||
#define BATTERY_STATUS_LEVEL 1
|
||||
#define BATTERY_STATS_VBATTMAX 1
|
||||
#define BATTERY_STATS_VBATTMIN 1
|
||||
#define BATTERY_STATS_VBATTMEA 1
|
||||
#define BATTERY_STATS_VBATTMEAN 1
|
||||
#define BATTERY_STATS_RESET_HI 1
|
||||
#define BATTERY_STATS_RESET_LO 1
|
||||
#define BATTERY_STSTS_GGJSRCALIB 1
|
||||
|
||||
#define BATTERY_STSTS_VCTRLSHORTS 1
|
||||
#define BATTERY_STATS_LMD_HI 1
|
||||
#define BATTERY_STATS_LMD_LO 1
|
||||
#define BATTERY_CONFIG_CELLCAPACITY_HI 1
|
||||
#define BATTERY_CONFIG_CELLCAPACITY_LO 1
|
||||
|
||||
#define BATTERY_STATS_CHARGETIMEWORST_HI 1
|
||||
#define BATTERY_STATS_CHARGETIMEWORST_LO 1
|
||||
#define BATTERY_STATS_CHARGETIMEMEAN_HI 1
|
||||
#define BATTERY_STATS_CHARGETIMEMEAN_LO 1
|
||||
#define BATTERY_STATS_BATTCYCLES_HI 1
|
||||
#define BATTERY_STATS_BATTCYCLES_LO 1
|
||||
#define BATTERY_STATS_BATTFULLCYCLES_HI 1
|
||||
#define BATTERY_STATS_BATTFULLCYCLES_LO 1
|
||||
#define BATTERY_STATS_POWERCYCLES_HI 1
|
||||
#define BATTERY_STATS_POWERCYCLES_LO 1
|
||||
|
||||
#define BATTERY_STATS_TBATTMAX 1
|
||||
#define BATTERY_STATS_TBATTMIN 1
|
||||
#define MOTOR_REF_HW 1
|
||||
#define MOTOR_REF_SW 1
|
||||
#define MOTOR_REALTIME_TEMP 1
|
||||
#define MOTOR_SN_PN_HI 1
|
||||
#define MOTOR_SN_PN_LO 1
|
||||
#define MOTOR_SN_ITEM_HI 1
|
||||
#define MOTOR_SN_ITEM_LO 1
|
||||
|
||||
#define CONSOLE_STATUS_SLAVE 1
|
||||
#define BATTERY_CONFIG_SHUTDOWN 1
|
||||
|
||||
#define CONSOLE_ASSIST_MAXSPEEDFLAG 1
|
||||
#define CONSOLE_ASSIST_MAXSPEED_HI 1
|
||||
#define CONSOLE_ASSIST_MAXSPEED_LO 1
|
||||
#define MOTOR_PROTECT_UNLOCK 1
|
||||
#define MOTOR_PROTECT_UNLOCK_KEY 1
|
||||
#define MOTOR_ASSIST_MAXSPEED 1
|
||||
#define CONSOLE_GEOMETRY_CIRC_HI 1
|
||||
#define CONSOLE_GEOMETRY_CIRC_LO1
|
||||
|
||||
#define CONSOLE_GEOMETRY_CIRC_LO 1
|
||||
#define MOTOR_GEOMETRY_CIRC_HI1
|
||||
#define MOTOR_GEOMETRY_CIRC_HI 1
|
||||
#define MOTOR_GEOMETRY_CIRC_LO 1
|
||||
#define CONSOLE_ASSIST_MINSPEEDFLAG 1
|
||||
#define CONSOLE_ASSIST_MINSPEED 1
|
||||
|
||||
#define CONSOLE_THROTTLE_MAXSPEEDFLAG 1
|
||||
#define CONSOLE_THROTTLE_MAXSPEED_HI 1
|
||||
#define CONSOLE_THROTTLE_MAXSPEED_LO 1
|
||||
|
||||
#define BATTERY_CONFIG_PACKSERIAL 1
|
||||
#define BATTERY_CELLMON_BALANCERENABLED 1
|
||||
#define BATTERY_CONFIG_PACKPARALLEL 1
|
||||
#define BATTERY_CELLMON_CHANNELADDR 1
|
||||
#define BATTERY_CELLMON_CHANNELDATA_HI 1
|
||||
|
||||
#define BATTERY_STATUS_PACKTEMPERATURE1 1
|
||||
|
||||
#define BATTERY_CELLMON_CHANNELDATA_LO 1
|
||||
|
||||
#define CONSOLE_REF_HW 1
|
||||
#define CONSOLE_REF_SW 1
|
||||
#define CONSOLE_ASSIST_INITLEVEL 1
|
||||
#define CONSOLE_SN_PN_HI 1
|
||||
#define CONSOLE_SN_PN_LO 1
|
||||
#define CONSOLE_SN_ITEM_HI 1
|
||||
#define CONSOLE_SN_ITEM_LO 1
|
||||
#define CONSOLE_ASSIST_MOUNTAINCAP 1
|
||||
#define CONSOLE_STATS_BCValueTypeWord_1 1
|
||||
#define CONSOLE_STATS_BCValueTypeWord_2 1
|
||||
#define CONSOLE_STATS_BCValueTypeWord_3 1
|
||||
|
||||
#define CONSOLE_STATS_BCValueTypeWord_4 1
|
||||
|
||||
#define doSleep(x) usleep(x*1000)
|
||||
|
||||
int gAssistInitLevel = -1, gPrintSystemSettings = 0, gSkipShutdown = 0, gPowerOff = 0, gConsoleSetSlaveMode = 1, gNoSerialNumbers = 0, gSetMountainCap = -1, gSetWheelCircumference = 0;
|
||||
double gSetSpeedLimit = -1, gSetMinSpeedLimit = -1, gSetThrottleSpeedLimit = -1;
|
||||
|
||||
#define CONSOLE 1
|
||||
#define MOTOR 2
|
||||
#define BATTERY 3
|
||||
#define BIB 4
|
||||
|
||||
|
||||
|
||||
char *getNodeName(unsigned char id)
|
||||
{
|
||||
if (id == CONSOLE)
|
||||
return "console";
|
||||
else if (id == BATTERY)
|
||||
return "battery";
|
||||
else if (id == MOTOR)
|
||||
return "motor";
|
||||
else if (id == BIB)
|
||||
return "bib";
|
||||
else
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
void setValue(unsigned char receipient, unsigned char reg, unsigned char value)
|
||||
{
|
||||
struct TCanMsg msg;
|
||||
int timeout = TIMEOUT_VALUE;
|
||||
|
||||
msg.MsgFlags = 0L;
|
||||
msg.Id = receipient;
|
||||
msg.MsgLen = 4;
|
||||
msg.MsgData[0] = 0x00;
|
||||
msg.MsgData[1] = reg;
|
||||
msg.MsgData[2] = 0x00;
|
||||
msg.MsgData[3] = value;
|
||||
|
||||
CanTransmit(0, &msg, 1);
|
||||
|
||||
while(timeout-- && CanTransmitGetCount(0))
|
||||
usleep(TIMEOUT_US);
|
||||
|
||||
if (timeout == -1)
|
||||
printf("error: could not send value to %s" _NL, getNodeName(receipient));
|
||||
}
|
||||
|
||||
unsigned int getValue(unsigned char receipient, unsigned char reg)
|
||||
{
|
||||
struct TCanMsg msg;
|
||||
int err, retry = 20;
|
||||
int timeout = TIMEOUT_VALUE;
|
||||
|
||||
msg.MsgFlags = 0L;
|
||||
msg.Id = receipient;
|
||||
msg.MsgLen = 2;
|
||||
msg.MsgData[0] = 0x00;
|
||||
msg.MsgData[1] = reg;
|
||||
|
||||
CanTransmit(0, &msg, 1);
|
||||
|
||||
while(timeout-- && CanTransmitGetCount(0))
|
||||
usleep(TIMEOUT_US);
|
||||
|
||||
if (timeout == -1)
|
||||
printf("error: could not send value to node %s" _NL, getNodeName(receipient));
|
||||
|
||||
retry:
|
||||
|
||||
timeout = TIMEOUT_VALUE;
|
||||
while(timeout-- && !CanReceiveGetCount(0))
|
||||
usleep(TIMEOUT_US);
|
||||
|
||||
if (timeout == -1)
|
||||
{
|
||||
printf("error: no response from node %s" _NL, getNodeName(receipient));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = CanReceive(0, &msg, 1)) > 0)
|
||||
{
|
||||
if (--retry && (msg.Id != BIB || msg.MsgLen != 4 || msg.MsgData[1] != reg))
|
||||
goto retry;
|
||||
|
||||
if (!retry)
|
||||
{
|
||||
printf("error: no response from node %s to %s" _NL, getNodeName(receipient), getNodeName(BIB));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (unsigned int) msg.MsgData[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: %d" _NL, err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void setSpeedLimit(double speed)
|
||||
{
|
||||
int limit = (speed != 0);
|
||||
|
||||
if (!speed)
|
||||
speed = UNLIMITED_SPEED_VALUE;
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_MAXSPEEDFLAG, limit);
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_MAXSPEED_HI, ((int)(speed * 10)) >> 8);
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_MAXSPEED_LO, ((int)(speed * 10)) & 0xff);
|
||||
setValue(MOTOR, MOTOR_PROTECT_UNLOCK, MOTOR_PROTECT_UNLOCK_KEY);
|
||||
setValue(MOTOR, MOTOR_ASSIST_MAXSPEED, (int)speed);
|
||||
}
|
||||
|
||||
|
||||
void setWheelCircumference(unsigned short circumference)
|
||||
{
|
||||
if (!circumference)
|
||||
return;
|
||||
|
||||
setValue(CONSOLE, CONSOLE_GEOMETRY_CIRC_HI, (int) (circumference >> 8));
|
||||
setValue(CONSOLE, CONSOLE_GEOMETRY_CIRC_LO, (int) (circumference & 0xff));
|
||||
setValue(MOTOR, MOTOR_PROTECT_UNLOCK, MOTOR_PROTECT_UNLOCK_KEY);
|
||||
setValue(MOTOR, MOTOR_GEOMETRY_CIRC_HI, (int) (circumference >> 8));
|
||||
setValue(MOTOR, MOTOR_GEOMETRY_CIRC_LO, (int) (circumference & 0xff));
|
||||
}
|
||||
|
||||
void setMinSpeedLimit(double speed)
|
||||
{
|
||||
char limit = (speed != 0);
|
||||
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_MINSPEEDFLAG, limit);
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_MINSPEED, (int)(speed * 10));
|
||||
}
|
||||
|
||||
|
||||
void setThrottleSpeedLimit(double speed)
|
||||
{
|
||||
int limit = (speed != 0);
|
||||
|
||||
if (!speed)
|
||||
speed = MAX_THROTTLE_SPEED_VALUE;
|
||||
|
||||
setValue(CONSOLE, CONSOLE_THROTTLE_MAXSPEEDFLAG, limit);
|
||||
setValue(CONSOLE, CONSOLE_THROTTLE_MAXSPEED_HI, ((int)(speed * 10)) >> 8);
|
||||
setValue(CONSOLE, CONSOLE_THROTTLE_MAXSPEED_LO, ((int)(speed * 10)) & 0xff);
|
||||
}
|
||||
|
||||
void printBatteryStats()
|
||||
{
|
||||
int channel = 1, packSerial, packParallel;
|
||||
|
||||
printf( " balancer enabled ...: %s" _NL _NL, (getValue(BATTERY, BATTERY_CELLMON_BALANCERENABLED != 0) ? "yes" : "no"));
|
||||
|
||||
packSerial = getValue(BATTERY, BATTERY_CONFIG_PACKSERIAL);
|
||||
packParallel = getValue(BATTERY, BATTERY_CONFIG_PACKPARALLEL);
|
||||
|
||||
packSerial = (packSerial > 20) ? 0 : packSerial;
|
||||
packParallel = (packParallel > 20) ? 0 : packParallel;
|
||||
|
||||
for (;channel <= packSerial; channel++) {
|
||||
setValue(BATTERY, BATTERY_CELLMON_CHANNELADDR, (int)0x80 + channel);
|
||||
printf(" voltage cell #%02d ...: %.3fV" _NL, channel,
|
||||
((getValue(BATTERY, BATTERY_CELLMON_CHANNELDATA_HI) << 8) + getValue(BATTERY,BATTERY_CELLMON_CHANNELDATA_LO)) * 0.001);
|
||||
}
|
||||
|
||||
for (channel = 0 ; channel < packParallel ; channel ++)
|
||||
printf(" temperature pack #%02d: %d" _DEGREE_SIGN "C" _NL, channel + 1,
|
||||
getValue(BATTERY, BATTERY_STATUS_PACKTEMPERATURE1 + channel));
|
||||
|
||||
printf(_NL);
|
||||
}
|
||||
|
||||
void printChargeStats() {
|
||||
int channel = 1, totalChagres = 0, c;
|
||||
|
||||
for (channel = 1 ; channel <= 10; channel++) {
|
||||
setValue(BATTERY, 0xf6, channel);
|
||||
c = (getValue(BATTERY, 0xf7) << 8) + getValue(BATTERY,0xf8);
|
||||
totalChagres += c;
|
||||
printf(" charge level @ %03d%% : %04d" _NL, channel*10, c);
|
||||
}
|
||||
|
||||
printf(" total # of charges .: %04d" _NL _NL, totalChagres);
|
||||
}
|
||||
|
||||
double getVoltageValue(unsigned char in, unsigned char reg)
|
||||
{
|
||||
return (getValue(BATTERY, reg) + 20.8333) * 0.416667;
|
||||
}
|
||||
|
||||
void usage(void) {
|
||||
printf( "usage:" _NL
|
||||
" -l <speedLimit> .......... set the speed limit to <speedLimit> (1 - " __STR(UNLIMITED_SPEED_VALUE) "), 0 = remove the limit" _NL );
|
||||
}
|
||||
|
||||
int parseOptions(int argc, char **argv)
|
||||
{
|
||||
int oc;
|
||||
char odef[] = "l:t:m:sa:pnxio:c:h?";
|
||||
|
||||
while((oc = getopt(argc,argv,odef)) != -1) {
|
||||
switch(oc) {
|
||||
case 'p':
|
||||
gPowerOff = 1;
|
||||
break;
|
||||
case 'x':
|
||||
gSkipShutdown = 1;
|
||||
break;
|
||||
case 'l':
|
||||
gSetSpeedLimit = atof(optarg);
|
||||
if (gSetSpeedLimit > UNLIMITED_SPEED_VALUE || gSetSpeedLimit < 0) {
|
||||
printf("error: speed limit %.2f is out of range. exiting..." _NL, gSetSpeedLimit);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
gSetThrottleSpeedLimit = atof(optarg);
|
||||
if (gSetThrottleSpeedLimit > MAX_THROTTLE_SPEED_VALUE || gSetThrottleSpeedLimit < 0) {
|
||||
printf("error: throttle speed limit %.2f is out of range. exiting..." _NL, gSetThrottleSpeedLimit);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
gSetMinSpeedLimit = atof(optarg);
|
||||
if (gSetMinSpeedLimit > UNLIMITED_MIN_SPEED_VALUE || gSetMinSpeedLimit < 0) {
|
||||
printf("error: min speed limit %.2f is out of range. exiting..." _NL, gSetMinSpeedLimit);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
gAssistInitLevel = atoi(optarg);
|
||||
if (gAssistInitLevel > 4 || gAssistInitLevel < 0) {
|
||||
printf("error: initial assist level %d is out of range. exiting..." _NL, gAssistInitLevel);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
gSetMountainCap = atoi(optarg);
|
||||
if (gSetMountainCap > 100 || gSetMountainCap < 0) {
|
||||
printf("error: mountain cap level %d is out of range. exiting..." _NL, gSetMountainCap);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
gSetWheelCircumference = atoi(optarg);
|
||||
if (gSetWheelCircumference > 3000 || gSetWheelCircumference < 1000) {
|
||||
printf("error: wheel circumference %d is out of range. exiting..." _NL, gSetWheelCircumference);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
gConsoleSetSlaveMode = 0;
|
||||
break;
|
||||
case 'i':
|
||||
gNoSerialNumbers = 1;
|
||||
break;
|
||||
case 's':
|
||||
gPrintSystemSettings = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void printSystemSettings()
|
||||
{
|
||||
int hwVersion, swVersion, wheelCirc;
|
||||
char *sl;
|
||||
double speedLimit = 0;
|
||||
|
||||
printf(_NL _NL);
|
||||
|
||||
hwVersion = getValue(CONSOLE, CONSOLE_REF_HW);
|
||||
|
||||
if (hwVersion == 0)
|
||||
printf("Console not responding" _NL _NL);
|
||||
else {
|
||||
swVersion = getValue(CONSOLE, CONSOLE_REF_SW);
|
||||
printf( "Console information:" _NL
|
||||
" hardware version ........: %02d" _NL
|
||||
" software version ........: %02d" _NL
|
||||
" assistance level ........: %d" _NL,
|
||||
hwVersion, swVersion,
|
||||
getValue(CONSOLE, CONSOLE_ASSIST_INITLEVEL)
|
||||
);
|
||||
|
||||
if (!gNoSerialNumbers)
|
||||
printf( " part number .............: %05d" _NL
|
||||
" item number .............: %05d" _NL _NL,
|
||||
((getValue(CONSOLE, CONSOLE_SN_PN_HI) << 8) + getValue(CONSOLE, CONSOLE_SN_PN_LO)),
|
||||
((getValue(CONSOLE, CONSOLE_SN_ITEM_HI) << 8) + getValue(CONSOLE, CONSOLE_SN_ITEM_LO))
|
||||
);
|
||||
|
||||
/* ASSIST speed limit */
|
||||
sl = getValue(CONSOLE, CONSOLE_ASSIST_MAXSPEEDFLAG) == 0 ? (char*)"no" : (char*)"yes";
|
||||
speedLimit = ((getValue(CONSOLE, CONSOLE_ASSIST_MAXSPEED_HI) << 8) + getValue(CONSOLE, CONSOLE_ASSIST_MAXSPEED_LO)) / (double)10;
|
||||
printf( " max limit enabled .......: %s" _NL
|
||||
" speed limit .............: %0.2f Km/h" _NL _NL, sl, speedLimit);
|
||||
|
||||
/* MIN speed limit */
|
||||
sl = getValue(CONSOLE, CONSOLE_ASSIST_MINSPEEDFLAG) == 0 ? (char*)"no" : (char*)"yes";
|
||||
speedLimit = (getValue(CONSOLE, CONSOLE_ASSIST_MINSPEED)) / (double)10;
|
||||
printf( " min limit enabled .......: %s" _NL
|
||||
" min speed limit .........: %0.2f Km/h" _NL _NL, sl, speedLimit);
|
||||
|
||||
/* THROTTLE speed limit */
|
||||
sl = getValue(CONSOLE, CONSOLE_THROTTLE_MAXSPEEDFLAG) == 0 ? (char*)"no" : (char*)"yes";
|
||||
speedLimit = ((getValue(CONSOLE, CONSOLE_THROTTLE_MAXSPEED_HI) << 8) + getValue(CONSOLE, CONSOLE_THROTTLE_MAXSPEED_LO)) / (double)10;
|
||||
printf( " throttle limit enabled ..: %s" _NL
|
||||
" throttle speed limit ....: %0.2f Km/h" _NL _NL, sl, speedLimit);
|
||||
|
||||
/* WHEEL CIRCUMFERENCE */
|
||||
wheelCirc = (getValue(CONSOLE, CONSOLE_GEOMETRY_CIRC_HI) << 8) + getValue(CONSOLE, CONSOLE_GEOMETRY_CIRC_LO);
|
||||
printf( " wheel circumference .....: %d mm" _NL _NL, wheelCirc);
|
||||
|
||||
if (swVersion >= 59)
|
||||
printf(
|
||||
" mountain cap ............: %0.2f%%" _NL,
|
||||
(getValue(CONSOLE, CONSOLE_ASSIST_MOUNTAINCAP) * 1.5625));
|
||||
|
||||
printf( " odo .....................: %0.2f Km" _NL _NL,
|
||||
((getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_1) << 24) +
|
||||
(getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_2) << 16) +
|
||||
(getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_3) << 8) +
|
||||
(getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_4))) / (double)10
|
||||
);
|
||||
}
|
||||
|
||||
hwVersion = getValue(BATTERY, BATTERY_REF_HW);
|
||||
if (hwVersion == 0)
|
||||
printf("Battery not responding" _NL _NL);
|
||||
else {
|
||||
printf( "Battery information:" _NL
|
||||
" hardware version ........: %02d" _NL
|
||||
" software version ........: %02d" _NL,
|
||||
hwVersion, getValue(BATTERY, BATTERY_REF_SW)
|
||||
);
|
||||
|
||||
if (!gNoSerialNumbers)
|
||||
printf( " part number .............: %05d" _NL
|
||||
" item number .............: %05d" _NL,
|
||||
((getValue(BATTERY, BATTERY_SN_PN_HI) << 8) + getValue(BATTERY, BATTERY_SN_PN_LO)),
|
||||
((getValue(BATTERY, BATTERY_SN_ITEM_HI) << 8) + getValue(BATTERY, BATTERY_SN_ITEM_LO))
|
||||
);
|
||||
|
||||
printf( " voltage .................: %0.2fV" _NL
|
||||
" battery level ...........: %0.2f%%" _NL
|
||||
" maximum voltage .........: %0.2f%%" _NL
|
||||
" minimum voltage .........: %0.2f%%" _NL
|
||||
" mean voltage ............: %0.2f%%" _NL
|
||||
" resets ..................: %0d" _NL
|
||||
" ggjrCalib ...............: %0d" _NL
|
||||
" vctrlShorts .............: %0d" _NL
|
||||
" lmd .....................: %0.2fAh" _NL
|
||||
" cell capacity ...........: %0.2fAh" _NL _NL,
|
||||
((getValue(BATTERY, BATTERY_STATUS_VBATT_HI) << 8) + getValue(BATTERY, BATTERY_STATUS_VBATT_LO)) * 0.001,
|
||||
(getValue(BATTERY, BATTERY_STATUS_LEVEL) * 6.6667),
|
||||
getVoltageValue(BATTERY, BATTERY_STATS_VBATTMAX),
|
||||
getVoltageValue(BATTERY, BATTERY_STATS_VBATTMIN),
|
||||
getVoltageValue(BATTERY, BATTERY_STATS_VBATTMEAN),
|
||||
(getValue(BATTERY, BATTERY_STATS_RESET_HI) << 8) + getValue(BATTERY, BATTERY_STATS_RESET_LO),
|
||||
getValue(BATTERY, BATTERY_STSTS_GGJSRCALIB),
|
||||
getValue(BATTERY, BATTERY_STSTS_VCTRLSHORTS),
|
||||
((getValue(BATTERY, BATTERY_STATS_LMD_HI) << 8) + getValue(BATTERY, BATTERY_STATS_LMD_LO)) * 0.002142,
|
||||
((getValue(BATTERY, BATTERY_CONFIG_CELLCAPACITY_HI) << 8) + getValue(BATTERY, BATTERY_CONFIG_CELLCAPACITY_LO)) * 0.001
|
||||
);
|
||||
|
||||
|
||||
printf( " charge time worst .......: %0d" _NL
|
||||
" charge time mean ........: %0d" _NL
|
||||
" charge cycles ...........: %0d" _NL
|
||||
" full charge cycles ......: %0d" _NL
|
||||
" power cycles ............: %0d" _NL
|
||||
" battery temp max ........: %0d" _NL
|
||||
" battery temp min ........: %0d" _NL _NL,
|
||||
(getValue(BATTERY, BATTERY_STATS_CHARGETIMEWORST_HI) << 8) + getValue(BATTERY, BATTERY_STATS_CHARGETIMEWORST_LO),
|
||||
(getValue(BATTERY, BATTERY_STATS_CHARGETIMEMEAN_HI) << 8) + getValue(BATTERY, BATTERY_STATS_CHARGETIMEMEAN_LO),
|
||||
(getValue(BATTERY, BATTERY_STATS_BATTCYCLES_HI) << 8) + getValue(BATTERY, BATTERY_STATS_BATTCYCLES_LO),
|
||||
(getValue(BATTERY, BATTERY_STATS_BATTFULLCYCLES_HI) << 8) + getValue(BATTERY, BATTERY_STATS_BATTFULLCYCLES_LO),
|
||||
(getValue(BATTERY, BATTERY_STATS_POWERCYCLES_HI) << 8) + getValue(BATTERY, BATTERY_STATS_POWERCYCLES_HI),
|
||||
getValue(BATTERY, BATTERY_STATS_TBATTMAX),
|
||||
getValue(BATTERY, BATTERY_STATS_TBATTMIN)
|
||||
);
|
||||
|
||||
printChargeStats();
|
||||
|
||||
if (hwVersion >= 60)
|
||||
printBatteryStats();
|
||||
else
|
||||
printf(" no battery details supported by battery hardware #%d" _NL _NL, hwVersion);
|
||||
}
|
||||
|
||||
hwVersion = getValue(MOTOR, MOTOR_REF_HW);
|
||||
if (hwVersion == 0)
|
||||
printf("Motor not responding" _NL _NL);
|
||||
else {
|
||||
printf( "Motor information:" _NL
|
||||
" hardware version ........: %02d" _NL
|
||||
" software version ........: %02d" _NL
|
||||
//" temperature .............: %02d" _DEGREE_SIGN "C"_NL
|
||||
" speed limit .............: %02d Km/h" _NL,
|
||||
hwVersion, getValue(MOTOR, MOTOR_REF_SW),
|
||||
getValue(MOTOR, MOTOR_REALTIME_TEMP),
|
||||
getValue(MOTOR, MOTOR_ASSIST_MAXSPEED)
|
||||
);
|
||||
|
||||
wheelCirc = (getValue(MOTOR, MOTOR_GEOMETRY_CIRC_HI) << 8) + getValue(MOTOR, MOTOR_GEOMETRY_CIRC_LO);
|
||||
printf( " wheel circumference .....: %d mm" _NL _NL, wheelCirc);
|
||||
|
||||
if (!gNoSerialNumbers)
|
||||
printf( " part number .............: %05d" _NL
|
||||
" item number .............: %05d" _NL _NL,
|
||||
((getValue(MOTOR, MOTOR_SN_PN_HI) << 8) + getValue(MOTOR, MOTOR_SN_PN_LO)),
|
||||
((getValue(MOTOR, MOTOR_SN_ITEM_HI) << 8) + getValue(MOTOR, MOTOR_SN_ITEM_LO))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int xmain(int argc, char **argv)
|
||||
{
|
||||
int err, doShutdown = 0, consoleInSlaveMode = 0;
|
||||
struct TDeviceStatus status;
|
||||
|
||||
printf("BigXionFlasher USB " __BXF_VERSION__ _NL " (c) 2011-2013 by Thomas Koenig <info@bigxionflasher.org> - www.bigxionflasher.org" _NL);
|
||||
|
||||
if ((err=parseOptions(argc, argv) < 0))
|
||||
exit(1);
|
||||
|
||||
if ((err = LoadDriver(TREIBER_NAME)) < 0) {
|
||||
printf("LoadDriver error: %d" _NL, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((err = CanInitDriver(NULL)) < 0) {
|
||||
printf("CanInitDriver error: %d" _NL, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((err = CanDeviceOpen(0, DEVICE_OPEN)) < 0) {
|
||||
printf("CanDeviceOpen error: %d" _NL, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
CanSetSpeed(0, CAN_125K_BIT);
|
||||
CanSetMode(0, OP_CAN_START, CAN_CMD_ALL_CLEAR);
|
||||
CanGetDeviceStatus(0, &status);
|
||||
|
||||
if (status.DrvStatus >= DRV_STATUS_CAN_OPEN)
|
||||
{
|
||||
if (status.CanStatus == CAN_STATUS_BUS_OFF)
|
||||
{
|
||||
printf("CAN Status BusOff" _NL);
|
||||
CanSetMode(0, OP_CAN_RESET, CAN_CMD_NONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("error: could not open device" _NL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
consoleInSlaveMode = getValue(CONSOLE, CONSOLE_STATUS_SLAVE);
|
||||
|
||||
if (consoleInSlaveMode)
|
||||
{
|
||||
printf("console already in salve mode. good!" _NL _NL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gConsoleSetSlaveMode)
|
||||
{
|
||||
int retry = 20;
|
||||
|
||||
printf("putting console in salve mode ... ");
|
||||
do {
|
||||
setValue(CONSOLE, CONSOLE_STATUS_SLAVE, 1);
|
||||
consoleInSlaveMode = getValue(CONSOLE, CONSOLE_STATUS_SLAVE);
|
||||
usleep(200000);
|
||||
} while(retry-- && !consoleInSlaveMode);
|
||||
|
||||
doSleep(500); // give the console some time to settle
|
||||
printf("%s" _NL _NL, consoleInSlaveMode ? "done" : "failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("console not in slave mode" _NL _NL);
|
||||
}
|
||||
}
|
||||
|
||||
if (gAssistInitLevel != -1)
|
||||
{
|
||||
printf("setting initial assistance level to %d" _NL, gAssistInitLevel);
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_INITLEVEL, gAssistInitLevel);
|
||||
}
|
||||
|
||||
if (gSetSpeedLimit > 0)
|
||||
{
|
||||
printf("set speed limit to %0.2f km/h" _NL, gSetSpeedLimit);
|
||||
setSpeedLimit(gSetSpeedLimit);
|
||||
doShutdown = 1;
|
||||
} else if (gSetSpeedLimit == 0) {
|
||||
printf("disable speed limit, drive carefully" _NL);
|
||||
setSpeedLimit(0);
|
||||
doShutdown = 1;
|
||||
}
|
||||
|
||||
if (gSetMinSpeedLimit > 0) {
|
||||
printf("set minimal speed limit to %0.2f km/h" _NL, gSetMinSpeedLimit);
|
||||
setMinSpeedLimit(gSetMinSpeedLimit);
|
||||
doShutdown = 1;
|
||||
} else if (gSetMinSpeedLimit == 0) {
|
||||
printf("disable minimal speed limit, drive carefully" _NL);
|
||||
setMinSpeedLimit(0);
|
||||
doShutdown = 1;
|
||||
}
|
||||
|
||||
if (gSetThrottleSpeedLimit > 0) {
|
||||
printf("set throttle speed limit to %0.2f km/h" _NL, gSetThrottleSpeedLimit);
|
||||
setThrottleSpeedLimit(gSetThrottleSpeedLimit);
|
||||
doShutdown = 1;
|
||||
} else if (gSetThrottleSpeedLimit == 0) {
|
||||
printf("disable throttle speed limit, drive carefully" _NL);
|
||||
setThrottleSpeedLimit(0);
|
||||
doShutdown = 1;
|
||||
}
|
||||
|
||||
if (gSetMountainCap > 0) {
|
||||
printf("set mountain cap level to %0.2f%%" _NL, ((int)gSetMountainCap / 1.5625) * 1.5625);
|
||||
setValue(CONSOLE, CONSOLE_ASSIST_MOUNTAINCAP, gSetMountainCap / 1.5625);
|
||||
}
|
||||
|
||||
if (gSetWheelCircumference > 0) {
|
||||
printf("set wheel circumference to %d" _NL, gSetWheelCircumference);
|
||||
setWheelCircumference(gSetWheelCircumference);
|
||||
}
|
||||
|
||||
if (gPrintSystemSettings)
|
||||
printSystemSettings();
|
||||
|
||||
if ((doShutdown && !gSkipShutdown) || gPowerOff) {
|
||||
doSleep(1000);
|
||||
printf("shutting down system." _NL);
|
||||
setValue(BATTERY, BATTERY_CONFIG_SHUTDOWN, 1);
|
||||
}
|
||||
|
||||
CanDownDriver();
|
||||
UnloadDriver();
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
CanDownDriver();
|
||||
UnloadDriver();
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
71
bc.h
@@ -36,9 +36,32 @@
|
||||
#include <cstdint>
|
||||
#include <QDebug>
|
||||
#include <QObject> // Nötig für Q_GADGET/Q_ENUM Makros
|
||||
#include <QTime>
|
||||
|
||||
//uint8_t;
|
||||
|
||||
#define BCTimeStamp QTime::currentTime().toString("hh:mm:ss.zzz: ")
|
||||
|
||||
using namespace Qt::Literals::StringLiterals; // Für _L1
|
||||
|
||||
namespace BCTags
|
||||
{
|
||||
inline constexpr auto Bike = "Bike"_L1;
|
||||
inline constexpr auto Device = "Device"_L1;
|
||||
inline constexpr auto ID = "ID"_L1;
|
||||
inline constexpr auto Label = "Label"_L1;
|
||||
inline constexpr auto UnitLabel = "UnitLabel"_L1;
|
||||
inline constexpr auto IsWord = "IsWord"_L1;
|
||||
inline constexpr auto ReadOnly = "ReadOnly"_L1;
|
||||
inline constexpr auto Default = "Default"_L1;
|
||||
|
||||
inline constexpr auto Current = "Current"_L1;
|
||||
inline constexpr auto Enabled = "Enabled"_L1;
|
||||
inline constexpr auto ValueType = "ValueType"_L1;
|
||||
inline constexpr auto Min = "Min"_L1;
|
||||
inline constexpr auto Max = "Max"_L1;
|
||||
inline constexpr auto Factor = "Factor"_L1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple exception class
|
||||
@@ -73,15 +96,6 @@ namespace bc
|
||||
[[maybe_unused]] constexpr static double NORMALIZED_VOLTAGE_OFFSET = 20.8333;
|
||||
[[maybe_unused]] constexpr static double NORMALIZED_VOLTAGE_FAKTOR = 0.416667;
|
||||
|
||||
// misc
|
||||
//#define cbc::Version "CanBusControl 0.0.01 / 02.07.2022"
|
||||
[[maybe_unused]] constexpr static const char* Version = "BionxControl 0.1.00 / 08.11.2022 © 2022 chris@sourceworx.org";
|
||||
|
||||
[[maybe_unused]] constexpr static const char* OrgName = "source::worx";
|
||||
[[maybe_unused]] constexpr static const char* DomainName = "sourceworx.org";
|
||||
[[maybe_unused]] constexpr static const char* AppName = "BionxControl";
|
||||
|
||||
|
||||
// timer
|
||||
void delay_seconds( uint32_t );
|
||||
void delay_millis( uint32_t );
|
||||
@@ -91,27 +105,6 @@ namespace bc
|
||||
QString formatInt( int count, int len );
|
||||
} // namespace bc
|
||||
|
||||
// abbreviations:
|
||||
// SOC = State Of Charge
|
||||
// LMD = Last Measured Discharge
|
||||
// NIP = ?
|
||||
|
||||
/*
|
||||
|
||||
Needed ?
|
||||
#include <type_traits>
|
||||
|
||||
template <typename E>
|
||||
constexpr auto to_u(E e) noexcept {
|
||||
return static_cast<std::underlying_type_t<E>>(e);
|
||||
}
|
||||
|
||||
// constants.h
|
||||
#pragma once
|
||||
#include <QLatin1StringView>
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct BC
|
||||
{
|
||||
@@ -766,23 +759,5 @@ public:
|
||||
Q_ENUM(ID)
|
||||
};
|
||||
|
||||
using namespace Qt::Literals::StringLiterals; // Für _L1
|
||||
|
||||
namespace BCTags
|
||||
{
|
||||
inline constexpr auto Device = "Device"_L1;
|
||||
inline constexpr auto ID = "ID"_L1;
|
||||
inline constexpr auto Label = "Label"_L1;
|
||||
inline constexpr auto UnitLabel = "UnitLabel"_L1;
|
||||
inline constexpr auto IsWord = "IsWord"_L1;
|
||||
inline constexpr auto Default = "Default"_L1;
|
||||
|
||||
inline constexpr auto Current = "Current"_L1;
|
||||
inline constexpr auto Enabled = "Enabled"_L1;
|
||||
inline constexpr auto ValueType = "ValueType"_L1;
|
||||
inline constexpr auto Min = "Min"_L1;
|
||||
inline constexpr auto Max = "Max"_L1;
|
||||
inline constexpr auto Factor = "Factor"_L1;
|
||||
}
|
||||
|
||||
#endif // BC_H
|
||||
|
||||
@@ -1,344 +0,0 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <QSlider>
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
#include <QTableView>
|
||||
|
||||
#include <QVariantAnimation>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPainter>
|
||||
|
||||
#include "bcanimateddelegate.h"
|
||||
|
||||
|
||||
BCAnimatedDelegate::BCAnimatedDelegate(const BCValueList& valueList, QTableView* view)
|
||||
: QStyledItemDelegate{view}, _valueList{valueList}, _view{view}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
QString BCAnimatedDelegate::displayText(const QVariant& dataValue, const QLocale& locale) const
|
||||
{
|
||||
// Wir prüfen, ob im Variant unser Struct steckt
|
||||
if (dataValue.canConvert<const BCValue&>())
|
||||
{
|
||||
const BCValue& bc = dataValue.value<const BCValue/>();
|
||||
//qDebug() << " --- YES: " << bc.label;
|
||||
// Hier bauen wir den String zusammen, den man sieht,
|
||||
// wenn KEIN Editor offen ist.
|
||||
// Format: "Label: Wert Einheit"
|
||||
return QString("%1: %2 %3").arg(bc.label, bc.visibleValue, "mmX");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << " --- Nö!";
|
||||
}
|
||||
|
||||
// Fallback für normale Strings/Zahlen
|
||||
return QStyledItemDelegate::displayText(dataValue, locale);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
QWidget *BCAnimatedDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
QVariant rawData = index.data(Qt::EditRole);
|
||||
//if (!rawData.canConvert<BCValue*>())
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
/*
|
||||
const BCValue& bc = *rawData.value<BCValue*>();
|
||||
|
||||
// Nur bei Integern den Slider-Editor bauen
|
||||
if (bc.value.typeId() == QMetaType::Int)
|
||||
{
|
||||
QWidget *container = new QWidget(parent);
|
||||
container->setAutoFillBackground(true);
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout(container);
|
||||
layout->setContentsMargins(4, 0, 4, 0);
|
||||
layout->setSpacing(10);
|
||||
|
||||
// Linkes Label (Name)
|
||||
QLabel *lblName = new QLabel(bc.label, container);
|
||||
lblName->setFixedWidth(80);
|
||||
|
||||
// Slider
|
||||
QSlider *slider = new QSlider(Qt::Horizontal, container);
|
||||
slider->setRange(0, 100);
|
||||
slider->setObjectName("slider");
|
||||
|
||||
// Rechtes Label (Vorschau Wert + Einheit)
|
||||
QLabel *lblUnit = new QLabel(container);
|
||||
lblUnit->setFixedWidth(60);
|
||||
lblUnit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
lblUnit->setObjectName("lblUnit");
|
||||
|
||||
layout->addWidget(lblName);
|
||||
layout->addWidget(slider);
|
||||
layout->addWidget(lblUnit);
|
||||
|
||||
// Live-Update des Labels im Editor (aber noch kein Speichern im Model)
|
||||
connect(slider, &QSlider::valueChanged, this, [=](int val){
|
||||
lblUnit->setText(QString("%1 %2").arg(val).arg("mm2"));
|
||||
});
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
*/
|
||||
}
|
||||
|
||||
void BCAnimatedDelegate::setEditorData(QWidget *editor, const QModelIndex& index) const
|
||||
{
|
||||
// Daten vom Model in den Editor laden
|
||||
const BCValue& bc = *index.data(Qt::EditRole).value<BCValue*>();
|
||||
|
||||
QSlider *slider = editor->findChild<QSlider*>("slider");
|
||||
QLabel *lblUnit = editor->findChild<QLabel*>("lblUnit");
|
||||
|
||||
if (slider && lblUnit) {
|
||||
bool olDriverState = slider->blockSignals(true);
|
||||
slider->setValue(bc.visibleValue.toInt());
|
||||
slider->blockSignals(olDriverState);
|
||||
|
||||
lblUnit->setText(QString("%1 %2").arg(bc.visibleValue.toInt()).arg( "mm3"));
|
||||
} else {
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimatedDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const
|
||||
{
|
||||
// Daten vom Editor zurück ins Model speichern (Beim Schließen)
|
||||
QSlider *slider = editor->findChild<QSlider*>("slider");
|
||||
|
||||
if (slider) {
|
||||
int value = slider->value();
|
||||
model->setData(index, value, Qt::EditRole);
|
||||
} else {
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimatedDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
// __fix!
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
QSize BCAnimatedDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
return QStyledItemDelegate::sizeHint(option,index);
|
||||
/*
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption(&opt, index);
|
||||
opt.text = formatDisplayString(index);
|
||||
|
||||
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
|
||||
return style->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), opt.widget);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void BCAnimatedDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
|
||||
// 1. Standard-Zeichnen (Text, Hintergrund, Selection) durchführen
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
|
||||
//QPen pen(QColor(255, 165, 0)); // Orange
|
||||
|
||||
/*
|
||||
if (index.row() == _highlightedRow && _opacity > 0.0)
|
||||
{
|
||||
painter->save();
|
||||
|
||||
qDebug() << " --- is highlight: " << index.row();
|
||||
|
||||
QColor highlightColor( 0xFF9800 );
|
||||
highlightColor.setAlphaF(_opacity);
|
||||
|
||||
QPen pen(highlightColor, 3);
|
||||
painter->setPen(pen);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRoundedRect(option.rect.adjusted(2, 2, -2, -2), 8, 8);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
int row = index.row();
|
||||
if (index.column() == 1 )
|
||||
{
|
||||
if( m_rowOpacities.contains(row))
|
||||
{
|
||||
paintHighlightRow(painter,option,index);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
qreal opacity = m_rowOpacities.value(row);
|
||||
if (opacity > 0.01)
|
||||
{
|
||||
painter->save();
|
||||
painter->setOpacity(opacity);
|
||||
painter->fillRect(option.rect, QColor(255, 140, 0, 120));
|
||||
painter->restore();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void BCAnimatedDelegate::paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
int row = index.row();
|
||||
qreal opacity = m_rowOpacities.value(row);
|
||||
painter->setOpacity(opacity);
|
||||
// Margin von 4px
|
||||
QRect itemRect = option.rect.adjusted(3, 3, -3, -3);
|
||||
|
||||
// Border von 2px berücksichtigen (nach innen)
|
||||
//QRect contentRect = itemRect.adjusted(2, 2, -2, -2);
|
||||
// painter->fillRect(contentRect,Qt::green);
|
||||
/*
|
||||
// Hintergrund (weiß)
|
||||
painter->setBrush(Qt::white);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->drawRoundedRect(itemRect, 8, 8);
|
||||
*/
|
||||
// Border (2px solid #2196F3)
|
||||
QPen borderPen( Qt::red, 1);
|
||||
painter->setPen(borderPen);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRoundedRect(itemRect, 2, 2);
|
||||
|
||||
// Padding von 8px für den Content
|
||||
//QRect textRect = contentRect.adjusted(8, 8, -8, -8);
|
||||
|
||||
/*
|
||||
// Text zeichnen
|
||||
painter->setPen(Qt::black); // oder option.palette.color(QPalette::Text)
|
||||
QString text = index.data(Qt::DisplayRole).toString();
|
||||
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
|
||||
*/
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
|
||||
void BCAnimatedDelegate::onHighlightRow(int row)
|
||||
{
|
||||
// Alte Animation für diese Zeile stoppen falls vorhanden
|
||||
if (m_rowAnimations.contains(row))
|
||||
{
|
||||
m_rowAnimations[row]->stop();
|
||||
m_rowAnimations[row]->deleteLater();
|
||||
}
|
||||
|
||||
// QVariantAnimation ist flexibler als QPropertyAnimation
|
||||
auto* anim = new QVariantAnimation(this);
|
||||
anim->setDuration(800);
|
||||
anim->setStartValue(0.0);
|
||||
anim->setEndValue(1.0);
|
||||
|
||||
// Custom Easing für Fade-in/out Effekt
|
||||
anim->setEasingCurve(QEasingCurve::OutQuad);
|
||||
|
||||
connect(anim, &QVariantAnimation::valueChanged, this, [this, row](const QVariant& value)
|
||||
{
|
||||
qreal progress = value.toReal();
|
||||
qreal opacity;
|
||||
|
||||
// Schnelles Fade-in (20%), langsames Fade-out (80%)
|
||||
if (progress < 0.2) {
|
||||
opacity = progress * 5.0; // 0->1 in 20%
|
||||
} else {
|
||||
opacity = 1.0 - ((progress - 0.2) / 0.8); // 1->0 in 80%
|
||||
}
|
||||
|
||||
m_rowOpacities[row] = opacity;
|
||||
updateRow(row);
|
||||
});
|
||||
|
||||
connect(anim, &QVariantAnimation::finished, this, [this, row, anim]()
|
||||
{
|
||||
m_rowOpacities.remove(row);
|
||||
m_rowAnimations.remove(row);
|
||||
updateRow(row);
|
||||
anim->deleteLater();
|
||||
});
|
||||
|
||||
m_rowAnimations[row] = anim;
|
||||
anim->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
}
|
||||
|
||||
// Optional: alle Highlights sofort clearen
|
||||
void BCAnimatedDelegate::clearAllHighlights()
|
||||
{
|
||||
for(auto* anim : std::as_const(m_rowAnimations))
|
||||
{
|
||||
anim->stop();
|
||||
anim->deleteLater();
|
||||
}
|
||||
m_rowAnimations.clear();
|
||||
m_rowOpacities.clear();
|
||||
|
||||
if (_view)
|
||||
{
|
||||
_view->viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimatedDelegate::updateRow(int row)
|
||||
{
|
||||
if (_view && _view->model() && row >= 0)
|
||||
{
|
||||
QModelIndex idx = _view->model()->index(row,1);
|
||||
QRect rect = _view->visualRect(idx);
|
||||
if (!rect.isEmpty()) {
|
||||
_view->viewport()->update(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
186
bcdelightpmwidget.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
|
||||
|
||||
#include <QPropertyAnimation>
|
||||
#include <QSequentialAnimationGroup>
|
||||
#include <QParallelAnimationGroup>
|
||||
#include <QRandomGenerator>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QPainterPath>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QIcon>
|
||||
#include <QDirIterator>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <bcdelightpmwidget.h>
|
||||
|
||||
|
||||
BCDelightPMWidget::BCDelightPMWidget(QWidget *parent)
|
||||
: QObject(parent), _playGround{parent}
|
||||
{
|
||||
loadWidgetsFromResources();
|
||||
}
|
||||
|
||||
|
||||
// Die Methode zum automatischen Einlesen
|
||||
void BCDelightPMWidget::loadWidgetsFromResources()
|
||||
{
|
||||
|
||||
QString resourcePath = ":/resources/smile";
|
||||
|
||||
QDirIterator it(resourcePath, QDir::Files);
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
QString fullPath = it.next();
|
||||
// Eine Zufallsfarbe für den Button-Hintergrund generieren
|
||||
QStringList colors = {"#ff5555", "#50fa7b", "#8be9fd", "#ffb86c"};
|
||||
|
||||
// Ihre Funktion aufrufen und den Pfad übergeben
|
||||
createFlyingWidget(fullPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BCDelightPMWidget::createFlyingWidget(const QString& iconPath)
|
||||
{
|
||||
// 1. Button als Kind des Playground erstellen
|
||||
QPushButton *btn = new QPushButton(_playGround);
|
||||
|
||||
// 2. Das Icon laden und setzen
|
||||
QPixmap pixmap(iconPath);
|
||||
QIcon icon(pixmap);
|
||||
btn->setIcon(icon);
|
||||
|
||||
// 3. WICHTIG: Icon-Größe und Button-Größe synchronisieren
|
||||
// Damit das Bild den Button voll ausfüllt
|
||||
QSize size(128, 128);
|
||||
btn->setFixedSize(size); // Die Klick-Fläche
|
||||
btn->setIconSize(size); // Das Bild darin
|
||||
|
||||
// 4. Stylesheet: Alle Standard-Rahmen und Hintergründe entfernen
|
||||
// "border: none" entfernt den 3D-Rahmen
|
||||
// "background: transparent" macht den Rest unsichtbar
|
||||
btn->setStyleSheet(
|
||||
"QPushButton {"
|
||||
" border: none;"
|
||||
" background-color: transparent;"
|
||||
" outline: none;" /* Entfernt den Fokus-Rahmen beim Klicken */
|
||||
"}"
|
||||
// Optional: Kleiner visueller Effekt beim Drücken (Bild bewegt sich leicht)
|
||||
"QPushButton:pressed {"
|
||||
" padding-top: 4px;"
|
||||
" padding-left: 4px;"
|
||||
"}"
|
||||
);
|
||||
|
||||
btn->show();
|
||||
|
||||
QGraphicsOpacityEffect *opacityEff = new QGraphicsOpacityEffect(btn);
|
||||
opacityEff->setOpacity(1.0);
|
||||
btn->setGraphicsEffect(opacityEff);
|
||||
// --------------------------------------
|
||||
|
||||
btn->show();
|
||||
|
||||
btn->move(50 + _flyingWidgets.size() * 60, 50);
|
||||
_flyingWidgets.append(btn);
|
||||
|
||||
btn->move(_playGround->width()/2, _playGround->height()/2);
|
||||
opacityEff->setOpacity(0.0);
|
||||
|
||||
}
|
||||
void BCDelightPMWidget::onStartChaos()
|
||||
{
|
||||
// Master-Gruppe, damit alle Widgets gleichzeitig starten
|
||||
QParallelAnimationGroup *masterGroup = new QParallelAnimationGroup(this);
|
||||
|
||||
// Gemeinsamer Startpunkt berechnen (Mitte des Playgrounds)
|
||||
// Wir ziehen die halbe Größe eines Widgets (ca. 25px) ab, damit sie wirklich zentriert sind
|
||||
int centerX = (_playGround->width() / 2) - 25;
|
||||
int centerY = (_playGround->height() / 2) - 25;
|
||||
QPoint startPoint(centerX, centerY);
|
||||
|
||||
for (QWidget *widget : std::as_const(_flyingWidgets))
|
||||
{
|
||||
|
||||
QParallelAnimationGroup *widgetGroup = new QParallelAnimationGroup(masterGroup);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 1. Die Bogen-Animation (QVariantAnimation statt QPropertyAnimation)
|
||||
// ---------------------------------------------------------
|
||||
|
||||
// ZIELE UND STÜTZPUNKTE BERECHNEN
|
||||
int maxX = _playGround->width() - widget->width();
|
||||
int maxY = _playGround->height() - widget->height();
|
||||
QPoint endPoint(
|
||||
QRandomGenerator::global()->bounded(qMax(0, maxX)),
|
||||
QRandomGenerator::global()->bounded(qMax(0, maxY))
|
||||
);
|
||||
|
||||
// Der Kontrollpunkt bestimmt die Kurve.
|
||||
// Für eine Rakete muss er viel HÖHER liegen als Start und Ziel.
|
||||
// Wir nehmen die Mitte zwischen Start/Ziel und gehen 300px nach oben (Y minus).
|
||||
int controlX = (startPoint.x() + endPoint.x()) / 2;
|
||||
int controlY = qMin(startPoint.y(), endPoint.y()) - 300;
|
||||
|
||||
// Pfad erstellen (Quadratische Bézierkurve)
|
||||
QPainterPath path;
|
||||
path.moveTo(startPoint);
|
||||
// quadTo(Kontrollpunkt, Endpunkt)
|
||||
path.quadTo(controlX, controlY, endPoint.x(), endPoint.y());
|
||||
|
||||
// Die Animation treibt den Fortschritt von 0.0 bis 1.0
|
||||
QVariantAnimation *animCurve = new QVariantAnimation();
|
||||
int duration = 2600 + QRandomGenerator::global()->bounded(800);
|
||||
animCurve->setDuration(duration);
|
||||
animCurve->setStartValue(0.0);
|
||||
animCurve->setEndValue(1.0);
|
||||
|
||||
// Für ballistische Flugbahnen ist 'OutQuad' oder 'OutSine' realistisch
|
||||
// (Schneller Start, oben langsamer, unten wieder schneller - physikalisch komplex,
|
||||
// aber OutQuad sieht gut aus für "Wurf")
|
||||
animCurve->setEasingCurve(QEasingCurve::OutQuad);
|
||||
|
||||
// WICHTIG: Lambda, um bei jedem Schritt die Position zu setzen
|
||||
// Wir müssen 'widget' und 'path' in das Lambda capturen (by value für path ist ok)
|
||||
connect(animCurve, &QVariantAnimation::valueChanged, [widget, path](const QVariant &val){
|
||||
qreal progress = val.toReal();
|
||||
|
||||
// Magie: Berechne den Punkt auf der Kurve bei 'progress' Prozent
|
||||
QPointF currentPos = path.pointAtPercent(progress);
|
||||
|
||||
widget->move(currentPos.toPoint());
|
||||
});
|
||||
|
||||
widgetGroup->addAnimation(animCurve);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 2. Fade-Out (Bleibt fast gleich)
|
||||
// ---------------------------------------------------------
|
||||
QGraphicsOpacityEffect *eff = qobject_cast<QGraphicsOpacityEffect*>(widget->graphicsEffect());
|
||||
if (eff) {
|
||||
QPropertyAnimation *animFade = new QPropertyAnimation(eff, "opacity");
|
||||
animFade->setDuration(duration);
|
||||
animFade->setStartValue(1.0);
|
||||
animFade->setEndValue(0.0);
|
||||
// Erst am Ende ausblenden (ExpoCurve), damit man den Flugbogen sieht
|
||||
animFade->setEasingCurve(QEasingCurve::InExpo);
|
||||
widgetGroup->addAnimation(animFade);
|
||||
}
|
||||
|
||||
masterGroup->addAnimation(widgetGroup);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Speicher aufräumen, wenn alles vorbei ist
|
||||
// Hinweis: Die Widgets bleiben danach unsichtbar (Opacity 0), existieren aber noch.
|
||||
connect(masterGroup, &QAbstractAnimation::finished, masterGroup, &QObject::deleteLater);
|
||||
|
||||
masterGroup->start();
|
||||
}
|
||||
33
bcdelightpmwidget.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef BCDELIGHTPMWIDGET_H
|
||||
#define BCDELIGHTPMWIDGET_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
/**
|
||||
* @brief The BCDelightPMWidget class : Demonstration Graphischer
|
||||
* Effekte für unseren Produktmanager Simon.
|
||||
*/
|
||||
|
||||
class BCDelightPMWidget : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BCDelightPMWidget( QWidget* parent );
|
||||
|
||||
public slots:
|
||||
|
||||
void onStartChaos();
|
||||
|
||||
protected:
|
||||
|
||||
void loadWidgetsFromResources();
|
||||
void createFlyingWidget(const QString& iconPath);
|
||||
|
||||
QWidget* _playGround{};
|
||||
// Liste der Widgets, die wir bewegen
|
||||
QList<QWidget*> _flyingWidgets;
|
||||
};
|
||||
|
||||
#endif // BCDELIGHTPMWIDGET_H
|
||||
@@ -30,8 +30,10 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <QHeaderView>
|
||||
|
||||
#include <bcdeviceview.h>
|
||||
#include <bcanimateddelegate.h>
|
||||
#include <bcvaluedelegate.h>
|
||||
|
||||
BCDeviceView::BCDeviceView(QWidget *parent)
|
||||
: QTableView(parent)
|
||||
@@ -42,10 +44,8 @@ BCDeviceView::BCDeviceView(QWidget *parent)
|
||||
//horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
|
||||
// __fix! ziemlich wildes ge-pointere, hier
|
||||
_itemDelegate = new BCAnimatedDelegate( _valueModel.getValueList(), this);
|
||||
setItemDelegate( _itemDelegate );
|
||||
|
||||
qDebug() << " --- View size I: " << this->size();
|
||||
_itemDelegate = new BCValueDelegate( _valueModel.getValueList(), this);
|
||||
setItemDelegateForColumn( 1, _itemDelegate );
|
||||
|
||||
}
|
||||
|
||||
@@ -53,39 +53,88 @@ BCDeviceView::BCDeviceView(QWidget *parent)
|
||||
|
||||
void BCDeviceView::setDeviceID( BCDevice::ID deviceID )
|
||||
{
|
||||
qDebug() << " --- View size II: " << this->size();
|
||||
|
||||
_devideID = deviceID;
|
||||
}
|
||||
|
||||
BCDevice::ID BCDeviceView::getDeviceID() const
|
||||
BCDevice::ID BCDeviceView::deviceID() const
|
||||
{
|
||||
return _devideID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gibt eine Referenz auf der ValueList zurück.
|
||||
*/
|
||||
|
||||
|
||||
const BCValueList& BCDeviceView::getValueListX()
|
||||
const BCValueList& BCDeviceView::getValueList()
|
||||
{
|
||||
return _valueModel.getValueList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Flag, ob diese View schonmal angezeigt wurde.
|
||||
*/
|
||||
|
||||
// __FIX ist das ok so?
|
||||
bool BCDeviceView::firstExpose()
|
||||
{
|
||||
bool stored = _firstExpose;
|
||||
_firstExpose = false;
|
||||
return stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SLOT, der aufgerufen wird, wenn die ValueList vom XML-Lader fertig geladen wurde.
|
||||
* Die DeviceView nimmt die ValueList dann in Besitz.
|
||||
*/
|
||||
void BCDeviceView::onValueListReady( BCDevice::ID deviceID, BCValueList valueList )
|
||||
{
|
||||
qDebug() << " --- onValueListReady: " << deviceID << ": " << valueList.size();
|
||||
if(_devideID == deviceID)
|
||||
{
|
||||
_valueModel.takeValueList( valueList );
|
||||
/*
|
||||
const BCValueList& list = _valueModel.getValueList();
|
||||
int rows = _valueModel.rowCount();
|
||||
for (int r = 0; r < rows; ++r)
|
||||
{
|
||||
BCValuePtr bcValue = list[r];
|
||||
if( !bcValue->isReadOnly() )
|
||||
{
|
||||
QModelIndex index = _valueModel.index(r, 1);
|
||||
openPersistentEditor(index);
|
||||
}
|
||||
}
|
||||
*/
|
||||
} // if id
|
||||
|
||||
}
|
||||
|
||||
void BCDeviceView::onValueUpdated(int index, BCValue::State state, const QString& newVisibleValue )
|
||||
|
||||
/**
|
||||
* @brief SLOT, der aufgerufen wird, wenn ein Value geändert wurde. Gibt dem ItemDelegate Bescheid.
|
||||
*/
|
||||
|
||||
void BCDeviceView::updateValue(int index,BCValue::Flags newState, uint32_t rawValue )
|
||||
{
|
||||
_valueModel.onValueUpdated( index, state, newVisibleValue);
|
||||
_valueModel.updateValue( index, newState, rawValue );
|
||||
_itemDelegate->onHighlightRow( index );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Die Spalte mit dem Label soll immer bei 60% der Gesamtbreite liegen.
|
||||
* @param event
|
||||
*/
|
||||
|
||||
void BCDeviceView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
// Zuerst die Basisklasse aufrufen (Wichtig für Layouts!)
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
// Berechnung: 40% der aktuellen Breite
|
||||
// Tipp: viewport()->width() ist genauer als width(), da es Scrollbars rausrechnet!
|
||||
int totalWidth = viewport()->width();
|
||||
int col0Width = static_cast<int>(totalWidth * 0.60);
|
||||
|
||||
// Setzen der Breite
|
||||
horizontalHeader()->resizeSection(0, col0Width);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <bcvaluemodel.h>
|
||||
|
||||
|
||||
class BCAnimatedDelegate;
|
||||
class BCValueDelegate;
|
||||
|
||||
class BCDeviceView : public QTableView
|
||||
{
|
||||
@@ -48,25 +48,27 @@ public:
|
||||
|
||||
explicit BCDeviceView(QWidget *parent = nullptr);
|
||||
|
||||
|
||||
void setDeviceID( BCDevice::ID deviceID );
|
||||
BCDevice::ID getDeviceID() const;
|
||||
BCDevice::ID deviceID() const;
|
||||
|
||||
const BCValueList& getValueListX();
|
||||
//BCValueModel &getValueModel();
|
||||
const BCValueList& getValueList();
|
||||
|
||||
bool hasContent();
|
||||
bool firstExpose();
|
||||
void updateValue(int index, BCValue::Flags newState, uint32_t rawValue );
|
||||
|
||||
public slots:
|
||||
|
||||
void onValueListReady( BCDevice::ID deviceID, BCValueList valueList );
|
||||
void onValueUpdated( int index, BCValue::State state, const QString& newVisibleValue="" );
|
||||
|
||||
protected:
|
||||
|
||||
BCDevice::ID _devideID{BCDevice::ID::Invalid};
|
||||
BCValueModel _valueModel;
|
||||
BCAnimatedDelegate* _itemDelegate{};
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
bool _firstExpose{true};
|
||||
BCDevice::ID _devideID{BCDevice::ID::Invalid};
|
||||
BCValueModel _valueModel;
|
||||
BCValueDelegate* _itemDelegate{};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -74,7 +74,9 @@ TransmitResult BCDriverDummy::readRawByte( uint32_t deviceID, uint8_t registerID
|
||||
{
|
||||
Q_UNUSED(deviceID)
|
||||
Q_UNUSED(registerID)
|
||||
qDebug() << " --- Dummy: readRawByte:DriverState: " << getDriverState();
|
||||
// Tätigkeit simulieren
|
||||
//bc::delay_millis(200);
|
||||
bc::delay_millis(50);
|
||||
uint8_t myRandomByte = static_cast<uint8_t>(QRandomGenerator::global()->bounded(256));
|
||||
return myRandomByte;
|
||||
}
|
||||
@@ -88,7 +90,7 @@ TransmitResult BCDriverDummy::writeRawByte( uint32_t deviceID, uint8_t registerI
|
||||
{
|
||||
Q_UNUSED(deviceID)
|
||||
Q_UNUSED(registerID)
|
||||
qDebug() << " --- BCDriverTinyCan writeRawValue: " << value;
|
||||
Q_UNUSED(value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
122
bcdriverstatewidget.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <bcdriverstatewidget.h>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Hilfswidget: Zeigt den DriverState als Icon an.
|
||||
*/
|
||||
|
||||
BCDriverStateWidget::BCDriverStateWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(10, 2, 10, 2);
|
||||
//layout->setSpacing(8);
|
||||
|
||||
_led = new QLabel(this);
|
||||
_led->setFixedSize(12, 12);
|
||||
|
||||
layout->addWidget(_led);
|
||||
|
||||
// Startzustand
|
||||
onDriverStateChanged(BCDriver::DriverState::NotPresent, "Kein Treiber geladen.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Hauptfunktion zum Setzen des Status
|
||||
// 'customMessage' ist optional. Wenn leer, wird ein Standardtext genommen.
|
||||
void BCDriverStateWidget::onDriverStateChanged(BCDriver::DriverState state, const QString& customMessage)
|
||||
{
|
||||
Q_UNUSED(customMessage)
|
||||
_state = state;
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
|
||||
void BCDriverStateWidget::updateStyle()
|
||||
{
|
||||
QString ledStyle;
|
||||
QString toolTipText;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case BCDriver::DriverState::NotPresent:
|
||||
// FLUENT GRAY (Neutral)
|
||||
// Wir machen es dunkelgrau mit hellem Rand -> "Ausgeschaltet"-Look
|
||||
ledStyle = "background-color: #3B3B3B; border: 1px solid #606060;";
|
||||
toolTipText = "Kein Treiber geladen.";
|
||||
break;
|
||||
|
||||
case BCDriver::DriverState::Error:
|
||||
// FLUENT RED (Critical)
|
||||
ledStyle = "background-color: #C42B1C; border: 1px solid #A80000;";
|
||||
toolTipText = "Fehler beim Laden des Treibers.";
|
||||
break;
|
||||
|
||||
// hier: dll vorhanden, Treiber geladen
|
||||
case BCDriver::DriverState::Loaded:
|
||||
case BCDriver::DriverState::Initialized:
|
||||
case BCDriver::DriverState::Opened:
|
||||
// ORANGE
|
||||
ledStyle = "background-color: #FF8C00; border: 1px solid #A80000;";
|
||||
toolTipText = "Kein Gerät verbunden.";
|
||||
break;
|
||||
|
||||
case BCDriver::DriverState::DeviceReady:
|
||||
// FLUENT GREEN (Success)
|
||||
ledStyle = "background-color: #107C10; border: 1px solid #0E600E;";
|
||||
toolTipText = "Verbindung erfolgreich hergestellt.";
|
||||
break;
|
||||
}
|
||||
|
||||
// Styles anwenden (immer rund machen)
|
||||
_led->setStyleSheet(ledStyle + "border-radius: 6px;");
|
||||
setToolTip(toolTipText);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief minimale click event
|
||||
*/
|
||||
|
||||
void BCDriverStateWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
emit clicked();
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
@@ -30,51 +30,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef BCGUIHELPERS_H
|
||||
#define BCGUIHELPERS_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include <bcdriver.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Einfaches Buttonwidget, um zwischen Dark- und Lightmode
|
||||
* zu wechseln
|
||||
*/
|
||||
|
||||
class BCThemeSwitchButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit BCThemeSwitchButton(QWidget *parent = nullptr);
|
||||
void setDarkMode( bool isDark );
|
||||
|
||||
signals:
|
||||
|
||||
void themeChanged(bool isDark);
|
||||
|
||||
private slots:
|
||||
|
||||
void toggleMode();
|
||||
|
||||
private:
|
||||
|
||||
void updateIcon();
|
||||
|
||||
bool _isDarkMode{false};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// -----------------------------------------------------------------------------------
|
||||
/// -----------------------------------------------------------------------------------
|
||||
#ifndef BCDRIVERSTATEWIDGET_H
|
||||
#define BCDRIVERSTATEWIDGET_H
|
||||
|
||||
|
||||
/**
|
||||
@@ -82,6 +39,12 @@ private:
|
||||
* Drivers anzuzeigen.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
|
||||
#include <bcdriver.h>
|
||||
class BCDriverStateWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -110,4 +73,4 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
#endif // BCGUIHELPERS_H
|
||||
#endif // BCDRIVERSTATEWIDGET_H
|
||||
@@ -151,7 +151,6 @@ BCDriver::DriverStateResult BCDriverTinyCan::loadDriver()
|
||||
return _driverState;
|
||||
};
|
||||
|
||||
|
||||
// #1. erstmal komplett zurücksetzen
|
||||
resetDriver();
|
||||
// #2. Treiber laden, initialisieren und
|
||||
@@ -177,27 +176,18 @@ BCDriver::DriverStateResult BCDriverTinyCan::loadDriver()
|
||||
BCDriver::DriverStateResult BCDriverTinyCan::setConsoleSlaveMode()
|
||||
{
|
||||
|
||||
// Wir versuchen ein Test-Byte zu lesen, hier: einfach die Hardware
|
||||
// Revision der Console.
|
||||
|
||||
uint32_t console = static_cast<uint32_t>(BCDevice::ID::Console);
|
||||
uint8_t slaveFlag = static_cast<uint8_t> (BC::ID::Cons_Status_Slave);
|
||||
|
||||
qDebug() << "XXX BCDriverTinyCan::Driver Init: putting Console in slave mode ... ";
|
||||
|
||||
unsigned int retry = cTimeOuts;
|
||||
TransmitResult isSlave = 0;
|
||||
// Already slave?
|
||||
isSlave = readRawByte( console, slaveFlag );
|
||||
if( isSlave.has_value() )
|
||||
{
|
||||
qDebug() << "Console responded: " << isSlave.value();
|
||||
if( isSlave.value() == 1 )
|
||||
{
|
||||
qDebug() << "Console already in slave mode. good!";
|
||||
return DriverState::DeviceReady;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "BCDriverTinyCan::BCDriverTinyCan::XXX Driver Init: putting Console in slave mode ... ";
|
||||
|
||||
unsigned int retry = cTimeOuts;
|
||||
if( isSlave.has_value() && isSlave.value() == 1 )
|
||||
goto happyEnd;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -208,11 +198,17 @@ BCDriver::DriverStateResult BCDriverTinyCan::setConsoleSlaveMode()
|
||||
} while( retry-- && !(*isSlave) );
|
||||
|
||||
bc::delay_millis( 500 ); // give the Console some time to settle
|
||||
//if( !isSlave )
|
||||
//emit statusHint( QString("putting Console in slave mode ") + (isSlave ? "done" : "failed") );
|
||||
|
||||
if( isSlave.has_value() && isSlave.value() == 1 )
|
||||
goto happyEnd;
|
||||
|
||||
// ist das jetzt irgendwie schlimm, wenn wir keine slave Console haben
|
||||
return isSlave ? DriverState::DeviceReady : DriverState::Opened;
|
||||
return DriverState::Opened;
|
||||
|
||||
happyEnd:
|
||||
|
||||
_driverState = DriverState::DeviceReady;
|
||||
return DriverState::DeviceReady;
|
||||
|
||||
}
|
||||
|
||||
@@ -237,75 +233,14 @@ void BCDriverTinyCan::resetDriver()
|
||||
TransmitResult BCDriverTinyCan::readRawByte( uint32_t deviceID, uint8_t registerID ) const
|
||||
{
|
||||
|
||||
qDebug() << " --- CAN Read Byte: Device: "<< deviceID << " register: " << registerID << " TRY! ";
|
||||
|
||||
struct TCanMsg msg;
|
||||
int err, retry = 20;
|
||||
int timeout = 80;
|
||||
|
||||
unsigned char receipient = (unsigned char) deviceID;
|
||||
unsigned char reg = (unsigned char) registerID;
|
||||
|
||||
msg.MsgFlags = 0L;
|
||||
msg.Id = receipient;
|
||||
msg.MsgLen = 2;
|
||||
msg.MsgData[0] = 0x00;
|
||||
msg.MsgData[1] = reg;
|
||||
|
||||
CanTransmit(0, &msg, 1);
|
||||
|
||||
while(timeout-- && CanTransmitGetCount(0))
|
||||
bc::delay_millis( cTIMEOUT_MS );
|
||||
|
||||
if (timeout == -1)
|
||||
qDebug() << "error: could not send value to node ";
|
||||
|
||||
retry:
|
||||
|
||||
timeout = 80;
|
||||
while(timeout-- && !CanReceiveGetCount(0))
|
||||
bc::delay_millis( cTIMEOUT_MS );
|
||||
|
||||
if (timeout == -1)
|
||||
{
|
||||
qDebug() << "error: no response from node";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = CanReceive(0, &msg, 1)) > 0)
|
||||
{
|
||||
qDebug() << " retry: " << retry << " BIB:" << BC::ID::ID_Bib << " msg.Id: " << msg.Id << " msg.MsgLen: " << msg.MsgLen << " msg.MsgData[1]: " << msg.MsgData[1] << " reg: " << reg;
|
||||
if (--retry && (msg.Id != (uint32_t)BC::ID::ID_Bib|| msg.MsgLen != 4 || msg.MsgData[1] != reg))
|
||||
goto retry;
|
||||
|
||||
if (!retry)
|
||||
{
|
||||
qDebug() << "XXX error: no response from node: " << err;
|
||||
return 0;
|
||||
}
|
||||
qDebug() << " --- CAN Read Byte: Device: "<< deviceID << " register: " << registerID << " BYTE: " << (uint32_t) msg.MsgData[3];
|
||||
return (unsigned int) msg.MsgData[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Error:" <<err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/*
|
||||
//TransmitResult
|
||||
qDebug() << " --- BCDriverTinyCan::readRawByte DriverState: " << getDriverState();
|
||||
|
||||
if( _driverState <DriverState::Opened )
|
||||
return std::unexpected(QString("readRawValue error: driver not loaded." ) );
|
||||
return std::unexpected(QString("readRawValue error: Treiber nicht geladen." ) );
|
||||
|
||||
unsigned char receipient = (unsigned char ) deviceID;
|
||||
::TCanMsg msg;
|
||||
|
||||
// msg verpacken
|
||||
msg.MsgFlags = 0L;
|
||||
msg.Id = receipient;//deviceID;
|
||||
msg.Id = deviceID;
|
||||
msg.MsgLen = 2;
|
||||
msg.MsgData[0] = 0x00;
|
||||
msg.MsgData[1] = registerID;
|
||||
@@ -313,16 +248,15 @@ retry:
|
||||
// msg verschicken
|
||||
::CanTransmit( 0, &msg, 1 );
|
||||
|
||||
int retries = cRetries; // 5?
|
||||
// cTimeOuts (== 20) mal cTIMEOUT_MS (== 10 ms ) Versuche ...
|
||||
int timeOuts = cTimeOuts; // 20 ?
|
||||
int retries = cRetries; // 5
|
||||
int timeOuts = cTimeOuts; // 20
|
||||
|
||||
// ... warten bis der Sendepuffer leer ist
|
||||
while( timeOuts-- && ::CanTransmitGetCount( 0 ) )
|
||||
bc::delay_millis( cTIMEOUT_MS );
|
||||
|
||||
if( timeOuts == -1 )
|
||||
return std::unexpected(QString("readRawValue error: could not send value" ));
|
||||
return std::unexpected(QString("readRawValue error: Sendefehler" ));
|
||||
|
||||
retry:
|
||||
|
||||
@@ -333,46 +267,34 @@ retry:
|
||||
bc::delay_millis( cTIMEOUT_MS );
|
||||
|
||||
if( timeOuts == -1 )
|
||||
return std::unexpected(QString("getValue error: no response from node" ));
|
||||
return std::unexpected(QString("readRawValue error: (Node)Timeout" ));
|
||||
|
||||
// message empfangen
|
||||
int err = ::CanReceive( 0, &msg, 1 );
|
||||
//qDebug() << "HÄÄ ?" << err << "reg: "<< registerID <<" timeOuts: " << timeOuts;
|
||||
|
||||
if( err < 0 )
|
||||
//throw BCException( "getValue error: could not receive value" );
|
||||
qDebug( "getValue error: could not receive value" );
|
||||
return std::unexpected(QString("readRawValue error: Lesefehler" ));
|
||||
|
||||
//qDebug() << "HÄÄ 2" <<msg.Id;
|
||||
//qDebug() << "HÄÄ 2" <<msg.MsgLen;
|
||||
//qDebug() << "HÄÄ 2" <<msg.MsgData[1];
|
||||
|
||||
//if( err > 0 )
|
||||
if( --retries && ( msg.Id != BIB || msg.MsgLen != 4 || msg.MsgData[1] != registerID ) )
|
||||
if( --retries && ( msg.Id != (uint32_t)BC::ID::ID_Bib || msg.MsgLen != 4 || msg.MsgData[1] != registerID ) )
|
||||
goto retry;
|
||||
|
||||
if( !timeOuts )
|
||||
return std::unexpected(QString("CAN response errror: timeout" ));
|
||||
return std::unexpected(QString("CAN response errror: Timeout" ));
|
||||
|
||||
qDebug() << " --- CAN Read Byte: " << (uint32_t) msg.MsgData[3] << " Device:: "<< deviceID << " register: " << registerID;
|
||||
return (uint32_t) msg.MsgData[3];
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
// void BCDriverTinyCan::setValue( unsigned char receipient, unsigned char reg, unsigned char value )
|
||||
TransmitResult BCDriverTinyCan::writeRawByte( uint32_t deviceID, uint8_t registerID, uint8_t value ) const
|
||||
{
|
||||
|
||||
if( _driverState <DriverState::Opened )
|
||||
return std::unexpected(QString("readRawValue error: driver not loaded." ) );
|
||||
|
||||
qDebug() << " --- BCDriverTinyCan writeRawValue: " << value;
|
||||
|
||||
::TCanMsg msg;
|
||||
int timeout_count = cTIMEOUT_COUNT;
|
||||
|
||||
|
||||
msg.MsgFlags = 0L;
|
||||
msg.Id = deviceID;
|
||||
msg.MsgLen = 4;
|
||||
@@ -389,6 +311,6 @@ TransmitResult BCDriverTinyCan::writeRawByte( uint32_t deviceID, uint8_t registe
|
||||
if( timeout_count == -1 )
|
||||
return std::unexpected(QString("error: could not send value to %1" ).arg( deviceID ) );
|
||||
|
||||
return uint32_t(1); // als 'true'
|
||||
return uint32_t(0); // kein Fehler
|
||||
}
|
||||
|
||||
|
||||
248
bcguihelpers.cpp
@@ -1,248 +0,0 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <bcguihelpers.h>
|
||||
|
||||
|
||||
BCThemeSwitchButton::BCThemeSwitchButton(QWidget *parent )
|
||||
: QPushButton(parent)
|
||||
{
|
||||
// Visuelles Setup: Flach, keine Ränder, Hand-Cursor
|
||||
setFlat(true);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
setFixedSize(24, 24); // Kleiner Footprint im StatusBar
|
||||
|
||||
// CSS: Transparent, damit es sich nahtlos in den StatusBar einfügt
|
||||
// Schriftgröße etwas erhöhen, damit die Emojis gut erkennbar sind
|
||||
/*
|
||||
setStyleSheet(R"(
|
||||
QPushButton {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
font-size: 11pt;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(128, 128, 128, 30); // Leichter Hover-Effekt
|
||||
border-radius: 24px;
|
||||
}
|
||||
)");
|
||||
*/
|
||||
// Initialer Status (Startet im Dark Mode -> zeigt Mond)
|
||||
updateIcon();
|
||||
|
||||
connect(this, &QPushButton::clicked, this, &BCThemeSwitchButton::toggle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Setzt den DarkMode
|
||||
*/
|
||||
|
||||
void BCThemeSwitchButton::setDarkMode( bool isDark )
|
||||
{
|
||||
_isDarkMode = !isDark;
|
||||
toggleMode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Schaltet den akutellen Mode um.
|
||||
*/
|
||||
|
||||
void BCThemeSwitchButton::toggleMode()
|
||||
{
|
||||
_isDarkMode = !_isDarkMode;
|
||||
updateIcon();
|
||||
emit themeChanged(_isDarkMode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Icon & Tooltip anpassen
|
||||
*/
|
||||
|
||||
void BCThemeSwitchButton::updateIcon()
|
||||
{
|
||||
// Logik:
|
||||
// Ist Dark Mode an? Zeige Mond (oder Sonne, je nach Geschmack).
|
||||
// Hier: Zeige das Symbol des AKTUELLEN Modus.
|
||||
setText(_isDarkMode ? "🌙" : "☀️");
|
||||
setToolTip(_isDarkMode ? "Zum LightMode wechseln" : "Zum DarkMode wechseln");
|
||||
}
|
||||
|
||||
|
||||
/// -----------------------------------------------------------------------------------
|
||||
/// -----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* @brief Hilfswidget: Zeigt den DriverState als Icon an.
|
||||
*/
|
||||
|
||||
BCDriverStateWidget::BCDriverStateWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(10, 2, 10, 2);
|
||||
//layout->setSpacing(8);
|
||||
|
||||
_led = new QLabel(this);
|
||||
_led->setFixedSize(12, 12);
|
||||
|
||||
layout->addWidget(_led);
|
||||
|
||||
// Startzustand
|
||||
onDriverStateChanged(BCDriver::DriverState::NotPresent, "Not Present");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Hauptfunktion zum Setzen des Status
|
||||
// 'customMessage' ist optional. Wenn leer, wird ein Standardtext genommen.
|
||||
void BCDriverStateWidget::onDriverStateChanged(BCDriver::DriverState state, const QString& customMessage)
|
||||
{
|
||||
_state = state;
|
||||
qDebug() << " --- StateWidget: " << state << " - " << customMessage;
|
||||
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
/*
|
||||
void BCDriverStateWidget::updateStyle()
|
||||
{
|
||||
QString ledStyle;
|
||||
QString labelColor;
|
||||
QString toolTipText;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case BCDriver::DriverState::DeviceReady:
|
||||
// FLUENT GREEN (Success)
|
||||
ledStyle = "background-color: #107C10; border: 1px solid #0E600E;#FF5F1F; #FF8C00;<- das isses #FF6700";
|
||||
labelColor = "#FFFFFF"; // Weiß (Hervorgehoben)
|
||||
toolTipText = "Verbindung erfolgreich hergestellt.";
|
||||
break;
|
||||
|
||||
case BCDriver::DriverState::Error:
|
||||
// FLUENT RED (Critical)
|
||||
ledStyle = "background-color: #C42B1C; border: 1px solid #A80000;";
|
||||
labelColor = "#FF99A4"; // Ein helleres Rot für Text, damit es auf Dunkel lesbar ist
|
||||
toolTipText = "Kritischer Fehler bei der Verbindung!";
|
||||
break;
|
||||
|
||||
default:
|
||||
// FLUENT GRAY (Neutral)
|
||||
// Wir machen es dunkelgrau mit hellem Rand -> "Ausgeschaltet"-Look
|
||||
ledStyle = "background-color: #3B3B3B; border: 1px solid #606060;";
|
||||
labelColor = "#9E9E9E"; // Ausgegrauter Text
|
||||
toolTipText = "System ist offline.";
|
||||
break;
|
||||
}
|
||||
|
||||
// Styles anwenden (immer rund machen)
|
||||
_led->setStyleSheet(ledStyle + "border-radius: 6px;");
|
||||
|
||||
// Textfarbe setzen
|
||||
_label->setStyleSheet(QString("color: %1; font-weight: %2;")
|
||||
.arg(labelColor)
|
||||
.arg(_state == BCDriver::DriverState::DeviceReady ? "bold" : "normal"));
|
||||
|
||||
setToolTip(toolTipText);
|
||||
}
|
||||
*/
|
||||
|
||||
void BCDriverStateWidget::updateStyle()
|
||||
{
|
||||
QString ledStyle;
|
||||
QString toolTipText;
|
||||
/*
|
||||
NotPresent,
|
||||
Error,
|
||||
Loaded,
|
||||
Initialized,
|
||||
Opened, // bis hierher: dll vorhanden, Treiber geladen
|
||||
DeviceReady
|
||||
*/
|
||||
switch (_state)
|
||||
{
|
||||
case BCDriver::DriverState::NotPresent:
|
||||
// FLUENT GRAY (Neutral)
|
||||
// Wir machen es dunkelgrau mit hellem Rand -> "Ausgeschaltet"-Look
|
||||
ledStyle = "background-color: #3B3B3B; border: 1px solid #606060;";
|
||||
toolTipText = "Treiber nicht geladen.";
|
||||
break;
|
||||
|
||||
case BCDriver::DriverState::Error:
|
||||
// FLUENT RED (Critical)
|
||||
ledStyle = "background-color: #C42B1C; border: 1px solid #A80000;";
|
||||
toolTipText = "Fehler beim Laden des Treibers.";
|
||||
break;
|
||||
|
||||
// hier: dll vorhanden, Treiber geladen
|
||||
case BCDriver::DriverState::Loaded:
|
||||
case BCDriver::DriverState::Initialized:
|
||||
case BCDriver::DriverState::Opened:
|
||||
// FLUENT RED (Critical)
|
||||
ledStyle = "background-color: #FF8C00; border: 1px solid #A80000;";
|
||||
toolTipText = "Fehler beim Laden des Treibers.";
|
||||
break;
|
||||
|
||||
case BCDriver::DriverState::DeviceReady:
|
||||
// FLUENT GREEN (Success)
|
||||
ledStyle = "background-color: #107C10; border: 1px solid #0E600E;";
|
||||
toolTipText = "Verbindung erfolgreich hergestellt.";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Styles anwenden (immer rund machen)
|
||||
_led->setStyleSheet(ledStyle + "border-radius: 6px;");
|
||||
|
||||
/*
|
||||
// Textfarbe setzen
|
||||
_setStyleSheet(QString("color: %1; font-weight: %2;")
|
||||
.arg(labelColor)
|
||||
.arg(_state == BCDriver::DriverState::DeviceReady ? "bold" : "normal"));
|
||||
*/
|
||||
setToolTip(toolTipText);
|
||||
}
|
||||
|
||||
void BCDriverStateWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
emit clicked();
|
||||
}
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
|
||||
206
bcmainwindow.cpp
@@ -29,14 +29,16 @@
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "qassert.h"
|
||||
#include <bcthemeswitchbutton.h>
|
||||
#include <bcdriverstatewidget.h>
|
||||
#include <bcmainwindow.h>
|
||||
#include <bcanimateddelegate.h>
|
||||
#include <bcvaluedelegate.h>
|
||||
#include <ui_bcmainwindow.h>
|
||||
#include <bcguihelpers.h>
|
||||
|
||||
/**
|
||||
* @brief Das Mainwindow erzeugen
|
||||
@@ -50,10 +52,12 @@ BCMainWindow::BCMainWindow(QWidget *parent)
|
||||
qRegisterMetaType<BCValue>("BCValue");
|
||||
qRegisterMetaType<QList<BCValue>>("BCValueList");
|
||||
|
||||
setupUi(this);
|
||||
#if defined(Q_OS_LINUX)
|
||||
// Für Touch screen: Window FRam weglassen
|
||||
//setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||
#endif
|
||||
|
||||
// den pimp-my-ride-button schalten wir vorerst aus.
|
||||
_pimpButton->hide();
|
||||
setupUi(this);
|
||||
|
||||
// Wir schreiben den 'initMainWindow()' Aufruf mit Hilfe des
|
||||
// timers in die Event-Queue, damit er erst ausgeführt wird,
|
||||
@@ -83,7 +87,6 @@ BCMainWindow::~BCMainWindow()
|
||||
|
||||
void BCMainWindow::initMainWindow()
|
||||
{
|
||||
|
||||
// Lambda um die buttons mit ihren Actions zu verbinden
|
||||
auto configureAction = [&]( QToolButton* button, QAction* action, BCDevice::ID deviceID )
|
||||
{
|
||||
@@ -91,78 +94,78 @@ void BCMainWindow::initMainWindow()
|
||||
button->setDefaultAction( action);
|
||||
// new way: die DeviceID muss aber explizit vom Lambda eingefanden werden.
|
||||
connect( action, &QAction::triggered, this, [this,deviceID]()
|
||||
{
|
||||
onShowDevicePanel( deviceID );
|
||||
});
|
||||
{
|
||||
onShowDevicePanel( deviceID );
|
||||
});
|
||||
|
||||
if( _devicePanels.contains(deviceID) )
|
||||
{
|
||||
BCDeviceView* currentPanel = _devicePanels[deviceID];
|
||||
// ... und ihre device ID
|
||||
currentPanel->setDeviceID( deviceID );
|
||||
// Wenn ein Device (entspricht einem Datenmodel) fertig eingelesen wurde,
|
||||
// wird es weitergereicht.
|
||||
// Problem: alle Panels bekommen alle Datenmodelle angeboten.
|
||||
connect( &_dataManager, &BCXmlLoader::valueListReady, currentPanel, &BCDeviceView::onValueListReady );
|
||||
}
|
||||
{
|
||||
BCDeviceView* currentPanel = _devicePanels[deviceID];
|
||||
// ... und ihre device ID
|
||||
currentPanel->setDeviceID( deviceID );
|
||||
// Wenn ein Device (entspricht einem Datenmodel) fertig eingelesen wurde,
|
||||
// wird es weitergereicht.
|
||||
// Problem: alle Panels bekommen alle Datenmodelle angeboten.
|
||||
connect( &_dataManager, &BCXmlLoader::valueListReady, currentPanel, &BCDeviceView::onValueListReady );
|
||||
|
||||
connect( currentPanel->model(), SIGNAL(makeSimonHappy()), this, SLOT(onStartAnimation() ) );
|
||||
}
|
||||
};
|
||||
|
||||
// Wir wollen die Devices den Views zuordnen können
|
||||
_devicePanels[BCDevice::ID::Console] = _consolePanel;
|
||||
_devicePanels[BCDevice::ID::Battery] = _batteryPanel;
|
||||
_devicePanels[BCDevice::ID::Motor] = _motorPanel;
|
||||
//_devicePanels[BCDevice::ID::Pimp] = _pimpPanel;
|
||||
|
||||
// Die actions an die Buttons binden
|
||||
// Die actions an die Buttons binden
|
||||
configureAction(_motorButton, _motorAction, BCDevice::ID::Motor );
|
||||
configureAction(_consoleButton, _consoleAction, BCDevice::ID::Console );
|
||||
configureAction(_batteryButton, _batteryAction, BCDevice::ID::Battery );
|
||||
//configureAction(_pimpButton, _pimpAction, BCDevice::ID::Pimp );
|
||||
|
||||
|
||||
/*
|
||||
bool m_isDarkMode = false;
|
||||
QString icon = m_isDarkMode ? "☀️" : "🌙";
|
||||
fitzeButton->setText(icon);
|
||||
|
||||
QString style = QString(
|
||||
"QPushButton {"
|
||||
" background-color: %1;"
|
||||
" border: 1px solid %2;"
|
||||
" border-radius: 6px;"
|
||||
" font-size: 12pt;"
|
||||
" padding: 0px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
" background-color: %3;"
|
||||
"}"
|
||||
).arg(m_isDarkMode ? "#2B2B2B" : "#FFFFFF")
|
||||
.arg(m_isDarkMode ? "#3F3F3F" : "#E1DFDD")
|
||||
.arg(m_isDarkMode ? "#3A3A3A" : "#F9F9F9");
|
||||
|
||||
fitzeButton->setStyleSheet(style);
|
||||
*/
|
||||
|
||||
initStatusBar();
|
||||
|
||||
// besser: model::emit dataChanged
|
||||
// also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole});
|
||||
connect( _connectButton, &QToolButton::clicked, &_transmitter, &BCTransmitter::onToggleDriverConnection );
|
||||
connect( _syncButton, &QToolButton::clicked, this, &BCMainWindow::onSyncDeviceView );
|
||||
connect( &_transmitter, &BCTransmitter::valueUpdated, this, &BCMainWindow::onValueUpdated );
|
||||
_connectButton->setDefaultAction( _connectAction);
|
||||
_syncButton->setDefaultAction( _syncAction);
|
||||
|
||||
connect(this, &BCMainWindow::requestValueUpdate, &_transmitter, &BCTransmitter::onEnqueueValue);
|
||||
connect(&_worker, &QThread::finished, &_transmitter, &QObject::deleteLater);
|
||||
connect( _connectAction, &QAction::triggered, &_transmitter, &BCTransmitter::onToggleDriverConnection );
|
||||
connect( _syncAction, &QAction::triggered, this, &BCMainWindow::onSyncDeviceView );
|
||||
connect( _exitButton, &QToolButton::clicked, qApp, &QCoreApplication::quit );
|
||||
|
||||
connect( &_transmitter, &BCTransmitter::valueUpdated, this, &BCMainWindow::onValueUpdated );
|
||||
connect( this, &BCMainWindow::requestValueUpdate, &_transmitter, &BCTransmitter::onUpdateValue);
|
||||
connect( &_worker, &QThread::finished, &_transmitter, &QObject::deleteLater);
|
||||
connect( &_transmitter, &BCTransmitter::driverStateChanged, this, &BCMainWindow::onDriverStateChanged );
|
||||
connect( &_transmitter, &BCTransmitter::endOfProcessing, this, &BCMainWindow::onEndOfProcessing );
|
||||
connect( this, &BCMainWindow::endOfTransmission, &_transmitter, &BCTransmitter::onEndOfTransmission );
|
||||
|
||||
// transmitter starten
|
||||
_transmitter.moveToThread(&_worker);
|
||||
_worker.start();
|
||||
|
||||
// die Daten des eBikes laden
|
||||
_dataManager.loadXmlBikeData(":/bikeinfo.xml"_L1);
|
||||
//_consoleAction->trigger();
|
||||
_batteryAction->trigger();
|
||||
try
|
||||
{
|
||||
// die Daten des eBikes laden
|
||||
_dataManager.loadXmlBikeData(":/bikeinfo.xml"_L1);
|
||||
}
|
||||
catch( BCException& exception )
|
||||
{
|
||||
QMessageBox::critical( this, "Ladefehler", exception.what() );
|
||||
}
|
||||
|
||||
// Konsolendaten als erstes anzeigen
|
||||
_consoleAction->trigger();
|
||||
//_batteryAction->trigger();
|
||||
|
||||
/*
|
||||
// Dummy sync beim starten
|
||||
QTimer::singleShot(1000, this, [this]()
|
||||
{
|
||||
onSyncDeviceView();
|
||||
});
|
||||
*/
|
||||
|
||||
// not least
|
||||
_delightWidget = new BCDelightPMWidget(this);
|
||||
|
||||
}
|
||||
|
||||
@@ -178,28 +181,31 @@ connectIcon.addFile(":/icons/plug_connected.svg", QSize(), QIcon::Normal, QIc
|
||||
|
||||
void BCMainWindow::initStatusBar()
|
||||
{
|
||||
QStatusBar *statBar = statusBar();
|
||||
|
||||
BCDriverStateWidget* conState = new BCDriverStateWidget(this);
|
||||
connect( &_transmitter, &BCTransmitter::driverStateChanged, conState, &BCDriverStateWidget::onDriverStateChanged );
|
||||
connect( conState, &BCDriverStateWidget::clicked, _connectAction, &QAction::trigger );
|
||||
|
||||
statBar->addPermanentWidget(conState);
|
||||
_statusBar->addPermanentWidget(conState);
|
||||
conState->installEventFilter(this);
|
||||
|
||||
BCThemeSwitchButton* themeBtn = new BCThemeSwitchButton(this);
|
||||
statBar->addPermanentWidget(themeBtn);
|
||||
_statusBar->addPermanentWidget(themeBtn);
|
||||
connect(themeBtn, &BCThemeSwitchButton::themeChanged, this, [this](bool isDark)
|
||||
{
|
||||
QString message = isDark ? "Dark Mode Activated" : "Light Mode Activated";
|
||||
statusBar()->showMessage( message, 3000);
|
||||
setApplicationStyleSheet( isDark ? ":/claude_dark_mode.qss"_L1 : ":/claude_light_mode.qss"_L1 );
|
||||
QString message = isDark ? "using DarkMode." : "using LightMode.";
|
||||
onShowMessage( message );
|
||||
setApplicationStyleSheet( isDark ? cDarkModeStyle : cLightModeStyle );
|
||||
|
||||
});
|
||||
|
||||
// Wir starten im light mode
|
||||
//themeBtn->setDarkMode( false );
|
||||
|
||||
statBar->showMessage("Ready");
|
||||
onShowMessage("Ready. (Using dummy driver)");
|
||||
|
||||
setApplicationStyleSheet(cLightModeStyle);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -233,6 +239,7 @@ bool BCMainWindow::setApplicationStyleSheet( QAnyStringView path )
|
||||
return false;
|
||||
}
|
||||
qWarning() << "Konnte Stylesheet nicht laden:" << styleFile.errorString();
|
||||
//qApp->setStyleSheet(" ");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -247,59 +254,73 @@ void BCMainWindow::setHeaderLabel( const QString& headerText)
|
||||
_headerLabel->setText( " BionxControl: " + headerText );
|
||||
}
|
||||
|
||||
|
||||
void BCMainWindow::onShowMessage( const QString& message, int timeOut )
|
||||
{
|
||||
_statusbar->showMessage( message, timeOut );
|
||||
_statusBar->showMessage( message, timeOut );
|
||||
}
|
||||
|
||||
void BCMainWindow::autoConnect()
|
||||
|
||||
void BCMainWindow::onStartAnimation()
|
||||
{
|
||||
// __fix!
|
||||
// if( !connect)
|
||||
// fallBack
|
||||
_delightWidget->onStartChaos();
|
||||
}
|
||||
|
||||
|
||||
void BCMainWindow::onDriverStateChanged( BCDriver::DriverState state, const QString& message )
|
||||
{
|
||||
qDebug() << " --- on DriverStatusChanged: " << state << ":" << message;
|
||||
_statusbar->showMessage( message, 8000 );
|
||||
Q_UNUSED(state)
|
||||
onShowMessage( message, 8000 );
|
||||
}
|
||||
|
||||
void BCMainWindow::onShowDevicePanel( BCDevice::ID deviceID )
|
||||
{
|
||||
qDebug() << " --- onShowDevicePanel:" << deviceID;
|
||||
if( _devicePanels.contains( deviceID ) )
|
||||
{
|
||||
BCDeviceView* nxtPanel = _devicePanels[deviceID];
|
||||
if( nxtPanel != _currentPanel )
|
||||
{
|
||||
_currentPanel = nxtPanel;
|
||||
qDebug() << " --- Firz: " << _currentPanel->property( BCKeyHeaderLabel );
|
||||
setHeaderLabel( _currentPanel->property( BCKeyHeaderLabel ).toString() );
|
||||
_stackedWidget->setCurrentWidget( nxtPanel );
|
||||
|
||||
setHeaderLabel( _currentPanel->property( cBCKeyHeaderLabel ).toString() );
|
||||
_stackedWidget->setCurrentWidget( _currentPanel );
|
||||
if( _currentPanel->firstExpose() )
|
||||
{
|
||||
// Dummy sync beim starten
|
||||
QTimer::singleShot(1000, this, [this]()
|
||||
{
|
||||
onSyncDeviceView();
|
||||
});
|
||||
}
|
||||
// knopf auch abschalten?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BCMainWindow::onConnectButtonToggled(bool checked )
|
||||
{
|
||||
//_dataManager.setDriverConnectionState( checked );
|
||||
}
|
||||
/**
|
||||
* @brief SLOT, wird aufgerufen, wenn der Treiber eine frischen Wert abgeholt hat.
|
||||
*/
|
||||
|
||||
void BCMainWindow::onValueUpdated(BCDevice::ID deviceID, int index, BCValue::State state, const QString& newValue )
|
||||
void BCMainWindow::onValueUpdated(BCDevice::ID deviceID, int index, BCValue::Flags newState, uint32_t rawValue )
|
||||
{
|
||||
qDebug() << "Reply: from: " << deviceID << " at: " << index << "finished. Success:" << (uint8_t)state << " on:" << newValue;
|
||||
if( _devicePanels.contains( deviceID ) )
|
||||
{
|
||||
BCDeviceView& panel = *_devicePanels[deviceID];
|
||||
panel.onValueUpdated( index, state, newValue );
|
||||
panel.updateValue( index, newState, rawValue );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief SLOT, wird aufgerufen, wenn der Treiber die Datenübertrgeung beendet hat.
|
||||
*/
|
||||
|
||||
void BCMainWindow::onEndOfProcessing()
|
||||
{
|
||||
_syncButton->setEnabled( true );
|
||||
onShowMessage( "Synchronization complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SLOT, der aufgerufen wird, um das akutelle Device (Battery, Motor, ... )
|
||||
* zu synchronisieren, d.h. die aktuellen Werte über den CAN-Bus abzufragen.
|
||||
@@ -307,27 +328,28 @@ void BCMainWindow::onValueUpdated(BCDevice::ID deviceID, int index, BCValue::Sta
|
||||
|
||||
void BCMainWindow::onSyncDeviceView()
|
||||
{
|
||||
|
||||
Q_ASSERT_X(_currentPanel, "onSyncDeviceView()", "_currentpanel ist null!");
|
||||
const BCValueList& currentList =_currentPanel->getValueList();
|
||||
|
||||
qDebug() << " ---Syncing";
|
||||
// wir schalten den Sync-Button hier ab,
|
||||
// wenn der Autrag bearbeitet wurde, wird der
|
||||
// Button wieder eingeschaltet.
|
||||
_syncButton->setEnabled( false );
|
||||
|
||||
const BCValueList& currentList =_currentPanel->getValueListX();
|
||||
|
||||
// alle einzeln? echt jetzt?
|
||||
QString devName = _currentPanel->property( cBCKeyHeaderLabel ).toString();
|
||||
onShowMessage( "Reading: " + devName );
|
||||
|
||||
for( const BCValuePtr& value : currentList )
|
||||
{
|
||||
qDebug() << " --- begin sync of value: " << QThread::currentThreadId() << " : " << value->label;
|
||||
// wir setzen auf 'lesen'
|
||||
value->state.setFlag( BCValue::State::ReadMe );
|
||||
value->setFlag( BCValue::Flag::ReadMe );
|
||||
|
||||
// statt '_transmitter.onEnqueueValue( value )' müssen wir hier
|
||||
// statt '_transmitter.onUpdateValue( value )' müssen wir hier
|
||||
// über emit requestValueUpdate() zur Thread sysnchronisation
|
||||
// entkoppeln,
|
||||
|
||||
emit requestValueUpdate( value);
|
||||
|
||||
}
|
||||
|
||||
emit endOfTransmission();
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <ui_bcmainwindow.h>
|
||||
#include <bcxmlloader.h>
|
||||
#include <bctransmitter.h>
|
||||
#include <bcdelightpmwidget.h>
|
||||
|
||||
class BCDeviceView;
|
||||
|
||||
@@ -57,26 +58,27 @@ public slots:
|
||||
|
||||
//void onValueListReady( BCDevice::ID deviceID );
|
||||
void onShowDevicePanel( BCDevice::ID deviceID );
|
||||
void onConnectButtonToggled(bool active );
|
||||
void onDriverStateChanged( BCDriver::DriverState state, const QString& message="" );
|
||||
|
||||
// Slots für Rückmeldungen vom Transmitter
|
||||
void onValueUpdated( BCDevice::ID deviceID, int index, BCValue::State state, const QString& newValue="" );
|
||||
void onValueUpdated( BCDevice::ID deviceID, int index, BCValue::Flags newState, uint32_t rawValue );
|
||||
void onEndOfProcessing();
|
||||
void onSyncDeviceView();
|
||||
|
||||
void onShowMessage( const QString& message, int timeOut=3000);
|
||||
void onShowMessage( const QString& message, int timeOut=4000);
|
||||
void onStartAnimation();
|
||||
|
||||
signals:
|
||||
|
||||
// Internes Signal, um Daten an den Worker Thread zu senden
|
||||
void requestValueUpdate( BCValuePtrConst value);
|
||||
void endOfTransmission();
|
||||
|
||||
protected:
|
||||
|
||||
bool setApplicationStyleSheet( QAnyStringView path );
|
||||
void initMainWindow();
|
||||
void initStatusBar();
|
||||
void autoConnect();
|
||||
|
||||
//bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
@@ -86,13 +88,15 @@ protected:
|
||||
// und dem Device, das sie darstellen.
|
||||
|
||||
using BCDeviceViews = QHash<BCDevice::ID, BCDeviceView*>;
|
||||
BCDeviceViews _devicePanels;
|
||||
BCDeviceView* _currentPanel{};
|
||||
BCDeviceViews _devicePanels;
|
||||
BCDeviceView* _currentPanel{};
|
||||
BCDelightPMWidget* _delightWidget{};
|
||||
QThread _worker;
|
||||
BCTransmitter _transmitter;
|
||||
|
||||
QThread _worker;
|
||||
BCTransmitter _transmitter;
|
||||
|
||||
static constexpr const char* BCKeyHeaderLabel = "BCHeaderLabel";
|
||||
static constexpr const char* cBCKeyHeaderLabel = "BCHeaderLabel";
|
||||
static constexpr const char* cDarkModeStyle = ":bc_dark.qss";
|
||||
static constexpr const char* cLightModeStyle = ":bc_light.qss";
|
||||
|
||||
};
|
||||
|
||||
|
||||
203
bcmainwindow.ui
@@ -71,9 +71,15 @@
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">_buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
@@ -93,9 +99,15 @@
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">_buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
@@ -115,31 +127,18 @@
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QToolButton" name="_pimpButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">_buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -157,17 +156,73 @@
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QToolButton" name="_syncButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sync</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QToolButton" name="_connectButton">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QToolButton" name="_exitButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Quit application.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="bionxcontrol.qrc">
|
||||
<normaloff>:/exit_red.png</normaloff>:/exit_red.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -190,7 +245,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="BCDeviceView" name="_consolePanel">
|
||||
<property name="frameShape">
|
||||
@@ -279,62 +334,17 @@
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="BCDeviceView" name="_pimpPanel">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::PenStyle::NoPen</enum>
|
||||
</property>
|
||||
<property name="BCHeaderLabel" stdset="0">
|
||||
<string>Pimp my Ride ...</string>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="_statusbar">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: #DADADA</string>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="_pimpAction">
|
||||
<widget class="QStatusBar" name="_statusBar"/>
|
||||
<action name="_motorAction">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:restart.png</normaloff>:restart.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>pimp</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Pimp my Ride</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_motorAction">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:bionx_motor.png</normaloff>:bionx_motor.png</iconset>
|
||||
@@ -343,10 +353,13 @@
|
||||
<string>motor</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show motor settings</string>
|
||||
<string>Show and edit motor settings.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_batteryAction">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:bionx_akku.png</normaloff>:bionx_akku.png</iconset>
|
||||
@@ -355,10 +368,13 @@
|
||||
<string>battery</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show battery settings</string>
|
||||
<string>Show and edit battery settings.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_consoleAction">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:bionx_console.png</normaloff>:bionx_console.png</iconset>
|
||||
@@ -367,31 +383,37 @@
|
||||
<string>console</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show console settings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_exitAction">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:exit.png</normaloff>:exit.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Exit</string>
|
||||
<string>Show and edit console settings.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_connectAction">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="bionxcontrol.qrc">
|
||||
<normaloff>:/connected.png</normaloff>:/connected.png</iconset>
|
||||
<normaloff>:/connect.png</normaloff>:/connect.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>connect</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>connect to bike</string>
|
||||
<string>Load TinyCAN native driver.</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::TextHeuristicRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_syncAction">
|
||||
<property name="icon">
|
||||
<iconset resource="bionxcontrol.qrc">
|
||||
<normaloff>:/sync.png</normaloff>:/sync.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>sync</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Synchronise with eBike settings.</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::TextHeuristicRole</enum>
|
||||
@@ -409,4 +431,7 @@
|
||||
<include location="bionxcontrol.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="_buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
||||
199
bcsliderstyle.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <bcsliderstyle.h>
|
||||
#include <bcvalueeditor.h>
|
||||
|
||||
|
||||
BCSliderStyle::BCSliderStyle()
|
||||
: QProxyStyle()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int BCSliderStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget ) const
|
||||
{
|
||||
switch (metric)
|
||||
{
|
||||
case PM_SliderThickness:
|
||||
return 24; // Höhe für horizontalen Slider
|
||||
case PM_SliderLength:
|
||||
return 16; // Handle-Größe
|
||||
case PM_SliderControlThickness:
|
||||
return 16;
|
||||
case PM_SliderSpaceAvailable:
|
||||
if (option)
|
||||
{
|
||||
if (const QStyleOptionSlider* sliderOpt = qstyleoption_cast<const QStyleOptionSlider*>(option))
|
||||
{
|
||||
return sliderOpt->rect.width() - 20;
|
||||
}
|
||||
}
|
||||
return QProxyStyle::pixelMetric(metric, option, widget);
|
||||
|
||||
default:
|
||||
return QProxyStyle::pixelMetric(metric, option, widget);
|
||||
}
|
||||
}
|
||||
|
||||
QRect BCSliderStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex* opt,SubControl sc, const QWidget* widget) const
|
||||
{
|
||||
if (cc == CC_Slider) {
|
||||
if (const QStyleOptionSlider* slider = qstyleoption_cast<const QStyleOptionSlider*>(opt))
|
||||
{
|
||||
QRect rect = slider->rect;
|
||||
int handleSize = 16;
|
||||
|
||||
if (sc == SC_SliderHandle)
|
||||
{
|
||||
// Handle Position korrekt berechnen
|
||||
if (slider->orientation == Qt::Horizontal)
|
||||
{
|
||||
int range = slider->maximum - slider->minimum;
|
||||
int pos = slider->sliderPosition - slider->minimum;
|
||||
int pixelRange = rect.width() - handleSize;
|
||||
int pixelPos = (range != 0) ? (pos * pixelRange) / range : 0;
|
||||
|
||||
return QRect(rect.x() + pixelPos,
|
||||
rect.center().y() - handleSize / 2,
|
||||
handleSize, handleSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
int range = slider->maximum - slider->minimum;
|
||||
int pos = slider->sliderPosition - slider->minimum;
|
||||
int pixelRange = rect.height() - handleSize;
|
||||
int pixelPos = (range != 0) ? (pos * pixelRange) / range : 0;
|
||||
|
||||
return QRect(rect.center().x() - handleSize / 2,
|
||||
rect.bottom() - pixelPos - handleSize,
|
||||
handleSize, handleSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QProxyStyle::subControlRect(cc, opt, sc, widget);
|
||||
}
|
||||
|
||||
void BCSliderStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
|
||||
{
|
||||
if (control == CC_Slider)
|
||||
{
|
||||
if (const QStyleOptionSlider* slider = qstyleoption_cast<const QStyleOptionSlider*>(option)) {
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// Fluent Colors
|
||||
QColor accentColor(0, 120, 212); // #0078D4
|
||||
QColor inactiveColor(138, 136, 134); // #8A8886
|
||||
QColor bgColor(255, 255, 255); // White background
|
||||
//QColor disabledText = option.palette.color(QPalette::Disabled, QPalette::Text);
|
||||
//painter->setBrush(disabledText);
|
||||
//QColor bgColor = Qt::green;//option->palette.color(QPalette::Base);
|
||||
drawHorizontalFluentSlider(painter, slider, accentColor, inactiveColor, bgColor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
QProxyStyle::drawComplexControl(control, option, painter, widget);
|
||||
}
|
||||
|
||||
|
||||
void BCSliderStyle::drawHorizontalFluentSlider(QPainter* painter, const QStyleOptionSlider* slider,
|
||||
const QColor& activeColor, const QColor& inactiveColor,
|
||||
const QColor& bgColor) const
|
||||
{
|
||||
QRect groove = slider->rect;
|
||||
QRect handle = subControlRect(CC_Slider, slider, SC_SliderHandle, nullptr);
|
||||
|
||||
qDebug() << " ---WTF: " << groove;
|
||||
|
||||
|
||||
BCValueEditor::paintSliderIndicator(painter, groove, 0.5 );
|
||||
/*
|
||||
int grooveHeight = 4;
|
||||
// Track sollte im Widget-Zentrum sein, nicht im groove-Zentrum
|
||||
int grooveY = groove.center().y() - grooveHeight / 2;
|
||||
|
||||
// Full background track
|
||||
QRect fullTrack(groove.left(), grooveY, groove.width(), grooveHeight);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(inactiveColor.lighter(150));
|
||||
painter->drawRoundedRect(fullTrack, grooveHeight / 2, grooveHeight / 2);
|
||||
|
||||
QRect handle = subControlRect(CC_Slider, slider, SC_SliderHandle, nullptr);
|
||||
|
||||
// Active track (filled portion)
|
||||
int activeWidth = handle.center().x() - groove.left();
|
||||
QRect activeTrack(groove.left(), grooveY, activeWidth, grooveHeight);
|
||||
painter->setBrush(activeColor);
|
||||
painter->drawRoundedRect(activeTrack, grooveHeight / 2, grooveHeight / 2);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
// Handle (Thumb) - Fluent style is more subtle
|
||||
int handleSize = 16;
|
||||
QRect thumbRect(handle.center().x() - handleSize / 2,
|
||||
handle.center().y() - handleSize / 2,
|
||||
handleSize, handleSize);
|
||||
|
||||
// Hover effect - subtle glow
|
||||
if (slider->state & State_MouseOver)
|
||||
{
|
||||
painter->setBrush(QColor(activeColor.red(), activeColor.green(),
|
||||
activeColor.blue(), 30));
|
||||
int glowSize = 18;
|
||||
QRect glow(handle.center().x() - glowSize / 2,
|
||||
handle.center().y() - glowSize / 2,
|
||||
glowSize, glowSize);
|
||||
painter->drawEllipse(glow);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Thumb
|
||||
painter->setBrush(bgColor);
|
||||
painter->setPen(QPen(activeColor, 2));
|
||||
painter->drawEllipse(thumbRect);
|
||||
|
||||
// Inner circle for pressed state
|
||||
if (slider->state & State_Sunken) {
|
||||
int innerSize = 6;
|
||||
QRect inner(handle.center().x() - innerSize / 2,
|
||||
handle.center().y() - innerSize / 2,
|
||||
innerSize, innerSize);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(activeColor);
|
||||
painter->drawEllipse(inner);
|
||||
}
|
||||
}
|
||||
|
||||
84
bcsliderstyle.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef BCSLIDERSTYLE_H
|
||||
#define BCSLIDERSTYLE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
#include <QTableView>
|
||||
#include <QStandardItemModel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHeaderView>
|
||||
|
||||
#include <QSlider>
|
||||
#include <QPainter>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
#include <QPushButton>
|
||||
#include <QLineEdit>
|
||||
#include <QSlider>
|
||||
#include <QCheckBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QProxyStyle>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionSlider>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
|
||||
// Fluent Design Slider Style
|
||||
class BCSliderStyle : public QProxyStyle
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
BCSliderStyle();
|
||||
|
||||
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
|
||||
|
||||
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget) const override;
|
||||
void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const override;
|
||||
void drawHorizontalFluentSlider(QPainter* painter,
|
||||
const QStyleOptionSlider* slider,
|
||||
const QColor& activeColor,
|
||||
const QColor& inactiveColor,
|
||||
const QColor& bgColor) const;
|
||||
|
||||
static void paintSliderIndicator(QPainter* painter, const QRect& rect, double ratio );
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // BCSLIDERSTYLE_H
|
||||
49
bcthemeswitchbutton.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <bcthemeswitchbutton.h>
|
||||
|
||||
|
||||
|
||||
BCThemeSwitchButton::BCThemeSwitchButton(QWidget *parent )
|
||||
: QPushButton(parent)
|
||||
{
|
||||
// Visuelles Setup: Flach, keine Ränder, Hand-Cursor
|
||||
setFlat(true);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
setFixedSize(24, 24);
|
||||
updateIcon();
|
||||
|
||||
connect(this, &QPushButton::clicked, this, &BCThemeSwitchButton::toggleMode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Setzt den DarkMode
|
||||
*/
|
||||
|
||||
void BCThemeSwitchButton::setDarkMode( bool isDark )
|
||||
{
|
||||
_isDarkMode = !isDark;
|
||||
toggleMode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Schaltet den akutellen Mode um.
|
||||
*/
|
||||
|
||||
void BCThemeSwitchButton::toggleMode()
|
||||
{
|
||||
_isDarkMode = !_isDarkMode;
|
||||
updateIcon();
|
||||
emit themeChanged(_isDarkMode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Icon & Tooltip anpassen
|
||||
*/
|
||||
|
||||
void BCThemeSwitchButton::updateIcon()
|
||||
{
|
||||
setText(_isDarkMode ? "🌙" : "☀️");
|
||||
setToolTip(_isDarkMode ? "Use LightMode" : "Use DarkMode");
|
||||
}
|
||||
72
bcthemeswitchbutton.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef BCTHEMESWITCHBUTTON_H
|
||||
#define BCTHEMESWITCHBUTTON_H
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include <bcdriver.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Einfaches Buttonwidget, um zwischen Dark- und Lightmode
|
||||
* zu wechseln
|
||||
*/
|
||||
|
||||
class BCThemeSwitchButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit BCThemeSwitchButton(QWidget *parent = nullptr);
|
||||
void setDarkMode( bool isDark );
|
||||
|
||||
signals:
|
||||
|
||||
void themeChanged(bool isDark);
|
||||
|
||||
private slots:
|
||||
|
||||
void toggleMode();
|
||||
|
||||
private:
|
||||
|
||||
void updateIcon();
|
||||
|
||||
bool _isDarkMode{false};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // BCTHEMESWITCHBUTTON_H
|
||||
125
bctoggleswitch.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
#include "bctoggleswitch.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QEasingCurve>
|
||||
#include <QEnterEvent>
|
||||
#include <QEvent>
|
||||
|
||||
BCToggleSwitch::BCToggleSwitch(QWidget *parent)
|
||||
: QAbstractButton(parent)
|
||||
, m_position(0.0f)
|
||||
{
|
||||
setCheckable(true);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
setFixedSize(44, 22); // Standardgröße
|
||||
|
||||
// Animation initialisieren
|
||||
m_animation = new QPropertyAnimation(this, "position", this);
|
||||
m_animation->setDuration(200);
|
||||
m_animation->setEasingCurve(QEasingCurve::OutQuad);
|
||||
|
||||
// Signal verknüpfen
|
||||
connect(this, &QAbstractButton::toggled, this, [this](bool checked){
|
||||
m_animation->stop();
|
||||
m_animation->setStartValue(m_position);
|
||||
m_animation->setEndValue(checked ? 1.0f : 0.0f);
|
||||
m_animation->start();
|
||||
});
|
||||
}
|
||||
|
||||
float BCToggleSwitch::position() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
void BCToggleSwitch::setPosition(float pos)
|
||||
{
|
||||
m_position = pos;
|
||||
update(); // Trigger Repaint
|
||||
}
|
||||
|
||||
QSize BCToggleSwitch::sizeHint() const
|
||||
{
|
||||
return QSize(44, 22);
|
||||
}
|
||||
|
||||
void BCToggleSwitch::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// --- Farben ---
|
||||
// Tipp: In einem echten Projekt diese Farben als const statics
|
||||
// oder aus der QPalette laden.
|
||||
QColor offBorderColor = QColor(0x8D8D8D);
|
||||
QColor offKnobColor = QColor(0x5D5D5D);
|
||||
QColor onColor = QColor(0x0078D4); // Fluent Blue
|
||||
QColor white = Qt::white;
|
||||
|
||||
QRectF rect = this->rect();
|
||||
qreal radius = rect.height() / 2.0;
|
||||
|
||||
// 1. Hintergrund (Track) zeichnen
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
if (isChecked() || m_position > 0.5f)
|
||||
{
|
||||
// AN-Zustand: Hintergrund gefüllt
|
||||
p.setBrush(onColor);
|
||||
p.drawRoundedRect(rect, radius, radius);
|
||||
}
|
||||
else
|
||||
{
|
||||
// AUS-Zustand: Nur Rahmen
|
||||
p.setBrush(Qt::NoBrush);
|
||||
|
||||
// Hover-Status prüfen
|
||||
if (underMouse())
|
||||
p.setPen(QPen(offBorderColor.darker(120), 1.5));
|
||||
else
|
||||
p.setPen(QPen(offBorderColor, 1.5));
|
||||
|
||||
// Rechteck etwas verkleinern, damit der Rahmen nicht abgeschnitten wird
|
||||
p.drawRoundedRect(rect.adjusted(1, 1, -1, -1), radius - 1, radius - 1);
|
||||
}
|
||||
|
||||
// 2. Knopf (Thumb) zeichnen
|
||||
qreal padding = 3.0;
|
||||
qreal knobDiameter = rect.height() - (2 * padding);
|
||||
|
||||
// Interpolation der Position
|
||||
qreal startX = padding;
|
||||
qreal endX = rect.width() - knobDiameter - padding;
|
||||
qreal currentX = startX + (m_position * (endX - startX));
|
||||
|
||||
QRectF knobRect(currentX, padding, knobDiameter, knobDiameter);
|
||||
|
||||
if (isChecked() || m_position > 0.5f)
|
||||
{
|
||||
p.setBrush(white);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (underMouse())
|
||||
p.setBrush(offKnobColor.darker(110));
|
||||
else
|
||||
p.setBrush(offKnobColor);
|
||||
}
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawEllipse(knobRect);
|
||||
}
|
||||
|
||||
void BCToggleSwitch::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
update(); // Für Hover-Effekt neu zeichnen
|
||||
QAbstractButton::enterEvent(event);
|
||||
}
|
||||
|
||||
void BCToggleSwitch::leaveEvent(QEvent *event)
|
||||
{
|
||||
update(); // Hover entfernen
|
||||
QAbstractButton::leaveEvent(event);
|
||||
}
|
||||
38
bctoggleswitch.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef BCTOGGLESWITCH_H
|
||||
#define BCTOGGLESWITCH_H
|
||||
|
||||
#include <QAbstractButton>
|
||||
|
||||
|
||||
// Vorwärtsdeklaration spart Include-Zeit
|
||||
class QPropertyAnimation;
|
||||
|
||||
class BCToggleSwitch : public QAbstractButton
|
||||
{
|
||||
Q_OBJECT
|
||||
// Property für die Animation (0.0 bis 1.0)
|
||||
Q_PROPERTY(float position READ position WRITE setPosition)
|
||||
|
||||
public:
|
||||
|
||||
explicit BCToggleSwitch(QWidget *parent = nullptr);
|
||||
|
||||
// Getter & Setter für die Animations-Property
|
||||
float position() const;
|
||||
void setPosition(float pos);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
|
||||
float m_position; // 0.0 = Aus, 1.0 = An
|
||||
QPropertyAnimation* m_animation;
|
||||
};
|
||||
|
||||
#endif // BCTOGGLESWITCH_H
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <bctransmitter.h>
|
||||
|
||||
@@ -40,7 +41,7 @@
|
||||
*/
|
||||
|
||||
BCTransmitter::BCTransmitter(QObject *parent)
|
||||
: QObject(parent), _isBusy(false)
|
||||
: QObject(parent)//, _isBusy(false)
|
||||
{
|
||||
//_canDriver = new BCDriverTinyCan{this};
|
||||
_canDriver = &_dummyDriver;
|
||||
@@ -55,27 +56,23 @@ BCTransmitter::BCTransmitter(QObject *parent)
|
||||
|
||||
void BCTransmitter::onToggleDriverConnection( bool connect )
|
||||
{
|
||||
qDebug() << " --- onToggleDriverConnection: " << connect;
|
||||
// FIX! Ende der current op abwarten!
|
||||
if( connect )
|
||||
emit driverStateChanged(BCDriver::DriverState::NotPresent, "Native Treiber wird geladen.");
|
||||
|
||||
/*
|
||||
// kill all pending stuff
|
||||
//QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
|
||||
BCDriver::DriverState state = connect ? BCDriver::DriverState::DeviceReady : BCDriver::DriverState::NotPresent;
|
||||
const QString& message = connect ? "Trying to connect" : " FAILED";
|
||||
emit driverStateChanged(state, message);
|
||||
return;
|
||||
*/
|
||||
|
||||
// Hier sind wir noch in GUI Thread
|
||||
QMutexLocker locker(&_mutex);
|
||||
// weitere operation stoppen
|
||||
_isBusy = true;
|
||||
connect ? connectCanDriver() : disconnectCanDriver();
|
||||
_isBusy = false;
|
||||
}
|
||||
|
||||
|
||||
void BCTransmitter::onStartNativeDriver()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void BCTransmitter::connectCanDriver()
|
||||
{
|
||||
// hier gehts nur um den echten Treiber
|
||||
@@ -85,137 +82,111 @@ void BCTransmitter::connectCanDriver()
|
||||
if( _tinyCanDriver.getDriverState() != BCDriver::DriverState::DeviceReady )
|
||||
result = _tinyCanDriver.loadAndStartDriver();
|
||||
|
||||
QString message("FitzeFatze!");
|
||||
// hat geklappt
|
||||
if( _tinyCanDriver.getDriverState() >= BCDriver::DriverState::Opened )
|
||||
{
|
||||
uint32_t console = static_cast<uint32_t>(BCDevice::ID::Console);
|
||||
uint8_t hwRev = static_cast<uint8_t> (BC::ID::Cons_Rev_Hw);
|
||||
|
||||
TransmitResult hwVersion = _tinyCanDriver.readRawByte( console, hwRev);
|
||||
if( hwVersion.has_value() )
|
||||
QString message("Treiber geladen (nicht verbunden)");
|
||||
|
||||
// Der result-Wert im ERfolgsfall ist der driver state.
|
||||
if(result.has_value() )
|
||||
{
|
||||
switch( result.value() )
|
||||
{
|
||||
message = " ---- HAIL to the king!";
|
||||
qDebug() << message;
|
||||
// swap driver
|
||||
_canDriver = &_tinyCanDriver;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Console not responding";
|
||||
case BCDriver::DriverState::Opened:
|
||||
|
||||
message = "Treiber geladen (Device antwortet nicht)";
|
||||
break;
|
||||
|
||||
case BCDriver::DriverState::DeviceReady:
|
||||
|
||||
message = "Treiber geladen und Device verbunden.";
|
||||
// swap driver
|
||||
_canDriver = &_tinyCanDriver;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
else // Fehlerfall, wir holen die Fehlermeldung
|
||||
{
|
||||
message = result.error();
|
||||
}
|
||||
|
||||
emit driverStateChanged( _tinyCanDriver.getDriverState(), message );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Native-Treiber zurücksetzen, Dummy-Treiber wieder aktivieren.
|
||||
*/
|
||||
|
||||
void BCTransmitter::disconnectCanDriver()
|
||||
{
|
||||
_tinyCanDriver.resetDriver();
|
||||
_canDriver = &_dummyDriver;
|
||||
emit driverStateChanged( _tinyCanDriver.getDriverState(), "Disconnected" );
|
||||
emit driverStateChanged( _tinyCanDriver.getDriverState(), "Disconnected, Dummy Treiber aktiviert." );
|
||||
}
|
||||
|
||||
|
||||
void BCTransmitter::onEnqueueValue( BCValuePtrConst value)
|
||||
void BCTransmitter::onUpdateValue( BCValuePtrConst valuePtr)
|
||||
{
|
||||
|
||||
// wir stellen hier auf die arte Tour sicher, das onEnqueueValue
|
||||
// wir stellen hier auf die harte Tour sicher, das onUpdateValue
|
||||
// nicht aus dem Parent-Thread direkt sondern über die EventQueue aufgerufen wurde.
|
||||
|
||||
Q_ASSERT(QThread::currentThread() == this->thread());
|
||||
|
||||
// Hier sind wir noch in GUI Thread
|
||||
//QMutexLocker locker(&_mutex);
|
||||
_valueQueue.enqueue( value );
|
||||
// Wir arbeiten hier ohne besondere Threadsynchronisation, mutexed o.ä: Die
|
||||
// entkoppelung und serialisierung passiert bereits durch die Qt-Eventqueue.
|
||||
// Das klappt aber nur in der hier gewählten Konstellation mit einer Parent-Thread
|
||||
// und einem Worker.
|
||||
|
||||
// wir wollen nicht den ganzen Value verschicken, erstrecht
|
||||
// wollen wir nicht den Value in verschiedenen Threads gleichzeitig
|
||||
// in die Hand nehmen, also hantieren wir nur mit den Inidizes.
|
||||
// Kosmetik
|
||||
const BCValue& value = *(valuePtr.get());
|
||||
|
||||
// Trigger processing im Event-Loop des Worker Threads
|
||||
// invokeMethod mit QueuedConnection entkoppelt den Aufruf,
|
||||
// damit onEnqueueValue sofort zurückkehrt (non-blocking für den Aufrufer).
|
||||
uint32_t devID = static_cast<uint32_t>(value.deviceID());
|
||||
uint8_t regID = static_cast<uint8_t> (value.registerID());
|
||||
|
||||
//QMetaObject::invokeMethod(this, "onProcessValue", Qt::QueuedConnection);
|
||||
onProcessValue();
|
||||
}
|
||||
// Für den Fehlerfall: Wir senden den alten Wert einfach zurück
|
||||
uint32_t newValue = value.rawValue();
|
||||
BCValue::Flag newState = BCValue::Flag::Failed;
|
||||
|
||||
void BCTransmitter::onProcessValue()
|
||||
{
|
||||
|
||||
//if (_isBusy)
|
||||
// return;
|
||||
|
||||
_isBusy = true;
|
||||
|
||||
while (true)
|
||||
if(value.testFlag( BCValue::Flag::WriteMe ) )
|
||||
{
|
||||
BCValuePtrConst valuePtr{};
|
||||
{
|
||||
//QMutexLocker locker(&_mutex);
|
||||
if (_valueQueue.isEmpty())
|
||||
{
|
||||
_isBusy = false;
|
||||
break; // Schleife verlassen, warten auf neue Events
|
||||
}
|
||||
valuePtr =_valueQueue.dequeue();
|
||||
} // Mutex wird hier freigegeben! WICHTIG: Execute ohne Lock!
|
||||
|
||||
// Kosmetik
|
||||
const BCValue& value = *(valuePtr.get());
|
||||
|
||||
qDebug() << "------- DE.-.QUEUE: " << QThread::currentThreadId() << ": " << value.label;
|
||||
|
||||
// Value ist 'under construction'
|
||||
//emit valueUpdated( value.deviceID, value.indexRow, BCValue::State::Locked );
|
||||
|
||||
|
||||
uint32_t devID = static_cast<uint32_t>(value.deviceID);
|
||||
uint8_t regID = static_cast<uint8_t> (value.registerID);
|
||||
|
||||
QString newVisibleValue;
|
||||
BCValue::State newState = BCValue::State::NoState;
|
||||
|
||||
if(value.state.testFlag( BCValue::State::WriteMe ) )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
// oder sollen wir hier beides erlauben ? readFlag & writeFlag ?
|
||||
// Was kommt dann zuerst? Schreiben und lesen als verify ?
|
||||
|
||||
else if( value.state.testFlag( BCValue::State::ReadMe ) )
|
||||
{
|
||||
// wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
|
||||
TransmitResult result = value.isWord ? readWordValue( devID, regID ) : readByteValue( devID, regID );
|
||||
if( result.has_value() )
|
||||
{
|
||||
newVisibleValue = value.formatValue( result.value() );
|
||||
newState = BCValue::State::InSync;
|
||||
}
|
||||
else
|
||||
{
|
||||
newState = BCValue::State::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
emit valueUpdated( value.deviceID, value.indexRow, newState, newVisibleValue );
|
||||
|
||||
// __fix
|
||||
//bc::processEventsFor(150);
|
||||
bc::delay_millis(150);
|
||||
|
||||
}
|
||||
// oder sollen wir hier beides erlauben ? readFlag & writeFlag ?
|
||||
// Was kommt dann zuerst? Schreiben und lesen als verify ?
|
||||
|
||||
else if( value.testFlag( BCValue::Flag::ReadMe ) )
|
||||
{
|
||||
// wir sind hier im anderen thread! nicht einfach so reinschreiben, nur lesen
|
||||
TransmitResult result = value.isWord() ? readWordValue( devID, regID ) : readByteValue( devID, regID );
|
||||
if( result.has_value() )
|
||||
{
|
||||
newState = BCValue::Flag::InSync;
|
||||
newValue = result.value();
|
||||
}
|
||||
}
|
||||
|
||||
emit valueUpdated( value.deviceID(), value.indexRow(), newState, newValue );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wenn dieser SLOT in der Event-Queue erreicht wird, dedeutet dies, das die
|
||||
* Übertrgung vom Mainwindow abgeschlossen wurde. Wir schicken zur Bestätigung das
|
||||
* Signal 'endOfProcessing' (Welches dann den 'Sync' - Button wieder einschaltet.
|
||||
*/
|
||||
|
||||
void BCTransmitter::onEndOfTransmission()
|
||||
{
|
||||
emit endOfProcessing();
|
||||
}
|
||||
|
||||
|
||||
TransmitResult BCTransmitter::readByteValue( uint32_t deviceID, uint8_t registerID )
|
||||
{
|
||||
//qDebug() << " --- YES: Read ByteValue: " << registerID;
|
||||
// Wir lesen nur ein Byte und gut.
|
||||
return _canDriver->readRawByte( deviceID, registerID );
|
||||
}
|
||||
@@ -223,8 +194,6 @@ TransmitResult BCTransmitter::readByteValue( uint32_t deviceID, uint8_t register
|
||||
|
||||
TransmitResult BCTransmitter::readWordValue( uint32_t deviceID, uint8_t registerID )
|
||||
{
|
||||
//qDebug() << " --- YES: Read WordValue: " << registerID;
|
||||
|
||||
uint32_t result{};
|
||||
// hi byte Leseversuch.
|
||||
TransmitResult value = _canDriver->readRawByte( deviceID, registerID );
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QMutex>
|
||||
#include <atomic>
|
||||
|
||||
#include <bcvalue.h>
|
||||
#include <bcdrivertinycan.h>
|
||||
@@ -63,13 +62,13 @@ public:
|
||||
public slots:
|
||||
|
||||
void onToggleDriverConnection( bool connect );
|
||||
void onEnqueueValue(BCValuePtrConst value );
|
||||
void onProcessValue();
|
||||
void onStartNativeDriver();
|
||||
void onUpdateValue(BCValuePtrConst valuePtr );
|
||||
void onEndOfTransmission();
|
||||
|
||||
signals:
|
||||
|
||||
void valueUpdated(BCDevice::ID deviceID, int index, BCValue::State state, const QString& newValue="" );
|
||||
void endOfProcessing();
|
||||
void valueUpdated(BCDevice::ID deviceID, int index, BCValue::Flag state, uint32_t rawValue );
|
||||
void driverStateChanged( BCDriver::DriverState state, const QString& message="" );
|
||||
|
||||
private:
|
||||
@@ -80,13 +79,6 @@ private:
|
||||
TransmitResult readByteValue( uint32_t deviceID, uint8_t registerID );
|
||||
TransmitResult readWordValue( uint32_t deviceID, uint8_t registerID );
|
||||
|
||||
using BCDataQueue = QQueue<BCValuePtrConst>;
|
||||
|
||||
BCDataQueue _valueQueue;
|
||||
QMutex _mutex;
|
||||
std::atomic<bool> _isBusy{ false };
|
||||
|
||||
// __fix!
|
||||
BCDriver* _canDriver{};
|
||||
BCDriverTinyCan _tinyCanDriver{};
|
||||
BCDriverDummy _dummyDriver{};
|
||||
|
||||
235
bcvalue.cpp
@@ -31,6 +31,7 @@
|
||||
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QTextStream>
|
||||
|
||||
#include <bcvalue.h>
|
||||
|
||||
@@ -39,28 +40,242 @@
|
||||
|
||||
|
||||
BCValue::BCValue( BCDevice::ID deviceID_, BC::ID registerID_)
|
||||
: deviceID{deviceID_}, registerID{registerID_}
|
||||
: _deviceID{deviceID_}, _registerID{registerID_}
|
||||
{
|
||||
visibleValue = "--";
|
||||
|
||||
}
|
||||
|
||||
QString BCValue::formatValue( uint32_t value ) const
|
||||
QString BCValue::formatValue() const
|
||||
{
|
||||
if( factor == 1 )
|
||||
return QString::number( value );
|
||||
if( _factor == 1 )
|
||||
return QString::number( _rawValue );
|
||||
|
||||
double result = value * factor;
|
||||
double result =_rawValue * _factor;
|
||||
return QString::number(result, 'f', 2);
|
||||
}
|
||||
|
||||
bool BCValue::isWord() const
|
||||
{
|
||||
return _valueFlags.testFlag(BCValue::Flag::IsWord);
|
||||
}
|
||||
|
||||
bool BCValue::isReadOnly() const
|
||||
{
|
||||
return _valueFlags.testFlag(BCValue::Flag::ReadOnly);
|
||||
}
|
||||
|
||||
bool BCValue::testFlag( BCValue::Flag flag ) const
|
||||
{
|
||||
return _valueFlags.testFlag( flag );
|
||||
}
|
||||
|
||||
|
||||
void BCValue::setFlag( BCValue::Flag flag, bool state) const
|
||||
{
|
||||
_valueFlags.setFlag( flag, state );
|
||||
}
|
||||
|
||||
|
||||
BCDevice::ID BCValue::deviceID() const noexcept
|
||||
{
|
||||
return _deviceID;
|
||||
}
|
||||
|
||||
BC::ID BCValue::registerID() const noexcept
|
||||
{
|
||||
return _registerID;
|
||||
}
|
||||
|
||||
uint32_t BCValue::rawValue() const noexcept
|
||||
{
|
||||
return _rawValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Speichert einen via CAN-Bus gelesenen Wert in
|
||||
* der BCValue Struktur.
|
||||
*/
|
||||
|
||||
void BCValue::setRawValue(uint32_t newRawValue) const
|
||||
{
|
||||
// die per Zufallsgenerator erzeugten Werte des Dummy-Treibers
|
||||
// können beliebigen Unsinn enthalten, also müssen wir sie
|
||||
// auch skalieren.
|
||||
|
||||
if( _valueType == ValueType::Bool )
|
||||
{
|
||||
_rawValue = newRawValue > 0 ? 1 : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
double value = newRawValue * _factor;
|
||||
|
||||
if( _optMin.has_value() && _optMax.has_value() )
|
||||
{
|
||||
|
||||
double min = _optMin.value();
|
||||
double max = _optMax.value();
|
||||
|
||||
value = (int) qBound( min,value, max);
|
||||
}
|
||||
|
||||
_rawValue = value / _factor;
|
||||
}
|
||||
|
||||
|
||||
BCValue::ValueType BCValue::valueType() const noexcept
|
||||
{
|
||||
return _valueType;
|
||||
}
|
||||
|
||||
|
||||
int BCValue::indexRow() const noexcept
|
||||
{
|
||||
return _indexRow;
|
||||
}
|
||||
|
||||
void BCValue::setIndexRow(int newIndexRow)
|
||||
{
|
||||
_indexRow = newIndexRow;
|
||||
}
|
||||
|
||||
QString BCValue::label() const
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
|
||||
QString BCValue::unitLabel() const
|
||||
{
|
||||
return _unitLabel;
|
||||
}
|
||||
|
||||
void BCValue::setFromDouble( double value )
|
||||
{
|
||||
//if( _isReadOnly)
|
||||
switch(_valueType)
|
||||
{
|
||||
|
||||
// wir betrachten plain
|
||||
|
||||
case ValueType::Bool :
|
||||
_rawValue = value > 0 ? 1 : 0;
|
||||
break;
|
||||
|
||||
case ValueType::Plain :
|
||||
case ValueType::Number:
|
||||
case ValueType::Float:
|
||||
|
||||
if( _optMin.has_value() && _optMax.has_value() )
|
||||
{
|
||||
|
||||
double min = _optMin.value();
|
||||
double max = _optMax.value();
|
||||
|
||||
value = qBound( min,value,max);
|
||||
}
|
||||
_rawValue = value / _factor;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
double BCValue::calcMinMaxRatio() const
|
||||
{
|
||||
|
||||
double ratio = 1;
|
||||
|
||||
if( _optMin.has_value() && _optMax.has_value() )
|
||||
{
|
||||
|
||||
double min = _optMin.value();
|
||||
double max = _optMax.value();
|
||||
|
||||
double range = max - min;
|
||||
|
||||
// Safety: Division durch Null verhindern (wenn min == max)
|
||||
if (std::abs(range) < 1e-9)
|
||||
return ratio;
|
||||
|
||||
double value = _rawValue * _factor;
|
||||
// Die eigentliche Formel
|
||||
ratio = ((value - min) / range);
|
||||
}
|
||||
return ratio;
|
||||
}
|
||||
|
||||
|
||||
bool BCValue::valuesForSlider(ValueRange& valueRange) const
|
||||
{
|
||||
valueRange.value = valueRange.min = valueRange.max = 0;
|
||||
|
||||
// min & max sind vorraussetzung für den slider
|
||||
if( !_optMin.has_value() || !_optMax.has_value() )
|
||||
return false;
|
||||
|
||||
// wir erwarten hier, das value zwischen min
|
||||
// und max liegt weil wir das schon bei setRawValue
|
||||
// überprüft haben.
|
||||
|
||||
valueRange.value = _rawValue * _factor;
|
||||
valueRange.min = _optMin.value();
|
||||
valueRange.max = _optMax.value();
|
||||
valueRange.ratio = calcMinMaxRatio();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void BCValue::dumpValue() const
|
||||
{
|
||||
|
||||
qDebug() << "DeviceID: " << deviceID << " Register: " << registerID << " state:" " << state << " << " label: " << label;
|
||||
qDebug() << "visibleValue: " << visibleValue << " min: " << min << " max: " << max << " factor: " << factor << " ValueType: " << (char)valueType << " ";
|
||||
qDebug() << "indexRow: " << indexRow << " isWord: " << isWord;
|
||||
qDebug() << "DeviceID: " << _deviceID << " Register: " << _registerID << " state:" " << state << " << " label: " << _label;
|
||||
qDebug() << "formattedValue: " << formatValue() << " min: " << _optMin << " max: " << _optMax << " factor: " << _factor << " ValueType: " << (char)_valueType << " ";
|
||||
qDebug() << "indexRow: " << _indexRow << " isWord: " << isWord() << " isRO: " << isReadOnly();
|
||||
qDebug();
|
||||
|
||||
}
|
||||
|
||||
/// ----
|
||||
QString BCValue::toString() const
|
||||
{
|
||||
QString result;
|
||||
QTextStream stream(&result);
|
||||
|
||||
stream << *this;
|
||||
|
||||
/*
|
||||
qDebug() << "DeviceID: " << _deviceID << " Register: " << _registerID << " state:" " << state << " << " label: " << _label;
|
||||
qDebug() << "formattedValue: " << formatValue() << " min: " << _optMin << " max: " << _optMax << " factor: " << _factor << " ValueType: " << (char)_valueType << " ";
|
||||
qDebug() << "indexRow: " << _indexRow << " isWord: " << isWord() << " isRO: " << isReadOnly();
|
||||
qDebug();
|
||||
*/
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Generischer Operator für ALLE Q_GADGETs
|
||||
inline QTextStream& operator<<(QTextStream& out, const BCValue& obj)
|
||||
{
|
||||
const QMetaObject* meta = &obj.staticMetaObject;
|
||||
|
||||
out << meta->className() << " { ";
|
||||
|
||||
// Iteriere über alle Properties (Reflection)
|
||||
for (int i = 0; i < meta->propertyCount(); ++i) {
|
||||
QMetaProperty prop = meta->property(i);
|
||||
const char* propName = prop.name();
|
||||
QVariant val = prop.readOnGadget(&obj);
|
||||
|
||||
out << propName << ": " << val.toString();
|
||||
|
||||
if (i < meta->propertyCount() - 1) out << ", ";
|
||||
}
|
||||
out << " }";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
116
bcvalue.h
@@ -6,7 +6,7 @@
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
mhsMEMBER _canMEMBER _drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
@@ -30,18 +30,18 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef BCVALUE_H
|
||||
#define BCVALUE_H
|
||||
#ifndef BCVALUEMEMBER_H
|
||||
#define BCVALUEMEMBER_H
|
||||
|
||||
#include <expected>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
|
||||
#include <expected>
|
||||
#include <bc.h>
|
||||
|
||||
|
||||
/*
|
||||
Werte haben verschiedene Längen (1,2 und 4 Byte) und werder auf unterschiedliche Art und Weise
|
||||
ausgelesen und geschrieben (Siehe BCValueTypeWord). Sie können also Wert-Typen zugeordnet werden. Ein Werttyp
|
||||
@@ -61,10 +61,13 @@ using OptDouble = std::optional<double>;
|
||||
// Enthält den gelesenen Wert oder einen Fehlerstring
|
||||
using TransmitResult = std::expected<uint32_t,QString>;
|
||||
// Funktionsobject, um Werte aus der Transmitterschicht zu holden
|
||||
//using ReadValueFunc = std::function<TransmitResult( const BCAbstractTransmitter& transmitter, uint32_t deviceID, uint8_t registerID )>;
|
||||
//using ReadValueFunc = std::function<TransmitResult( const BCAbstractTransmitter& transmitter, uint32MEMBER _t deviceID, uint8MEMBER _t registerID )>;
|
||||
|
||||
class BCValue
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
friend class BCXmlLoader;
|
||||
|
||||
public:
|
||||
|
||||
@@ -72,60 +75,103 @@ public:
|
||||
// später der Editor
|
||||
enum class ValueType : uint8_t
|
||||
{
|
||||
Plain,
|
||||
Plain, // nur lesen, sowas wie SerialNo
|
||||
Bool,
|
||||
Number,
|
||||
Float
|
||||
};
|
||||
|
||||
enum class State : uint8_t
|
||||
enum class Flag : uint8_t
|
||||
{
|
||||
NoState = 0x00,
|
||||
NoFlag = 0x00,
|
||||
ReadMe = 0x01,
|
||||
WriteMe = 0x02,
|
||||
ReadOnly = 0x04,
|
||||
Locked = 0x08,
|
||||
Failed = 0x10,
|
||||
InSync = 0x20,
|
||||
OK = 0x40
|
||||
OK = 0x40,
|
||||
IsWord = 0x80
|
||||
};
|
||||
Q_DECLARE_FLAGS(States, State )
|
||||
Q_DECLARE_FLAGS(Flags, Flag )
|
||||
Q_FLAG(Flags)
|
||||
|
||||
BCValue( BCDevice::ID deviceID_, BC::ID registerID_ );
|
||||
//Q_PROPERTY(Flags valueFlags MEMBER _valueFlags )
|
||||
Q_PROPERTY(BCDevice::ID deviceID MEMBER _deviceID READ deviceID )
|
||||
Q_PROPERTY(BC::ID registerID MEMBER _registerID READ registerID )
|
||||
Q_PROPERTY(ValueType valueType MEMBER _valueType READ valueType )
|
||||
Q_PROPERTY(int indexRow MEMBER _indexRow READ indexRow)
|
||||
Q_PROPERTY(QString label MEMBER _label READ label )
|
||||
Q_PROPERTY(uint32_t rawValue MEMBER _rawValue READ rawValue )
|
||||
Q_PROPERTY(QString unitLabel MEMBER _unitLabel READ unitLabel )
|
||||
Q_PROPERTY(double factor MEMBER _factor )
|
||||
//QMEMBER _PROPERTY(OptDouble MEMBER _optMin)
|
||||
//QMEMBER _PROPERTY(OptDouble MEMBER _optMax)
|
||||
|
||||
QString formatValue( uint32_t value ) const;
|
||||
void dumpValue() const;
|
||||
struct ValueRange
|
||||
{
|
||||
int value{0};
|
||||
int min{0};
|
||||
int max{0};
|
||||
double ratio{1};
|
||||
};
|
||||
|
||||
BCValue( BCDevice::ID deviceID, BC::ID registerID );
|
||||
|
||||
QString formatValue() const;
|
||||
double calcMinMaxRatio() const;
|
||||
void dumpValue() const;
|
||||
bool isWord() const;
|
||||
bool isReadOnly() const;
|
||||
|
||||
bool testFlag( Flag flag ) const;
|
||||
void setFlag( Flag flag, bool state=true ) const;
|
||||
|
||||
BCDevice::ID deviceID() const noexcept;
|
||||
BC::ID registerID() const noexcept;
|
||||
|
||||
uint32_t rawValue() const noexcept;
|
||||
void setRawValue(uint32_t newRawValue) const;
|
||||
void setFromDouble( double value );
|
||||
|
||||
ValueType valueType() const noexcept;
|
||||
int indexRow() const noexcept;
|
||||
|
||||
void setIndexRow(int newIndexRow);
|
||||
QString label() const;
|
||||
QString unitLabel() const;
|
||||
|
||||
bool valuesForSlider( ValueRange& valueRange ) const;
|
||||
|
||||
QString toString() const;
|
||||
|
||||
protected:
|
||||
|
||||
mutable Flags _valueFlags{BCValue::Flag::NoFlag};
|
||||
BCDevice::ID _deviceID{BCDevice::ID::Invalid};
|
||||
BC::ID _registerID{BC::ID::Invalid};
|
||||
ValueType _valueType{ValueType::Plain};
|
||||
int _indexRow{-1};
|
||||
QString _label;
|
||||
mutable uint32_t _rawValue{};
|
||||
QString _unitLabel;
|
||||
double _factor{1};
|
||||
OptDouble _optMin;
|
||||
OptDouble _optMax;
|
||||
|
||||
mutable States state{BCValue::State::ReadOnly};
|
||||
BCDevice::ID deviceID{BCDevice::ID::Invalid};
|
||||
BC::ID registerID{BC::ID::Invalid};
|
||||
ValueType valueType{ValueType::Plain};
|
||||
int indexRow{-1};
|
||||
QString label;
|
||||
mutable QString visibleValue;
|
||||
bool isWord{false};
|
||||
QString unitLabel;
|
||||
double factor{1};
|
||||
OptDouble min;
|
||||
OptDouble max;
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(BCValue::States)
|
||||
|
||||
|
||||
|
||||
//Q_DECLARE_METATYPE(const BCValue&)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(BCValue::Flags)
|
||||
Q_DECLARE_METATYPE(BCValue::Flags)
|
||||
|
||||
using BCValuePtr = std::shared_ptr<BCValue>;
|
||||
using BCValuePtrConst = std::shared_ptr<const BCValue>;
|
||||
|
||||
//using BCValueList = QList<BCValue>;
|
||||
using BCValueList = QList<BCValuePtr>;
|
||||
|
||||
Q_DECLARE_METATYPE(const BCValuePtr)
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(BCValueList)
|
||||
|
||||
|
||||
// Generischer Operator für ALLE GADGETs
|
||||
inline QTextStream& operator<<(QTextStream& out, const BCValue& obj);
|
||||
|
||||
#endif // BCVALUE_H
|
||||
|
||||
280
bcvaluedelegate.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/***************************************************************************
|
||||
|
||||
BionxControl
|
||||
© 2025 -2026 christoph holzheuer
|
||||
christoph.holzheuer@gmail.com
|
||||
|
||||
Using:
|
||||
|
||||
mhs_can_drv.c
|
||||
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
|
||||
Klaus Demlehner, klaus@mhs-elektronik.de
|
||||
@see www.mhs-elektronik.de
|
||||
|
||||
Based on Bionx data type descriptions from:
|
||||
|
||||
BigXionFlasher USB V 0.2.4 rev. 97
|
||||
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
|
||||
@see www.bigxionflasher.org
|
||||
|
||||
Bionx Bike Info
|
||||
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
|
||||
@see www.ts-soft.de
|
||||
|
||||
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.
|
||||
@see https://github.com/bikemike/bionx-bikeinfo
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <QSlider>
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QVariantAnimation>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPainter>
|
||||
|
||||
#include <bcdeviceview.h>
|
||||
#include <bcvaluedelegate.h>
|
||||
#include <bcvalueeditor.h>
|
||||
|
||||
|
||||
BCValueDelegate::BCValueDelegate(const BCValueList& valueList, BCDeviceView* view)
|
||||
: QStyledItemDelegate{view}, _valueList{valueList}, _view{view}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
QWidget* BCValueDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
|
||||
Q_UNUSED(option)
|
||||
Q_UNUSED(index)
|
||||
|
||||
const BCValue& bcValue = *(_valueList[ index.row()].get());
|
||||
|
||||
BCValue::ValueRange params;
|
||||
bool hasData = bcValue.valuesForSlider( params );
|
||||
if( !hasData )
|
||||
return nullptr;
|
||||
|
||||
qDebug() << " --- Create Editor: " << bcValue.label() << " value: " << params.value << " min: " << params.min << " max: " << params.max << " ratio:" << bcValue.calcMinMaxRatio()*100.0 << '%';
|
||||
|
||||
auto* valueEditor = new BCValueEditor(parent);
|
||||
valueEditor->setValueAndRange( params );
|
||||
|
||||
// Signal für sofortige Updates
|
||||
connect(valueEditor, &BCValueEditor::valueChanged, this, [this, valueEditor]()
|
||||
{
|
||||
// Commit data sofort bei Änderung
|
||||
emit const_cast<BCValueDelegate*>(this)->commitData(valueEditor);
|
||||
});
|
||||
|
||||
// Signal für sofortige Updates
|
||||
connect(valueEditor, &BCValueEditor::valueCommited, this, [this, valueEditor](int newValue)
|
||||
{
|
||||
qDebug() << " --- value set:" << newValue;
|
||||
// Commit data sofort bei Änderung
|
||||
//emit const_cast<BCValueDelegate*>(this)->commitData(valueEditor);
|
||||
});
|
||||
|
||||
return valueEditor;
|
||||
}
|
||||
|
||||
void BCValueDelegate::setEditorData(QWidget *editor, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(editor)
|
||||
Q_UNUSED(index)
|
||||
|
||||
// tue nix.
|
||||
|
||||
}
|
||||
|
||||
void BCValueDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const
|
||||
{
|
||||
if( index.column() == 1)
|
||||
{
|
||||
// Daten vom Editor zurück ins Model speichern (Beim Schließen)
|
||||
BCValueEditor* slider = qobject_cast<BCValueEditor*>(editor);
|
||||
if (slider)
|
||||
{
|
||||
int value = slider->value();
|
||||
model->setData(index, value, Qt::EditRole);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
|
||||
|
||||
void BCValueDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
// Standard-Zeichnen (Text, Hintergrund, Selection) durchführen
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
int row = index.row();
|
||||
|
||||
if( index.column() != 1 )
|
||||
return;
|
||||
if( row<0 || row >= _valueList.size() )
|
||||
return;
|
||||
|
||||
const BCValue& bcValue = *(_valueList[ index.row()].get());
|
||||
if( !bcValue.isReadOnly() )
|
||||
{
|
||||
if( bcValue.valueType() == BCValue::ValueType::Bool )
|
||||
paintButtonIndicator(painter, option, bcValue);
|
||||
else
|
||||
{
|
||||
|
||||
BCValueEditor::paintSliderIndicator(painter, option.rect, bcValue.calcMinMaxRatio() );
|
||||
}
|
||||
}
|
||||
|
||||
if(_rowOpacities.contains(row))
|
||||
paintHighlightRow(painter,option,index.row());
|
||||
|
||||
}
|
||||
|
||||
|
||||
void BCValueDelegate::paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, int row) const
|
||||
{
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
qreal opacity =_rowOpacities.value(row);
|
||||
painter->setOpacity(opacity);
|
||||
// Margin von 2px
|
||||
const int m = 3;
|
||||
QRect itemRect = option.rect.adjusted(m,m,-m,-m);
|
||||
|
||||
// Border (2px solid #2196F3)
|
||||
// oranger rahmen
|
||||
QPen borderPen( QColor(0xFF8C00), 1);
|
||||
painter->setPen(borderPen);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
// highlight background
|
||||
//QColor highlightColor = option.palette.highlight().color();
|
||||
//highlightColor.setAlphaF(0.3); // 0.0 bis 1.0 (float ist oft lesbarer)
|
||||
//painter->fillRect(option.rect, highlightColor);
|
||||
|
||||
painter->drawRoundedRect(itemRect, 2, 2);
|
||||
|
||||
painter->restore();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void BCValueDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
|
||||
QRect sliderRect = BCValueEditor::updateEditorRect( option.rect );
|
||||
editor->setGeometry(sliderRect); // Slider nur über Progress Bar
|
||||
}
|
||||
|
||||
void BCValueDelegate::paintButtonIndicator(QPainter* painter, const QStyleOptionViewItem& option, const BCValue& bcValue) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Startet die Animation für die übergebene Zeile
|
||||
* @param row
|
||||
*/
|
||||
|
||||
void BCValueDelegate::onHighlightRow(int row)
|
||||
{
|
||||
// Alte Animation für diese Zeile stoppen falls vorhanden
|
||||
if (_rowAnimations.contains(row))
|
||||
{
|
||||
_rowAnimations[row]->stop();
|
||||
_rowAnimations[row]->deleteLater();
|
||||
}
|
||||
|
||||
// QVariantAnimation ist flexibler als QPropertyAnimation
|
||||
auto* anim = new QVariantAnimation(this);
|
||||
anim->setDuration(800);
|
||||
anim->setStartValue(0.0);
|
||||
anim->setEndValue(1.0);
|
||||
|
||||
// Custom Easing für Fade-in/out Effekt
|
||||
anim->setEasingCurve(QEasingCurve::OutQuad);
|
||||
|
||||
connect(anim, &QVariantAnimation::valueChanged, this, [this, row](const QVariant& value)
|
||||
{
|
||||
qreal progress = value.toReal();
|
||||
qreal opacity;
|
||||
|
||||
// Schnelles Fade-in (20%), langsames Fade-out (80%)
|
||||
if (progress < 0.2) {
|
||||
opacity = progress * 5.0; // 0->1 in 20%
|
||||
} else {
|
||||
opacity = 1.0 - ((progress - 0.2) / 0.8); // 1->0 in 80%
|
||||
}
|
||||
|
||||
_rowOpacities[row] = opacity;
|
||||
updateRow(row);
|
||||
});
|
||||
|
||||
connect(anim, &QVariantAnimation::finished, this, [this, row, anim]()
|
||||
{
|
||||
_rowOpacities.remove(row);
|
||||
_rowAnimations.remove(row);
|
||||
updateRow(row);
|
||||
anim->deleteLater();
|
||||
});
|
||||
|
||||
_rowAnimations[row] = anim;
|
||||
anim->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sopt alle gerade laufenden Animationen
|
||||
*/
|
||||
|
||||
void BCValueDelegate::clearAllHighlights()
|
||||
{
|
||||
for(auto* anim : std::as_const(_rowAnimations))
|
||||
{
|
||||
anim->stop();
|
||||
anim->deleteLater();
|
||||
}
|
||||
_rowAnimations.clear();
|
||||
_rowOpacities.clear();
|
||||
|
||||
if (_view)
|
||||
{
|
||||
_view->viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Zeichnet die übegebene Zeile neu.
|
||||
* @param row
|
||||
*/
|
||||
|
||||
void BCValueDelegate::updateRow(int row)
|
||||
{
|
||||
if (_view && _view->model() && row >= 0)
|
||||
{
|
||||
QModelIndex idx = _view->model()->index(row,1);
|
||||
QRect rect = _view->visualRect(idx);
|
||||
if (!rect.isEmpty()) {
|
||||
_view->viewport()->update(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef BCANIMATEDDELEGATE_H
|
||||
#define BCANIMATEDDELEGATE_H
|
||||
#ifndef BCVALUEDELEGATE_H
|
||||
#define BCVALUEDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
@@ -39,73 +39,53 @@
|
||||
|
||||
class QPropertyAnimation;
|
||||
class QVariantAnimation;
|
||||
class QTableView;
|
||||
class BCDeviceView;
|
||||
|
||||
|
||||
class BCAnimatedDelegate : public QStyledItemDelegate
|
||||
class BCValueDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit BCAnimatedDelegate(const BCValueList& valueList, QTableView* view );
|
||||
|
||||
// QString displayText(const QVariant& dataValue, const QLocale& locale) const override;
|
||||
explicit BCValueDelegate(const BCValueList& valueList, BCDeviceView* view );
|
||||
|
||||
// Zuständig für den Edit-Modus (Doppelklick)
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const override;
|
||||
void setEditorData(QWidget *editor, const QModelIndex& index) const override;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const override;
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index) const override;
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex& index) const override;
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override;
|
||||
|
||||
/*
|
||||
qreal highlightOpacity() const
|
||||
{
|
||||
return _opacity;
|
||||
}
|
||||
|
||||
void setHighlightOpacity(qreal opacity)
|
||||
{
|
||||
_opacity = opacity;
|
||||
//qDebug() << " --- opa: " << opacity;
|
||||
// __fix! unsinn!
|
||||
emit viewUpdateNeeded();
|
||||
}
|
||||
*/
|
||||
|
||||
void clearAllHighlights();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
void onHighlightRow(int row);
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
//void viewUpdateNeeded();
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
void updateRow(int row);
|
||||
void paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
void paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, int row) const;
|
||||
void paintSliderIndicator(QPainter* painter, const QRect &rect, double ratio) const;
|
||||
void paintButtonIndicator(QPainter* painter, const QStyleOptionViewItem& option, const BCValue& bcValue) const;
|
||||
|
||||
// Das ist ein Quickhack, der Delegate sollte
|
||||
// nichts über die Originaldaten wissen. Die
|
||||
// Datenbeschaffung ist alleine Sache des Models.
|
||||
|
||||
const BCValueList& _valueList;
|
||||
QTableView* _view{};
|
||||
|
||||
//int _highlightedRow{-1};
|
||||
//qreal _opacity{1.0};
|
||||
BCDeviceView* _view{};
|
||||
|
||||
QPropertyAnimation* _animation{};
|
||||
|
||||
private:
|
||||
QHash<int, qreal> _rowOpacities;
|
||||
QHash<int, QVariantAnimation*> _rowAnimations;
|
||||
|
||||
QHash<int, qreal> m_rowOpacities;
|
||||
QHash<int, QVariantAnimation*> m_rowAnimations;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // BCANIMATEDDELEGATE_H
|
||||
#endif // BCVALUEDELEGATE_H
|
||||
97
bcvalueeditor.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
#include <bcsliderstyle.h>
|
||||
#include <bcvalueeditor.h>
|
||||
|
||||
|
||||
BCValueEditor::BCValueEditor( QWidget *parent )
|
||||
: QWidget(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
// wir wollen ja modern sein
|
||||
_slider->setStyle(new BCSliderStyle());
|
||||
setAutoFillBackground(true);
|
||||
|
||||
QSizePolicy sp = _commitButton->sizePolicy();
|
||||
sp.setRetainSizeWhenHidden(true); // <--- Das ist der magische Schalter
|
||||
_commitButton->setSizePolicy(sp);
|
||||
|
||||
|
||||
|
||||
// Wenn Slider bewegt wird -> Signal nach außen senden
|
||||
connect(_slider, &QSlider::valueChanged, this, [this](int val)
|
||||
{
|
||||
emit valueChanged(val);
|
||||
});
|
||||
|
||||
// Wenn Reset gedrückt wird -> Slider auf 0 (löst auch valueChanged aus)
|
||||
connect(_commitButton, &QPushButton::clicked, this, [this]()
|
||||
{
|
||||
emit valueCommited( value() );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
int BCValueEditor::value() const
|
||||
{
|
||||
return _slider->value();
|
||||
}
|
||||
|
||||
void BCValueEditor::setValueAndRange( const BCValue::ValueRange& params )
|
||||
{
|
||||
_slider->setRange( params.min, params.max);
|
||||
// Block Signals verhindern Endlosschleifen, falls das Model
|
||||
// das Widget während des Updates neu setzt (passiert manchmal bei Live-Updates).
|
||||
if (params.value != _slider->value())
|
||||
{
|
||||
bool blocked = _slider->blockSignals(true);
|
||||
_slider->setValue(params.value);
|
||||
_slider->blockSignals(blocked);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Zeichnet eine passiven Slider, um den möglichen Wertebereich des übergebenen BCValue anzuzeigen.
|
||||
*/
|
||||
|
||||
void BCValueEditor::paintSliderIndicator(QPainter* painter, const QRect& rect, double ratio )
|
||||
{
|
||||
// Kleinen Slider-Indikator zeichnen
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
qDebug() << " ---WTF in paint: " <<rect;
|
||||
|
||||
int adjX = rect.width() - cTextBlockOffset;
|
||||
|
||||
// Mini Progress Bar: der Gesamtbereich
|
||||
QRect barRect = rect.adjusted( adjX, 12, -10-24, -12 );
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor(0xE0E0E0));
|
||||
painter->drawRoundedRect(barRect, 2, 2);
|
||||
|
||||
// Mini Progress Bar: der Wertebereich
|
||||
barRect.setWidth( ratio * barRect.width() );
|
||||
painter->setBrush(QColor(0x0078D4));
|
||||
painter->drawRoundedRect(barRect, 2, 2);
|
||||
if(rect.x() != 0 )
|
||||
painter->setBrush(Qt::blue);
|
||||
else
|
||||
painter->setBrush(Qt::red);
|
||||
painter->drawRoundedRect(rect, 2, 2);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
|
||||
QRect BCValueEditor::updateEditorRect( const QRect& rect)
|
||||
{
|
||||
return rect.adjusted(
|
||||
rect.width() - cTextBlockOffset, // Von rechts: cTextBlockOffset (==130) px (Breite der Progress Bar)
|
||||
0, // Oben: kein Offset
|
||||
-cPaddingRight, // Rechts: 8px Padding
|
||||
0 // Unten: kein Offset
|
||||
);
|
||||
}
|
||||
43
bcvalueeditor.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef BCValueEditor_H
|
||||
#define BCValueEditor_H
|
||||
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <bcvalue.h>
|
||||
#include <ui_bcvalueeditor.h>
|
||||
|
||||
class QSlider;
|
||||
class QPushButton;
|
||||
class BCValue;
|
||||
|
||||
class BCValueEditor : public QWidget, private Ui::BCValueEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit BCValueEditor(QWidget *parent = nullptr);
|
||||
|
||||
int value() const;
|
||||
void setValueAndRange( const BCValue::ValueRange& params );
|
||||
|
||||
// helper functions
|
||||
static QRect updateEditorRect( const QRect& rect);
|
||||
static void paintSliderIndicator(QPainter* painter, const QRect& rect, double ratio );
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
void valueChanged(int value);
|
||||
void valueCommited(int value);
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr int cTextBlockOffset = 130;
|
||||
static constexpr int cPaddingRight = 8;
|
||||
static constexpr int cSliderWidth = 117;
|
||||
|
||||
};
|
||||
|
||||
#endif // BCValueEditor_H
|
||||
95
bcvalueeditor.ui
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BCValueEditor</class>
|
||||
<widget class="QWidget" name="BCValueEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>111</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetMinimumSize</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="_slider">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="_commitButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777212</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="bionxcontrol.qrc">
|
||||
<normaloff>:/update.png</normaloff>:/update.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::ToolButtonPopupMode::InstantPopup</enum>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="bionxcontrol.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -45,8 +45,6 @@ BCValueModel::BCValueModel(QObject *parent)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gibt die interne Werteliste als const ref zurück
|
||||
* @return Die WerteListe
|
||||
@@ -81,27 +79,21 @@ void BCValueModel::takeValueList(BCValueList& newValueList)
|
||||
* @param newValue Der neue sichtbare Zahlenwert, formatiert als QString, optionall
|
||||
*/
|
||||
|
||||
void BCValueModel::onValueUpdated( int row, BCValue::State state, const QString& newVisisbleValue )
|
||||
void BCValueModel::updateValue(int row, BCValue::Flags newState, uint32_t rawValue )
|
||||
{
|
||||
if( row > -1 && row < _valueList.size() )
|
||||
{
|
||||
BCValue& value = *(_valueList[row].get());
|
||||
const BCValue& value = *(_valueList[row].get());
|
||||
|
||||
BCValue::Flags newFlags1 = BCValue::Flag::NoFlag;
|
||||
BCValue::Flags newFlags2 = newState;
|
||||
|
||||
// Obacht hier!
|
||||
//value.valueFlags = state;
|
||||
value.setRawValue( rawValue );
|
||||
|
||||
QModelIndex idx = index(row,1);
|
||||
|
||||
//qDebug();
|
||||
//qDebug() << " --- OLD:"<< newVisisbleValue;
|
||||
//value.dumpValue();
|
||||
|
||||
value.state = state;
|
||||
|
||||
if( !newVisisbleValue.isEmpty() && newVisisbleValue != value.visibleValue )
|
||||
{
|
||||
value.visibleValue = newVisisbleValue;
|
||||
}
|
||||
|
||||
//qDebug() << " --- NEW: " << newVisisbleValue;
|
||||
//value.dumpValue();
|
||||
|
||||
// wir schicken auf jeden fall einen update request
|
||||
emit dataChanged(idx, idx, {Qt::DisplayRole, Qt::EditRole});
|
||||
}
|
||||
@@ -136,8 +128,6 @@ int BCValueModel::columnCount(const QModelIndex& parent) const
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gibt die Model-Daten zurück.
|
||||
*/
|
||||
@@ -156,65 +146,58 @@ QVariant BCValueModel::data(const QModelIndex& index, int role) const
|
||||
const BCValue& value = *(_valueList.at( row ).get());
|
||||
|
||||
if( col == 0 )
|
||||
return value.label;
|
||||
return value.label();
|
||||
|
||||
if( col == 1)
|
||||
{
|
||||
if( role == Qt::DisplayRole )
|
||||
return QString("%1 %2").arg( value.visibleValue, value.unitLabel);
|
||||
return QString("%1 %2").arg( value.formatValue(), value.unitLabel());
|
||||
|
||||
return value.visibleValue;
|
||||
return value.formatValue();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
|
||||
|
||||
/*
|
||||
Das Model Gibt hier, unabhängig von der DataRole, immer das
|
||||
* gesamte BCValue Object zurück. Die Umsetzung von Status- und Typeinfromationen in GUI-Elemente
|
||||
* findet nicht hier, sondern im BCDelagate statt.
|
||||
|
||||
// falsch! wie geben hier doch ordentlich die einzelwerte zurück
|
||||
|
||||
// Bonus: Rechtsbündig für Zahlen
|
||||
if (role == Qt::TextAlignmentRole && (index.column() == 0 || index.column() == 2)) {
|
||||
return Qt::AlignRight | Qt::AlignVCenter;
|
||||
}
|
||||
|
||||
//return QVariant::fromValue( entry );
|
||||
|
||||
return QVariant();
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
Qt::ItemFlags BCValueModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
|
||||
Qt::ItemFlags flag = Qt::NoItemFlags|Qt::ItemNeverHasChildren;
|
||||
// die label spalte lässt sich nicht editieren
|
||||
if (!index.isValid() || index.column() == 0 )
|
||||
return flag;
|
||||
int row = index.row();
|
||||
if( row>-1 && row<_valueList.size() )
|
||||
{
|
||||
const BCValue& bcValue = *_valueList[row].get();
|
||||
flag = bcValue.isReadOnly() ? flag : flag|Qt::ItemIsEditable|Qt::ItemIsEnabled;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
||||
bool BCValueModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
bool BCValueModel::setData(const QModelIndex& index, const QVariant& variant, int role)
|
||||
{
|
||||
|
||||
// __fix!
|
||||
|
||||
if (index.isValid() && role == Qt::EditRole)
|
||||
{
|
||||
BCValuePtr item = _valueList[index.row()];
|
||||
|
||||
qDebug() << " --- SetData: at: " << index.row() << " --- set: " << variant.toString();
|
||||
|
||||
BCValuePtr value = _valueList[index.row()];
|
||||
|
||||
// Wir erwarten hier nur den Value-Teil (vom Slider/Editor)
|
||||
// Checken ob Int oder Double
|
||||
if (value.canConvert<double>())
|
||||
if (variant.canConvert<int>())
|
||||
{
|
||||
item->visibleValue = value.toString();
|
||||
if( variant.toInt() == 42)
|
||||
{
|
||||
//emit makeSimonHappy();
|
||||
}
|
||||
// QUARK!
|
||||
value->setRawValue( variant.toInt() );
|
||||
}
|
||||
|
||||
_valueList[index.row()] = item;
|
||||
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,16 +59,16 @@ public:
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
//QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
// Nötig für Editierbarkeit
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||
|
||||
public slots:
|
||||
void updateValue(int row, BCValue::Flags newState, uint32_t rawValue );
|
||||
|
||||
void onValueUpdated(int index, BCValue::State state, const QString& newVisisbleValue="" );
|
||||
signals:
|
||||
|
||||
void makeSimonHappy();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
158
bcxmlloader.cpp
@@ -51,37 +51,30 @@ BCXmlLoader::BCXmlLoader(QObject *parent)
|
||||
|
||||
void BCXmlLoader::loadXmlBikeData( const QString& fileName )
|
||||
{
|
||||
/*
|
||||
auto printAttrs = [](const QXmlStreamReader& xml)
|
||||
{
|
||||
QStringList parts;
|
||||
for (const auto &attr : xml.attributes()) {
|
||||
for (const auto &attr : xml.attributes())
|
||||
{
|
||||
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
|
||||
}
|
||||
qDebug().noquote() << parts.join(" ");
|
||||
};
|
||||
/*
|
||||
QString fileName = QFileDialog::getOpenFileName(this, "XML öffnen", "", "XML Files (*.xml)");
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
*/
|
||||
|
||||
QMetaEnum bcDeviceEnum{QMetaEnum::fromType<BCDevice::ID>()};
|
||||
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
// __fix throw
|
||||
QMessageBox::warning(nullptr, "Fehler", "Datei konnte nicht geöffnet werden.");
|
||||
return;
|
||||
}
|
||||
throw BCException( "Fehler", "Datei konnte nicht geöffnet werden.");
|
||||
|
||||
_xml.setDevice(&file);
|
||||
|
||||
if (_xml.readNextStartElement())
|
||||
{
|
||||
if (_xml.name() != "Bike"_L1 )
|
||||
// fix throw
|
||||
_xml.raiseError(QObject::tr("The file is not an 'Bike' file."));
|
||||
throw BCException( "Fehler", "Falsches Datenformat.");
|
||||
}
|
||||
// ??
|
||||
Q_ASSERT(_xml.isStartElement() && _xml.name() == "Bike"_L1);
|
||||
@@ -92,53 +85,43 @@ void BCXmlLoader::loadXmlBikeData( const QString& fileName )
|
||||
if (token == QXmlStreamReader::StartElement)
|
||||
{
|
||||
QString deviceType = _xml.attributes().value("Type"_L1).toString();
|
||||
printAttrs (_xml);
|
||||
// Wir wollen die Device-ID aus dem XML Tag ermitteln
|
||||
const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData();
|
||||
bool ok;
|
||||
if( deviceType.isEmpty() )
|
||||
continue;
|
||||
|
||||
QByteArray byteArray = deviceType.toUtf8();
|
||||
const char* deviceKey = byteArray.constData();
|
||||
bool ok=false;
|
||||
auto optDeviceID = bcDeviceEnum.keyToValue(deviceKey,&ok);
|
||||
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );
|
||||
//if( optDeviceID.has_value())
|
||||
if(ok)
|
||||
{
|
||||
qDebug() << " --- Device: " << _xml.name() << ": " << deviceType << " : " << optDeviceID;
|
||||
//BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID.value() );
|
||||
BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID );
|
||||
loadXmlBikeDeviceData(currentDeviceID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (xml.hasError())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Parsing Fehler", xml.errorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_model->setDevices(parsedValues);
|
||||
}
|
||||
*/
|
||||
|
||||
// create & add new model to the model map
|
||||
|
||||
if(!ok)
|
||||
throw BCException( "Fehler", QString("Devicetype %1 existiert nicht.").arg(deviceType) );
|
||||
//BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID.value() );
|
||||
BCDevice::ID currentDeviceID = BCDevice::ID( optDeviceID );
|
||||
loadXmlBikeDeviceData(currentDeviceID);
|
||||
} // if startElement
|
||||
} // end while
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Lädt deie Daten des BionX eBikes
|
||||
* @param deviceID
|
||||
*/
|
||||
|
||||
void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
|
||||
{
|
||||
auto printAttrs = [](const QXmlStreamReader& xml)
|
||||
{
|
||||
QStringList parts;
|
||||
for (const auto &attr : xml.attributes()) {
|
||||
for (const auto &attr : xml.attributes())
|
||||
parts << attr.name().toString() + "=\"" + attr.value().toString() + "\"";
|
||||
}
|
||||
qDebug().noquote() << parts.join(" ");
|
||||
};
|
||||
|
||||
printAttrs (_xml);
|
||||
Q_ASSERT(_xml.isStartElement() && _xml.name() == "Device"_L1);
|
||||
qDebug() << " XXX ---------------";
|
||||
Q_ASSERT(_xml.isStartElement() && _xml.name() == BCTags::Device );
|
||||
|
||||
// temporäre Wertliste für neues Device
|
||||
BCValueList currentValues;
|
||||
@@ -146,9 +129,7 @@ void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
|
||||
while( _xml.readNextStartElement() )
|
||||
{
|
||||
if( _xml.attributes().hasAttribute(BCTags::ID) )
|
||||
{
|
||||
//qDebug() << " --- found: " << _xml.name() << " : " << _xml.attributes().value(BCTags::ID);
|
||||
|
||||
{
|
||||
// füllen des Parameter packs
|
||||
BCValueParams params
|
||||
{
|
||||
@@ -159,6 +140,7 @@ void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
|
||||
.Min = _xml.attributes().value(BCTags::Min).toString(),
|
||||
.Max = _xml.attributes().value(BCTags::Max).toString(),
|
||||
.IsWord = _xml.attributes().value(BCTags::IsWord).toString(),
|
||||
.ReadOnly = _xml.attributes().value(BCTags::ReadOnly).toString(),
|
||||
.ValueType = _xml.attributes().value(BCTags::ValueType).toString(),
|
||||
};
|
||||
|
||||
@@ -167,7 +149,7 @@ void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
|
||||
if(newValue)
|
||||
{
|
||||
// wir merken uns gleich den index in der Werteliste
|
||||
(*newValue)->indexRow = currentValues.size();
|
||||
(*newValue)->setIndexRow( currentValues.size() );
|
||||
currentValues.push_back( *newValue );
|
||||
}
|
||||
|
||||
@@ -182,6 +164,11 @@ void BCXmlLoader::loadXmlBikeDeviceData(BCDevice::ID deviceID)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Erzeugt einen BCValue für die DeviceID aus dem gegebenen parameter pack
|
||||
*/
|
||||
|
||||
std::optional<BCValuePtr> BCXmlLoader::makeValue( BCDevice::ID deviceID, const BCValueParams& params )
|
||||
{
|
||||
|
||||
@@ -193,66 +180,57 @@ std::optional<BCValuePtr> BCXmlLoader::makeValue( BCDevice::ID deviceID, const B
|
||||
{ "Float", BCValue::ValueType::Float }
|
||||
};
|
||||
|
||||
auto setIfExists = [&]<typename T>( QStringView source, T& target )
|
||||
auto setIfExists = [&]<typename T>( T& target, QStringView source )
|
||||
{
|
||||
if( !source.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
double testVal = source.toDouble(&ok);
|
||||
if (ok)
|
||||
target = testVal;
|
||||
}
|
||||
{
|
||||
bool ok;
|
||||
double testVal = source.toDouble(&ok);
|
||||
if (ok)
|
||||
target = testVal;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Wir brauchen:
|
||||
- einen gültige ID String um die enum ID herauszufinden.
|
||||
- einen gültige UnitType String um den ValueType herauszufinden.
|
||||
|
||||
*/
|
||||
// Wir brauchen:
|
||||
// - einen gültige ID String um die enum ID herauszufinden.
|
||||
// - einen gültige UnitType String um den ValueType herauszufinden.
|
||||
|
||||
// geht nicht auf qt6.8 von debian trixie
|
||||
//std::optional<quint64> IDVal = s_bcValueEnum.keyToValue64( params.ID.toLatin1().constData() );
|
||||
bool ok;
|
||||
static QMetaEnum s_bcValueEnum{QMetaEnum::fromType<BC::ID>()};
|
||||
int IDVal = s_bcValueEnum.keyToValue( params.ID.toLatin1().constData(), &ok );
|
||||
qDebug() << " --- should create: " << params.Label;
|
||||
QByteArray byteArray = params.ID.toUtf8();
|
||||
int IDVal = s_bcValueEnum.keyToValue( params.ID.toUtf8().constData(), &ok );
|
||||
//if( IDVal.has_value() )
|
||||
if( ok )
|
||||
{
|
||||
BCValuePtr newValuePtr = std::make_shared<BCValue>( deviceID, static_cast<BC::ID>(IDVal) );
|
||||
BCValue& newValue = *newValuePtr.get();
|
||||
if( !ok )
|
||||
throw BCException( "Fehler", QString("Devicetype %1 existiert nicht.").arg(params.ID) );
|
||||
|
||||
setIfExists( params.Factor, newValue.factor );
|
||||
setIfExists( params.Min, newValue.min );
|
||||
setIfExists( params.Max, newValue.max );
|
||||
setIfExists( params.IsWord, newValue.isWord );
|
||||
BCValuePtr newValuePtr = std::make_shared<BCValue>( deviceID, static_cast<BC::ID>(IDVal) );
|
||||
BCValue& newValue = *newValuePtr.get();
|
||||
|
||||
newValue.label = params.Label;
|
||||
newValue.unitLabel = params.UnitLabel;
|
||||
// ValueType
|
||||
if( !s_valueTypes.contains( params.ValueType ) )
|
||||
throw BCException( "Fehler", QString("ValueType %1 existiert nicht.").arg(params.ValueType) );
|
||||
|
||||
if( s_valueTypes.contains( params.ValueType ) )
|
||||
newValue.valueType = s_valueTypes[params.ValueType];
|
||||
newValue._valueType = s_valueTypes[params.ValueType];
|
||||
|
||||
/*
|
||||
QString ID;
|
||||
QString Label;
|
||||
QString UnitLabel;
|
||||
QString Factor;
|
||||
QString Min;
|
||||
QString Max;
|
||||
QString IsWord;
|
||||
QString ValueType;
|
||||
*/
|
||||
newValue._label = params.Label;
|
||||
newValue._unitLabel = params.UnitLabel;
|
||||
|
||||
qDebug() << " --- created: " << params.Label;
|
||||
newValue.dumpValue();
|
||||
setIfExists( newValue._factor, params.Factor );
|
||||
setIfExists( newValue._optMin, params.Min );
|
||||
setIfExists( newValue._optMax, params.Max );
|
||||
|
||||
return std::optional<BCValuePtr>( newValuePtr );
|
||||
}
|
||||
if( params.IsWord == "true")
|
||||
newValue._valueFlags.setFlag( BCValue::Flag::IsWord, true );
|
||||
|
||||
if( params.ReadOnly == "true")
|
||||
newValue._valueFlags.setFlag( BCValue::Flag::ReadOnly, true );
|
||||
|
||||
//newValue.dumpValue();
|
||||
|
||||
return std::optional<BCValuePtr>( newValuePtr );
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ protected:
|
||||
QString Min;
|
||||
QString Max;
|
||||
QString IsWord;
|
||||
QString ReadOnly;
|
||||
QString ValueType;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="bikeinfo.xml">resources/bikeinfo.xml</file>
|
||||
<file alias="bionxcontrol.qss">resources/bionxcontrol.qss</file>
|
||||
<file alias="claude_dark_mode.qss">resources/claude_dark_mode.qss</file>
|
||||
<file alias="claude_light_mode.qss">resources/claude_light_mode.qss</file>
|
||||
<file alias="bc_light.qss">resources/bc_light.qss</file>
|
||||
<file alias="bionx_akku.png">resources/bionx_akku.png</file>
|
||||
<file alias="bionx_console.png">resources/bionx_console.png</file>
|
||||
<file alias="bionx_motor.png">resources/bionx_motor.png</file>
|
||||
<file alias="exit.png">resources/exit.png</file>
|
||||
<file alias="important.png">resources/important.png</file>
|
||||
<file alias="restart.png">resources/restart.png</file>
|
||||
<file alias="splash.png">resources/splash.png</file>
|
||||
<file alias="connect.png">resources/connect.png</file>
|
||||
<file alias="connected.png">resources/connected.png</file>
|
||||
<file alias="disconnected.png">resources/disconnected.png</file>
|
||||
<file>resources/connect_white.svg</file>
|
||||
<file>resources/sync_green.svg</file>
|
||||
<file>resources/sync_yellow.svg</file>
|
||||
<file alias="exit.png">resources/exit.png</file>
|
||||
<file alias="exit_red.png">resources/exit_red.png</file>
|
||||
<file alias="sync_green.png">resources/sync_green.png</file>
|
||||
<file alias="sync_yellow.png">resources/sync_yellow.png</file>
|
||||
<file alias="sync.png">resources/sync.png</file>
|
||||
<file alias="bc_dark.qss">resources/bc_dark.qss</file>
|
||||
<file>resources/smile/face-angel.png</file>
|
||||
<file>resources/smile/face-angry.png</file>
|
||||
<file>resources/smile/face-cool.png</file>
|
||||
<file>resources/smile/face-crying.png</file>
|
||||
<file>resources/smile/face-embarrassed.png</file>
|
||||
<file>resources/smile/face-glasses.png</file>
|
||||
<file>resources/smile/face-kiss.png</file>
|
||||
<file>resources/smile/face-laugh.png</file>
|
||||
<file>resources/smile/face-monkey.png</file>
|
||||
<file>resources/smile/face-plain.png</file>
|
||||
<file>resources/smile/face-raspberry.png</file>
|
||||
<file>resources/smile/face-sad.png</file>
|
||||
<file>resources/smile/face-sick.png</file>
|
||||
<file>resources/smile/face-smile.png</file>
|
||||
<file>resources/smile/face-smile-big.png</file>
|
||||
<file>resources/smile/face-smirk.png</file>
|
||||
<file>resources/smile/face-surprise.png</file>
|
||||
<file alias="update.png">resources/update.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -27,6 +27,43 @@ sudo apt purge modemmanager
|
||||
|
||||
// ---
|
||||
|
||||
sudo apt install \
|
||||
qt6-declarative-dev \
|
||||
qt6-tools-dev \
|
||||
qt6-tools-dev-tools \
|
||||
qt6-l10n-tools \
|
||||
qt6-scxml-dev \
|
||||
qt6-serialport-dev \
|
||||
qt6-serialbus-dev \
|
||||
qt6-connectivity-dev \
|
||||
qt6-sensors-dev \
|
||||
qt6-websockets-dev \
|
||||
qt6-webchannel-dev \
|
||||
qt6-svg-dev \
|
||||
qt6-multimedia-dev \
|
||||
qt6-charts-dev \
|
||||
qt6-wayland \
|
||||
qml6-module-qtquick-controls \
|
||||
qml6-module-qtquick-layouts \
|
||||
qml6-module-qtquick-templates \
|
||||
qml6-module-qtquick-window \
|
||||
qml6-module-qtqml-workerscript \
|
||||
qml6-module-qtcharts \
|
||||
qml6-module-qt-labs-platform \
|
||||
libqt6sql6-mysql libqt6sql6-psql libqt6sql6-sqlite \
|
||||
libqt6opengl6-dev
|
||||
|
||||
sudo apt update
|
||||
sudo apt install \
|
||||
qtcreator \
|
||||
qtcreator-doc \
|
||||
cmake \
|
||||
ninja-build \
|
||||
gdb \
|
||||
clang \
|
||||
clang-format
|
||||
|
||||
|
||||
https://github.com/MHS-Elektronik/OBD-Display
|
||||
|
||||
sudo chgrp pi /opt
|
||||
@@ -36,21 +73,5 @@ https://github.com/MHS-Elektronik/OBD-Display
|
||||
tar -xzvf tiny_can_raspberry_790.tar.gz
|
||||
rm tiny_can_raspberry_790.tar.gz
|
||||
|
||||
sudo apt install fonts-open-sans
|
||||
|
||||
|
||||
RANT
|
||||
|
||||
--- STRUKTUR
|
||||
|
||||
Denglish -> Comments, Bezeichnungen 'aligned', 'given'
|
||||
Weltsprache, mag ja sein,
|
||||
|
||||
Schlimmer: Doku & Bücher -> c++, qt, OO nicht verstanden
|
||||
|
||||
includes_ pfade hartcodiert statt im Makefile -> Kunstfehler
|
||||
Projecte willkürlich verstreut
|
||||
|
||||
Respektlose Schlampigkeit: copy & paste: es werden sogar die Artefakte des MKS mitkopiert ->
|
||||
---
|
||||
|
||||
---
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
|
||||
Sehr geehrte Frau Spaag,
|
||||
|
||||
Aktuell bin ich als Softwareentwickler im Bereich C++/Qt fest angestellt, suche jedoch
|
||||
nach neuen Entwicklungsmöglichkeiten.
|
||||
|
||||
Ihre Stellenanzeige hat mich sofort angesprochen, denn das beschriebene Anforderungsprofil
|
||||
harmonisiert sehr gut mit meiner derzeitigen Tätigkeit im Bereich Datenvisualisierung und
|
||||
|
||||
blub
|
||||
|
||||
Ich freu mich wie woschd und verbeibe mit freundlichen Grüßen
|
||||
|
||||
Christoph Holzheuer
|
||||
|
||||
|
||||
// ----------
|
||||
|
||||
znode<T> ist eine header-only Klasse in modern c++ für generische Baumstrukturen
|
||||
In der derzeitigen Ausführung dient sie mit Hilfe des pugixml Parser zur Verwaltung
|
||||
von XML Daten innerhalb des xtree-Projekts.
|
||||
|
||||
Die Knoten sind std::c++, die Verwaltung der Attribs ist drangeebrt und somit variable.
|
||||
|
||||
Besonderheit ist die Übergabe das String types als template parameter: In Xtree instanzierung durch QString,
|
||||
andere durch std::string bzw. std::w_string ohne Dependencies zur Qt-Lib eingehen zu müssen.
|
||||
bridge-code
|
||||
|
||||
// ----------
|
||||
|
Before Width: | Height: | Size: 46 KiB |
@@ -1,63 +0,0 @@
|
||||
Challenges
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
BionxControl
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
xtree
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
znode
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
libPigPio
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
supportware
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
raDIYo
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
|
||||
miniCash.connect
|
||||
|
||||
Aufgabe:
|
||||
|
||||
Ansatz:
|
||||
|
||||
-------------------------------------------------------------------------------------------------
|
||||
18
main.cpp
@@ -47,25 +47,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QApplication app(argc, argv);
|
||||
/*
|
||||
app.setStyleSheet(R"(
|
||||
QWidget {
|
||||
background-color: #F3F3F3;
|
||||
font-family: 'Segoe UI Variable', 'Segoe UI', sans-serif;
|
||||
}
|
||||
)");
|
||||
*/
|
||||
/*
|
||||
app.setStyleSheet(R"(
|
||||
* {
|
||||
font-family: 'Calibri', 'Carlito', 'Arial', sans-serif;
|
||||
font-size: 12pt;
|
||||
})");
|
||||
|
||||
*/
|
||||
//QFont font("segoe UI", 12); // Name, Größe
|
||||
//QFont font("calibri", 12); // Name, Größe
|
||||
//app.setFont(font);
|
||||
|
||||
BCMainWindow w;
|
||||
w.show();
|
||||
|
||||
230
resources/bc_dark.qss
Normal file
@@ -0,0 +1,230 @@
|
||||
/* ===== Fluent Dark Mode Theme ===== */
|
||||
/* Basierend auf Microsoft Fluent Design System */
|
||||
|
||||
/* === Color Palette === */
|
||||
/* Background: #202020, #2b2b2b, #323232 */
|
||||
/* Accent: #0078d4 (Fluent Blue) */
|
||||
/* Text: #ffffff, #e4e4e4 */
|
||||
/* Borders: #3d3d3d, #4d4d4d */
|
||||
|
||||
/* === QWidget Base === */
|
||||
QWidget
|
||||
{
|
||||
background-color: #202020;
|
||||
color: #ffffff;
|
||||
font-family: "Segoe UI", "Roboto", sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
QLabel#_headerLabel
|
||||
{
|
||||
font-size: 18pt;
|
||||
/*font-weight: bold;*/
|
||||
}
|
||||
|
||||
QWidget:disabled
|
||||
{
|
||||
color: #6d6d6d;
|
||||
}
|
||||
|
||||
/* === QToolButton === */
|
||||
QToolButton
|
||||
{
|
||||
background-color: transparent;
|
||||
color: #ffffff;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
padding: 6px 12px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QToolButton:hover
|
||||
{
|
||||
background-color: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
QToolButton:pressed
|
||||
{
|
||||
background-color: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
QToolButton:checked
|
||||
{
|
||||
background-color: rgba(0, 120, 212, 0.15);
|
||||
border: 1px solid #0078d4;
|
||||
color: #0078d4;
|
||||
}
|
||||
|
||||
QToolButton:checked:hover
|
||||
{
|
||||
background-color: rgba(0, 120, 212, 0.25);
|
||||
}
|
||||
|
||||
QToolButton:disabled
|
||||
{
|
||||
color: #6d6d6d;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Basis-Zustand: Alles weg */
|
||||
QToolButton#_commitButton
|
||||
{
|
||||
background: transparent;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
outline: none; /* Entfernt den Fokus-Rahmen (gepunktete Linie) */
|
||||
padding: 0px; /* Entfernt Innenabstand */
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
QToolButton#_commitButton:hover
|
||||
{
|
||||
background-color: rgba(0, 0, 0, 0.03);
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton#_commitButton:pressed
|
||||
{
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton#_commitButton:checked
|
||||
{
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton#_commitButton:focus
|
||||
{
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* === QTableView === */
|
||||
QTableView
|
||||
{
|
||||
background-color: #2b2b2b;
|
||||
color: #ffffff;
|
||||
border: 1px solid #3d3d3d;
|
||||
border-radius: 4px;
|
||||
selection-background-color: #0078d4;
|
||||
selection-color: #ffffff;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
QTableView::item
|
||||
{
|
||||
padding: 0px;
|
||||
border: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
QTableView::item:focus
|
||||
{
|
||||
outline: 0;
|
||||
background-color: blue;
|
||||
}
|
||||
*/
|
||||
|
||||
QTableView::item:hover
|
||||
{
|
||||
background-color: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
QTableView::item:selected
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
/* === Corner Widget (zwischen Scrollbars) === */
|
||||
QTableView QTableCornerButton::section
|
||||
{
|
||||
background-color: #323232;
|
||||
border: none;
|
||||
border-right: 1px solid #3d3d3d;
|
||||
border-bottom: 1px solid #3d3d3d;
|
||||
}
|
||||
|
||||
|
||||
/* === QScrollBar Vertical === */
|
||||
QScrollBar:vertical
|
||||
{
|
||||
background: transparent;
|
||||
width: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
min-height: 30px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background: rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:pressed {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical,
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* === QScrollBar Horizontal === */
|
||||
QScrollBar:horizontal {
|
||||
background: transparent;
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
min-width: 30px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:hover {
|
||||
background: rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:pressed {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal,
|
||||
QScrollBar::sub-line:horizontal {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:horizontal,
|
||||
QScrollBar::sub-page:horizontal {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* === QToolTip === */
|
||||
QToolTip
|
||||
{
|
||||
background-color: #323232;
|
||||
color: #ffffff;
|
||||
border: 1px solid #4d4d4d;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
252
resources/bc_light.qss
Normal file
@@ -0,0 +1,252 @@
|
||||
/* ===== Fluent Light Mode Theme ===== */
|
||||
/* Basierend auf Microsoft Fluent Design System */
|
||||
|
||||
/* === Color Palette === */
|
||||
/* Background: #f3f3f3, #ffffff, #fafafa */
|
||||
/* Accent: #0078d4 (Fluent Blue) */
|
||||
/* Text: #000000, #1f1f1f */
|
||||
/* Borders: #e1e1e1, #d1d1d1 */
|
||||
|
||||
/* === QWidget Base === */
|
||||
QWidget {
|
||||
background-color: #f3f3f3;
|
||||
color: #1f1f1f;
|
||||
font-family: "Segoe UI", "Roboto", sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
QLabel#_headerLabel
|
||||
{
|
||||
font-size: 18pt;
|
||||
/*font-weight: bold;*/
|
||||
}
|
||||
|
||||
QWidget:disabled {
|
||||
color: #a0a0a0;
|
||||
}
|
||||
|
||||
/* === QToolButton === */
|
||||
QToolButton {
|
||||
background-color: transparent;
|
||||
color: #1f1f1f;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
padding: 6px 12px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QToolButton:hover {
|
||||
background-color: rgba(0, 0, 0, 0.03);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
QToolButton:pressed {
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
QToolButton:checked {
|
||||
background-color: rgba(0, 120, 212, 0.1);
|
||||
border: 1px solid #0078d4;
|
||||
color: #0078d4;
|
||||
}
|
||||
|
||||
QToolButton:checked:hover {
|
||||
background-color: rgba(0, 120, 212, 0.15);
|
||||
}
|
||||
|
||||
QToolButton:disabled {
|
||||
color: #a0a0a0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Basis-Zustand: Alles weg */
|
||||
QToolButton#_commitButton {
|
||||
background: transparent;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
outline: none; /* Entfernt den Fokus-Rahmen (gepunktete Linie) */
|
||||
padding: 0px; /* Entfernt Innenabstand */
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/* WICHTIG: Auch die interaktiven Zustände überschreiben,
|
||||
sonst flackert der Standard-Style beim Klicken wieder auf */
|
||||
|
||||
QToolButton#_commitButton:hover
|
||||
{
|
||||
background-color: rgba(0, 0, 0, 0.03);
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton#_commitButton:pressed
|
||||
{
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton#_commitButton:checked
|
||||
{
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton#_commitButton:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* === QTableView === */
|
||||
QTableView
|
||||
{
|
||||
background-color: #ffffff;
|
||||
alternate-background-color: #fafafa;
|
||||
color: #1f1f1f;
|
||||
gridline-color: #e1e1e1;
|
||||
border: 1px solid #d1d1d1;
|
||||
border-radius: 4px;
|
||||
selection-background-color: #0078d4;
|
||||
selection-color: #ffffff;
|
||||
}
|
||||
|
||||
QTableView::item
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
QTableView::item:hover {
|
||||
background-color: rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
QTableView::item:selected {
|
||||
background-color: #0078d4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QTableView::item:selected:hover
|
||||
{
|
||||
background-color: #005a9e;
|
||||
}
|
||||
|
||||
QTableView::item:selected:!active
|
||||
{
|
||||
background-color: rgba(0, 120, 212, 0.3);
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
QTableView:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* === QScrollBar Vertical === */
|
||||
QScrollBar:vertical {
|
||||
background: transparent;
|
||||
width: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
min-height: 30px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:pressed {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical,
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* === QScrollBar Horizontal === */
|
||||
QScrollBar:horizontal {
|
||||
background: transparent;
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
min-width: 30px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:hover {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:pressed {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal,
|
||||
QScrollBar::sub-line:horizontal {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:horizontal,
|
||||
QScrollBar::sub-page:horizontal {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* === QToolTip === */
|
||||
QToolTip {
|
||||
background-color: #ffffff;
|
||||
color: #1f1f1f;
|
||||
border: 1px solid #d1d1d1;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* === Corner Widget (zwischen Scrollbars) === */
|
||||
QTableView QTableCornerButton::section {
|
||||
background-color: #fafafa;
|
||||
border: none;
|
||||
border-right: 1px solid #e1e1e1;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
/* QLineEdit */
|
||||
QLineEdit {
|
||||
background-color: #ffffff;
|
||||
color: #1f1f1f;
|
||||
border: 1px solid #d1d1d1;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
selection-background-color: #0078d4;
|
||||
selection-color: #ffffff;
|
||||
}
|
||||
|
||||
QLineEdit:hover {
|
||||
border: 1px solid #a0a0a0;
|
||||
}
|
||||
|
||||
/*
|
||||
QLineEdit:focus {
|
||||
border: 1px solid #0078d4;
|
||||
border-bottom: 2px solid #0078d4;
|
||||
}
|
||||
*/
|
||||
|
||||
QLineEdit:disabled {
|
||||
background-color: #fafafa;
|
||||
color: #a0a0a0;
|
||||
border: 1px solid #e1e1e1;
|
||||
}
|
||||
@@ -2,68 +2,65 @@
|
||||
|
||||
<Bike name='franken-wheeler'>
|
||||
|
||||
<Device Type="Console">
|
||||
<Value ID='Cons_Rev_Hw' Label='Hardware Version' />
|
||||
<Value ID='Cons_Rev_Sw' Label='Software Version' />
|
||||
|
||||
<Value ID='Cons_Sn_Product_Hi' Label='Product Number' IsWord='1'/>
|
||||
<Value ID='Cons_Sn_Oem_Hi' Label='OEM Number' IsWord='1' />
|
||||
|
||||
<Value ID='Cons_Assist_Initlevel' Label='Assistance Init Level' Min='0' Max='4'/>
|
||||
|
||||
|
||||
<Value ID='Cons_Assist_Level_1' Label='Assistance Level 1' Factor='1.5625' UnitLabel='%' Min='0' Max='400' />
|
||||
<Value ID='Cons_Assist_Level_2' Label='Assistance Level 2' Factor='1.5625' UnitLabel='%' Min='0' Max='400' />
|
||||
<Value ID='Cons_Assist_Level_3' Label='Assistance Level 3' Factor='1.5625' UnitLabel='%' Min='0' Max='400' />
|
||||
<Value ID='Cons_Assist_Level_4' Label='Assistance Level 4' Factor='1.5625' UnitLabel='%' Min='0' Max='400' />
|
||||
|
||||
<Value ID='Cons_Assist_Maxspeed_Flag' Label='Max Limit Enabled' ValueType='bool' />
|
||||
<Value ID='Cons_Assist_Maxspeed_Hi' Label='Max Speed Limit' UnitLabel='km/h' Factor='0.1' Min='0' Max='70'/>
|
||||
|
||||
<Value ID='Cons_Assist_Minspeed_Flag' Label='Min Limit Enabled' ValueType='bool' />
|
||||
<Value ID='Cons_Assist_Minspeed' Label='Min Speed Limit' UnitLabel='km/h' Min='0' Max='70' />
|
||||
|
||||
<Value ID='Cons_Throttle_Maxspeed_Flag' Label='Throttle Limit Enabled' ValueType='bool'/>
|
||||
<Value ID='Cons_Throttle_Maxspeed_Hi' Label='Throttle Speed Limit' UnitLabel='km/h' Factor='0.1' Min='0' Max='70' />
|
||||
|
||||
<Value ID='Cons_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='1' UnitLabel='mm' Min='0' Max='2300' Factor='1.5625' />
|
||||
<Value ID='Cons_Assist_Mountain_Cap' Label='Mountain Cap' UnitLabel='%' Factor='1.5625' />
|
||||
<Device Type='Motor'>
|
||||
<Value ID='Motor_Rev_Hw' Label='Hardware Version' ValueType='Plain' ReadOnly='true' />
|
||||
<Value ID='Motor_Rev_Sw' Label='Software Version' ValueType='Plain' ReadOnly='true' />
|
||||
<Value ID='Motor_Sn_Item_Hi' Label='Motor Part Number' ValueType='Plain' IsWord='true' ReadOnly='true' />
|
||||
<Value ID='Motor_Sn_Item_Hi' Label='Motor Serial Number' ValueType='Plain' IsWord='true' ReadOnly='true' />
|
||||
<Value ID='Motor_Status_Temperature' Label='Motor Temperature' ValueType='Float' UnitLabel='°C' />
|
||||
<Value ID='Motor_Assist_Maxspeed' Label='Motor max. Speed' UnitLabel='km/h' Factor='0.1' Min='0' Max='70' ValueType='Float' />
|
||||
<Value ID='Motor_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='true' UnitLabel='mm' Min='0' Max='2300' ValueType='Number' Factor='1.5625' />
|
||||
</Device>
|
||||
|
||||
<!--
|
||||
<Device Type="Motor">
|
||||
<Value ID='Motor_Rev_Hw' Label='Hardware Version' />
|
||||
<Value ID='Motor_Rev_Sw' Label='Software Version' />
|
||||
<Value ID='Motor_Sn_Item_Hi' Label='Motor Part Number' IsWord='1'/>
|
||||
<Value ID='Motor_Sn_Item_Hi' Label='Motor Serial Number' IsWord='1' />
|
||||
<Value ID='Motor_Status_Temperature' Label='Motor Temperature' UnitLabel='°C' />
|
||||
<Value ID='Motor_Assist_Maxspeed' Label='Motor max. Speed' Reader='Kmh' />
|
||||
|
||||
<Value ID='Motor_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='1' UnitLabel='mm' Min='0' Max='2300' Factor='1.5625' />
|
||||
<Device Type='Battery'>
|
||||
<Value ID='Reg_Battery_Rev_Hw' Label='Hardware Version' ValueType='Plain' ReadOnly='true' />
|
||||
<Value ID='Reg_Battery_Rev_Sw' Label='Software Version' ValueType='Plain' ReadOnly='true' />
|
||||
</Device>
|
||||
|
||||
<Device Type="Battery">
|
||||
<Value ID='Battery_Rev_Hw' Label='Hardware Version' />
|
||||
<Value ID='Battery_Rev_Sw' Label='Software Version' />
|
||||
<Device Type='Console'>
|
||||
<Value ID='Cons_Rev_Hw' Label='Hardware Version' ValueType='Plain' ReadOnly='true' />
|
||||
<Value ID='Cons_Rev_Sw' Label='Software Version' ValueType='Plain' ReadOnly='true' />
|
||||
|
||||
<Value ID='Cons_Sn_Product_Hi' Label='Product Number' IsWord='true' ValueType='Plain' ReadOnly='true'/>
|
||||
<Value ID='Cons_Sn_Oem_Hi' Label='OEM Number' IsWord='true' ValueType='Plain' ReadOnly='true' />
|
||||
|
||||
<!--<Value ID='Cons_Assist_Initlevel' Label='Assistance Init Level' Min='0' Max='4' ValueType='Number'/>-->
|
||||
<Value ID='Cons_Assist_Initlevel' Label='Assistance Init Level' Min='0' Max='100' UnitLabel='%' ValueType='Float'/>
|
||||
<Value ID='Cons_Assist_Level_1' Label='Assistance Level 1' Factor='1.5625' UnitLabel='%' Min='0' Max='400' ValueType='Float'/>
|
||||
<Value ID='Cons_Assist_Level_2' Label='Assistance Level 2' Factor='1.5625' UnitLabel='%' Min='0' Max='400' ValueType='Float'/>
|
||||
<Value ID='Cons_Assist_Level_3' Label='Assistance Level 3' Factor='1.5625' UnitLabel='%' Min='0' Max='400' ValueType='Float'/>
|
||||
<Value ID='Cons_Assist_Level_4' Label='Assistance Level 4' Factor='1.5625' UnitLabel='%' Min='0' Max='400' ValueType='Float'/>
|
||||
|
||||
<Value ID='Cons_Assist_Maxspeed_Flag' Label='Max Limit Enabled' ValueType='Bool' />
|
||||
<Value ID='Cons_Assist_Maxspeed_Hi' Label='Max Speed Limit' UnitLabel='km/h' Factor='0.1' Min='0' Max='70' ValueType='Float'/>
|
||||
|
||||
<Value ID='Cons_Assist_Minspeed_Flag' Label='Min Limit Enabled' ValueType='Bool' />
|
||||
<Value ID='Cons_Assist_Minspeed' Label='Min Speed Limit' UnitLabel='km/h' Min='0' Max='70' ValueType='Float'/>
|
||||
|
||||
<Value ID='Cons_Throttle_Maxspeed_Flag' Label='Throttle Limit Enabled' ValueType='Bool'/>
|
||||
<Value ID='Cons_Throttle_Maxspeed_Hi' Label='Throttle Speed Limit' UnitLabel='km/h' Factor='0.1' Min='0' Max='70' ValueType='Float'/>
|
||||
|
||||
<Value ID='Cons_Geometry_Circ_Hi' Label='Wheel Circumference' IsWord='true' UnitLabel='mm' Min='0' Max='2300' Factor='1.5625' ValueType='Number'/>
|
||||
<Value ID='Cons_Assist_Mountain_Cap' Label='Mountain Cap' UnitLabel='%' Factor='1.5625' ValueType='Float'/>
|
||||
</Device>
|
||||
-->
|
||||
|
||||
</Bike>
|
||||
|
||||
<!--
|
||||
printf( " odo .....................: Percent0.2f Km" _NL _NL,
|
||||
((getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_1) << 24) +
|
||||
((getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_1) << 24) +
|
||||
(getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_2) << 16) +
|
||||
(getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_3) << 8) +
|
||||
(getValue(CONSOLE, CONSOLE_STATS_BCValueTypeWord_4))) / (double)10
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<Value ID='Cons_Stat_Dist_Hi' Label='' Reader='mm' Factor='0.1' />
|
||||
<Value ID='Cons_Stat_Dist_Lo' Label='' Reader='mm'/>
|
||||
<Value ID='Cons_Stat_Dist_Lo' Label='' Reader='mm'/>
|
||||
<Value ID='Cons_Stat_Avgspeed_Hi' Label='' Reader='mm' Factor='0.1' />
|
||||
<Value ID='Cons_Stat_Avgspeed_Lo' Label='' Reader='mm'/>
|
||||
|
||||
@@ -87,7 +84,7 @@
|
||||
<Value ID='Cons_Sn_Day' Label='' />
|
||||
|
||||
<Value ID='Cons_Sn_Pn_Hi' Label='' />
|
||||
<Value ID='Cons_Sn_Pn_Lo' Label='' />
|
||||
<Value ID='Cons_Sn_Pn_Lo' Label='' />
|
||||
<Value ID='Cons_Sn_Item_Hi' Label='' />
|
||||
<Value ID='Cons_Sn_Item_Lo' Label='' />
|
||||
|
||||
@@ -133,7 +130,7 @@
|
||||
<Value ID='Cons_Preference_Codesrw_Lolo' Label='' />
|
||||
<Value ID='Cons_Preference_Throttle_Mode' Label='' />
|
||||
|
||||
|
||||
|
||||
<Value ID='Cons_Throttle_Boost_Triggerlevel' Label='' Min='1.5' Max='50.0' Factor='1.5625' />
|
||||
<Value ID='Cons_Preference_Flip_Side' Label='' />
|
||||
<Value ID='Cons_Config_Testmode' Label='' />
|
||||
@@ -141,25 +138,25 @@
|
||||
|
||||
<Value ID='Cons_Config_Last_Mode' Label='' />
|
||||
<Value ID='Cons_Assist_Speedgain' Label='' Factor='0.1' />
|
||||
|
||||
|
||||
|
||||
<Value ID='Cons_Config_Last_Mode_On' Label='' />
|
||||
<Value ID='Cons_Config_Last_Mode_Off' Label='' />
|
||||
<Value ID='Cons_Config_Last_Mode_Off' Label='' />
|
||||
|
||||
<Value ID='Cons_Status_Slave' Label='' />
|
||||
|
||||
<Value ID='Cons_Throttle_Raw_Hi' Label='' />
|
||||
<Value ID='Cons_Throttle_Raw_Lo' Label='' />
|
||||
<Value ID='Cons_Throttle_Raw_Lo' Label='' />
|
||||
<Value ID='Cons_Throttle_Position' Label='' Factor='1.5625'/>
|
||||
|
||||
<Value ID='Cons_Assist_Level_Rekuperation_3' Label='' Factor='1.5625'/>
|
||||
<Value ID='Cons_Assist_Level_Rekuperation_4' Label='' Factor='1.5625'/>
|
||||
<Value ID='Cons_Assist_Level_Rekuperation_4' Label='' Factor='1.5625'/>
|
||||
<Value ID='Cons_Config_Service_Timestamp_Hi' Label='' />
|
||||
<Value ID='Cons_Config_Service_Zimestamp_Lo' Label='' />
|
||||
<Value ID='Cons_Config_Service_Distance_Hi' Label='' />
|
||||
<Value ID='Cons_Config_Service_Distance_Lo' Label='' />
|
||||
|
||||
<Value ID='Cons_Assist_Level_Rekuperation_1' Label='' Factor='1.5625'/>
|
||||
<Value ID='Cons_Assist_Level_Rekuperation_2' Label='' Factor='1.5625'/>
|
||||
<Value ID='Cons_Assist_Level_Rekuperation_2' Label='' Factor='1.5625'/>
|
||||
|
||||
-->
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/* appqss */
|
||||
|
||||
/* Alle QWidgets bekommen diesen Font */
|
||||
QWidget
|
||||
{
|
||||
font-size: 14px;
|
||||
font-family: Segoe UI, sans-serif;
|
||||
}
|
||||
/*
|
||||
QMainWindow
|
||||
{
|
||||
background-color: #272727;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Spezifisches Styling für Buttons */
|
||||
QPushButton
|
||||
{
|
||||
background-color: #0078d7;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
QPushButton:hover
|
||||
{
|
||||
background-color: #1084e3;
|
||||
}
|
||||
|
||||
QPushButton:pressed
|
||||
{
|
||||
background-color: #005a9e;
|
||||
}
|
||||
|
||||
/* Normal */
|
||||
QToolButton {
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/* Hover */
|
||||
QToolButton:hover {
|
||||
background-color: #E3F2FD;
|
||||
border: 1px solid #2196F3;
|
||||
}
|
||||
|
||||
/* Pressed/Clicked */
|
||||
QToolButton:pressed {
|
||||
background-color: #BBDEFB;
|
||||
}
|
||||
|
||||
/* Checked (bei checkable buttons) */
|
||||
QToolButton:checked {
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Checked + Hover */
|
||||
QToolButton:checked:hover {
|
||||
background-color: #1976D2;
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
QToolButton:disabled {
|
||||
color: #BDBDBD;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
QTableView
|
||||
{
|
||||
background-color: #404142;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
show-decoration-selected: 0;
|
||||
}
|
||||
|
||||
QTableView::item
|
||||
{
|
||||
border: 2px solid #2196F3;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
margin: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
*/
|
||||
|
||||
QTableView::item:hover
|
||||
{
|
||||
border-color: #FF9800;
|
||||
background-color: #fff8f0;
|
||||
}
|
||||
|
||||
QTableView::item:selected
|
||||
{
|
||||
border-color: #F44336; /* Roter Rahmen */
|
||||
background-color: #ffebee;
|
||||
}
|
||||
|
||||
QTableView::item:selected:hover
|
||||
{
|
||||
border-color: #FF9800;
|
||||
background-color: #ffe0b2;
|
||||
}
|
||||
*/
|
||||
|
||||
QTableView::item:focus
|
||||
{
|
||||
/*
|
||||
// outline: none; Entfernt das Focus-Rectangle
|
||||
// border-color: green;
|
||||
// background-color: #ffe0b2;
|
||||
*/
|
||||
border: 2px solid gray;
|
||||
border-style: inset;
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
@@ -1,871 +0,0 @@
|
||||
/* ===================================================================
|
||||
Fluent Design Dark Mode Stylesheet for Qt6
|
||||
Windows 11 inspired dark theme
|
||||
=================================================================== */
|
||||
|
||||
/* === Color Palette ===
|
||||
Background: #202020
|
||||
Surface: #2B2B2B
|
||||
Surface Hover: #3A3A3A
|
||||
Border: #3F3F3F
|
||||
Text: #FFFFFF
|
||||
Text Secondary: #B0B0B0
|
||||
Accent: #0078D4
|
||||
Accent Hover: #106EBE
|
||||
=== */
|
||||
|
||||
/* === Global Styles === */
|
||||
* {
|
||||
font-family: "Segoe UI", "Noto Sans", Roboto, sans-serif;
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
QWidget {
|
||||
background-color: #202020;
|
||||
color: #FFFFFF;
|
||||
selection-background-color: #0078D4;
|
||||
selection-color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QMainWindow === */
|
||||
QMainWindow {
|
||||
background-color: #202020;
|
||||
}
|
||||
|
||||
QMainWindow::separator {
|
||||
background-color: #3F3F3F;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
QMainWindow::separator:hover {
|
||||
background-color: #0078D4;
|
||||
}
|
||||
|
||||
/* === QPushButton === */
|
||||
QPushButton {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
padding: 6px 16px;
|
||||
min-height: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
background-color: #3A3A3A;
|
||||
border-color: #5A5A5A;
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: #1F1F1F;
|
||||
border-color: #3F3F3F;
|
||||
}
|
||||
|
||||
QPushButton:disabled {
|
||||
background-color: #2B2B2B;
|
||||
color: #5A5A5A;
|
||||
border-color: #3F3F3F;
|
||||
}
|
||||
|
||||
QPushButton:default {
|
||||
background-color: #0078D4;
|
||||
border-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QPushButton:default:hover {
|
||||
background-color: #106EBE;
|
||||
border-color: #106EBE;
|
||||
}
|
||||
|
||||
QPushButton:default:pressed {
|
||||
background-color: #005A9E;
|
||||
border-color: #005A9E;
|
||||
}
|
||||
|
||||
/* === QLineEdit === */
|
||||
QLineEdit {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QLineEdit:hover {
|
||||
border-color: #5A5A5A;
|
||||
}
|
||||
|
||||
QLineEdit:focus {
|
||||
background-color: #1F1F1F;
|
||||
border: 2px solid #0078D4;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
QLineEdit:disabled {
|
||||
background-color: #2B2B2B;
|
||||
color: #5A5A5A;
|
||||
border-color: #3F3F3F;
|
||||
}
|
||||
|
||||
QLineEdit[readOnly="true"] {
|
||||
background-color: #2B2B2B;
|
||||
color: #B0B0B0;
|
||||
}
|
||||
|
||||
/* === QTextEdit & QPlainTextEdit === */
|
||||
QTextEdit, QPlainTextEdit {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QTextEdit:hover, QPlainTextEdit:hover {
|
||||
border-color: #5A5A5A;
|
||||
}
|
||||
|
||||
QTextEdit:focus, QPlainTextEdit:focus {
|
||||
border: 2px solid #0078D4;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
QTextEdit:disabled, QPlainTextEdit:disabled {
|
||||
background-color: #2B2B2B;
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QComboBox === */
|
||||
QComboBox {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QComboBox:hover {
|
||||
background-color: #3A3A3A;
|
||||
border-color: #5A5A5A;
|
||||
}
|
||||
|
||||
QComboBox:focus {
|
||||
border: 2px solid #0078D4;
|
||||
}
|
||||
|
||||
QComboBox:disabled {
|
||||
background-color: #2B2B2B;
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
QComboBox::drop-down {
|
||||
border: none;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow {
|
||||
image: url(:/icons/down-arrow.png);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
selection-background-color: #0078D4;
|
||||
selection-color: #FFFFFF;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView::item {
|
||||
min-height: 28px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView::item:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
/* === QSpinBox & QDoubleSpinBox === */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QSpinBox:hover, QDoubleSpinBox:hover {
|
||||
border-color: #5A5A5A;
|
||||
}
|
||||
|
||||
QSpinBox:focus, QDoubleSpinBox:focus {
|
||||
border: 2px solid #0078D4;
|
||||
}
|
||||
|
||||
QSpinBox:disabled, QDoubleSpinBox:disabled {
|
||||
background-color: #2B2B2B;
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
QSpinBox::up-button, QDoubleSpinBox::up-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
QSpinBox::up-button:hover, QDoubleSpinBox::up-button:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QSpinBox::down-button, QDoubleSpinBox::down-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
/* === QCheckBox === */
|
||||
QCheckBox {
|
||||
spacing: 8px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QCheckBox::indicator {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #5A5A5A;
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:hover {
|
||||
background-color: #3A3A3A;
|
||||
border-color: #6A6A6A;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #0078D4;
|
||||
border-color: #0078D4;
|
||||
image: url(:/icons/checkmark.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked:hover {
|
||||
background-color: #106EBE;
|
||||
border-color: #106EBE;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:disabled {
|
||||
background-color: #2B2B2B;
|
||||
border-color: #3F3F3F;
|
||||
}
|
||||
|
||||
QCheckBox:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QRadioButton === */
|
||||
QRadioButton {
|
||||
spacing: 8px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QRadioButton::indicator {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 9px;
|
||||
border: 1px solid #5A5A5A;
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:hover {
|
||||
background-color: #3A3A3A;
|
||||
border-color: #6A6A6A;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked {
|
||||
background-color: #0078D4;
|
||||
border-color: #0078D4;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked:hover {
|
||||
background-color: #106EBE;
|
||||
border-color: #106EBE;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked::after {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:disabled {
|
||||
background-color: #2B2B2B;
|
||||
border-color: #3F3F3F;
|
||||
}
|
||||
|
||||
QRadioButton:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QSlider === */
|
||||
QSlider::groove:horizontal {
|
||||
height: 4px;
|
||||
background-color: #3F3F3F;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #0078D4;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -7px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal:hover {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #106EBE;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal:pressed {
|
||||
background-color: #E0E0E0;
|
||||
}
|
||||
|
||||
QSlider::sub-page:horizontal {
|
||||
background-color: #0078D4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QSlider::groove:vertical {
|
||||
width: 4px;
|
||||
background-color: #3F3F3F;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QSlider::handle:vertical {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #0078D4;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 -7px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
QSlider::sub-page:vertical {
|
||||
background-color: #0078D4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* === QProgressBar === */
|
||||
QProgressBar {
|
||||
background-color: #3F3F3F;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
height: 4px;
|
||||
text-align: center;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background-color: #0078D4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QProgressBar:disabled {
|
||||
background-color: #3F3F3F;
|
||||
}
|
||||
|
||||
/* === QScrollBar === */
|
||||
QScrollBar:horizontal {
|
||||
background-color: transparent;
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
background-color: #5A5A5A;
|
||||
min-width: 40px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:hover {
|
||||
background-color: #6A6A6A;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:pressed {
|
||||
background-color: #7A7A7A;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal,
|
||||
QScrollBar::sub-line:horizontal {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:horizontal,
|
||||
QScrollBar::sub-page:horizontal {
|
||||
background: none;
|
||||
}
|
||||
|
||||
QScrollBar:vertical {
|
||||
background-color: transparent;
|
||||
width: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background-color: #5A5A5A;
|
||||
min-height: 40px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background-color: #6A6A6A;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:pressed {
|
||||
background-color: #7A7A7A;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical,
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* === QTabWidget === */
|
||||
QTabWidget::pane {
|
||||
background-color: #2B2B2B;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
QTabBar::tab {
|
||||
background-color: transparent;
|
||||
color: #B0B0B0;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: 8px 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
QTabBar::tab:hover {
|
||||
color: #FFFFFF;
|
||||
background-color: #3A3A3A;
|
||||
border-bottom: 2px solid #5A5A5A;
|
||||
}
|
||||
|
||||
QTabBar::tab:selected {
|
||||
color: #FFFFFF;
|
||||
background-color: #2B2B2B;
|
||||
border-bottom: 2px solid #0078D4;
|
||||
}
|
||||
|
||||
QTabBar::tab:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QGroupBox === */
|
||||
QGroupBox {
|
||||
background-color: #2B2B2B;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 6px;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top left;
|
||||
padding: 0 8px;
|
||||
color: #FFFFFF;
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
/* === QLabel === */
|
||||
QLabel {
|
||||
background-color: transparent;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QLabel:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QToolButton === */
|
||||
QToolButton {
|
||||
background-color: transparent;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
QToolButton:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QToolButton:pressed {
|
||||
background-color: #1F1F1F;
|
||||
}
|
||||
|
||||
QToolButton:checked {
|
||||
background-color: #0078D4;
|
||||
}
|
||||
|
||||
QToolButton:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QMenu === */
|
||||
QMenu {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QMenu::item {
|
||||
background-color: transparent;
|
||||
padding: 6px 24px 6px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QMenu::item:selected {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QMenu::item:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
QMenu::separator {
|
||||
height: 1px;
|
||||
background-color: #3F3F3F;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
QMenu::icon {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
/* === QMenuBar === */
|
||||
QMenuBar {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border-bottom: 1px solid #3F3F3F;
|
||||
}
|
||||
|
||||
QMenuBar::item {
|
||||
background-color: transparent;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QMenuBar::item:selected {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QMenuBar::item:pressed {
|
||||
background-color: #1F1F1F;
|
||||
}
|
||||
|
||||
/* === QToolBar === */
|
||||
QToolBar {
|
||||
background-color: #2B2B2B;
|
||||
border: none;
|
||||
border-bottom: 1px solid #3F3F3F;
|
||||
spacing: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QToolBar::handle {
|
||||
background-color: #3F3F3F;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
QToolBar::separator {
|
||||
background-color: #3F3F3F;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
/* === QStatusBar === */
|
||||
QStatusBar {
|
||||
background-color: #2B2B2B;
|
||||
color: #B0B0B0;
|
||||
border-top: 1px solid #3F3F3F;
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* === QDockWidget === */
|
||||
QDockWidget {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
titlebar-close-icon: url(:/icons/close.png);
|
||||
titlebar-normal-icon: url(:/icons/float.png);
|
||||
}
|
||||
|
||||
QDockWidget::title {
|
||||
background-color: #2B2B2B;
|
||||
border: 1px solid #3F3F3F;
|
||||
padding: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
QDockWidget::close-button,
|
||||
QDockWidget::float-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QDockWidget::close-button:hover,
|
||||
QDockWidget::float-button:hover {
|
||||
background-color: #3A3A3A;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* === QListView & QListWidget === */
|
||||
QListView, QListWidget {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QListView::item, QListWidget::item {
|
||||
padding: 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QListView::item:hover, QListWidget::item:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QListView::item:selected, QListWidget::item:selected {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QListView::item:disabled, QListWidget::item:disabled {
|
||||
color: #5A5A5A;
|
||||
}
|
||||
|
||||
/* === QTreeView & QTreeWidget === */
|
||||
QTreeView, QTreeWidget {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
show-decoration-selected: 1;
|
||||
}
|
||||
|
||||
QTreeView::item, QTreeWidget::item {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QTreeView::item:hover, QTreeWidget::item:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QTreeView::item:selected, QTreeWidget::item:selected {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QTreeView::branch, QTreeWidget::branch {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QTreeView::branch:closed:has-children, QTreeWidget::branch:closed:has-children {
|
||||
image: url(:/icons/branch-closed.png);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children, QTreeWidget::branch:open:has-children {
|
||||
image: url(:/icons/branch-open.png);
|
||||
}
|
||||
|
||||
/* === QTableView & QTableWidget === */
|
||||
QTableView, QTableWidget {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
gridline-color: #3F3F3F;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 4px;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QTableView::item, QTableWidget::item {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QTableView::item:hover, QTableWidget::item:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QTableView::item:selected, QTableWidget::item:selected {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QHeaderView::section {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
border-right: 1px solid #3F3F3F;
|
||||
border-bottom: 1px solid #3F3F3F;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
QHeaderView::section:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
/* === QDialog === */
|
||||
QDialog {
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
/* === QMessageBox === */
|
||||
QMessageBox {
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
QMessageBox QLabel {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QToolTip === */
|
||||
QToolTip {
|
||||
background-color: #3A3A3A;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #5A5A5A;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
/* === QCalendarWidget === */
|
||||
QCalendarWidget {
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
QCalendarWidget QToolButton {
|
||||
color: #FFFFFF;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QCalendarWidget QToolButton:hover {
|
||||
background-color: #3A3A3A;
|
||||
}
|
||||
|
||||
QCalendarWidget QMenu {
|
||||
background-color: #2B2B2B;
|
||||
}
|
||||
|
||||
QCalendarWidget QSpinBox {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QCalendarWidget QAbstractItemView {
|
||||
background-color: #2B2B2B;
|
||||
color: #FFFFFF;
|
||||
selection-background-color: #0078D4;
|
||||
selection-color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QSplitter === */
|
||||
QSplitter::handle {
|
||||
background-color: #3F3F3F;
|
||||
}
|
||||
|
||||
QSplitter::handle:hover {
|
||||
background-color: #0078D4;
|
||||
}
|
||||
|
||||
QSplitter::handle:horizontal {
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
QSplitter::handle:vertical {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
/* === Custom Classes === */
|
||||
.accent-button {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.accent-button:hover {
|
||||
background-color: #106EBE;
|
||||
}
|
||||
|
||||
.accent-button:pressed {
|
||||
background-color: #005A9E;
|
||||
}
|
||||
|
||||
.danger-button {
|
||||
background-color: #C42B1C;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.danger-button:hover {
|
||||
background-color: #A52314;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #2B2B2B;
|
||||
border: 1px solid #3F3F3F;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.surface {
|
||||
background-color: #2B2B2B;
|
||||
border: 1px solid #3F3F3F;
|
||||
}
|
||||
|
||||
.divider {
|
||||
background-color: #3F3F3F;
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
}
|
||||
@@ -1,890 +0,0 @@
|
||||
/* ===================================================================
|
||||
Fluent Design Light Mode Stylesheet for Qt6
|
||||
Windows 11 inspired light theme
|
||||
=================================================================== */
|
||||
|
||||
/* === Color Palette ===
|
||||
Background: #F3F3F3
|
||||
Surface: #FFFFFF
|
||||
Surface Hover: #F9F9F9
|
||||
Border: #E1DFDD
|
||||
Text: #000000
|
||||
Text Secondary: #605E5C
|
||||
Accent: #0078D4
|
||||
Accent Hover: #106EBE
|
||||
=== */
|
||||
|
||||
/* === Global Styles === */
|
||||
* {
|
||||
font-family: "Segoe UI", "Noto Sans", Roboto, sans-serif;
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
QWidget {
|
||||
background-color: #F3F3F3;
|
||||
color: #000000;
|
||||
selection-background-color: #0078D4;
|
||||
selection-color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QMainWindow === */
|
||||
QMainWindow {
|
||||
background-color: #F3F3F3;
|
||||
}
|
||||
|
||||
QMainWindow::separator {
|
||||
background-color: #E1DFDD;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
QMainWindow::separator:hover {
|
||||
background-color: #0078D4;
|
||||
}
|
||||
|
||||
/* === QPushButton === */
|
||||
QPushButton {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
padding: 6px 16px;
|
||||
min-height: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
background-color: #F9F9F9;
|
||||
border-color: #D1CFCD;
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: #F0F0F0;
|
||||
border-color: #E1DFDD;
|
||||
}
|
||||
|
||||
QPushButton:disabled {
|
||||
background-color: #F9F9F9;
|
||||
color: #A19F9D;
|
||||
border-color: #E1DFDD;
|
||||
}
|
||||
|
||||
QPushButton:default {
|
||||
background-color: #0078D4;
|
||||
border-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QPushButton:default:hover {
|
||||
background-color: #106EBE;
|
||||
border-color: #106EBE;
|
||||
}
|
||||
|
||||
QPushButton:default:pressed {
|
||||
background-color: #005A9E;
|
||||
border-color: #005A9E;
|
||||
}
|
||||
|
||||
/* === QLineEdit === */
|
||||
QLineEdit {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QLineEdit:hover {
|
||||
border-color: #D1CFCD;
|
||||
}
|
||||
|
||||
QLineEdit:focus {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #0078D4;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
QLineEdit:disabled {
|
||||
background-color: #F9F9F9;
|
||||
color: #A19F9D;
|
||||
border-color: #E1DFDD;
|
||||
}
|
||||
|
||||
QLineEdit[readOnly="true"] {
|
||||
background-color: #F9F9F9;
|
||||
color: #605E5C;
|
||||
}
|
||||
|
||||
/* === QTextEdit & QPlainTextEdit === */
|
||||
QTextEdit, QPlainTextEdit {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QTextEdit:hover, QPlainTextEdit:hover {
|
||||
border-color: #D1CFCD;
|
||||
}
|
||||
|
||||
QTextEdit:focus, QPlainTextEdit:focus {
|
||||
border: 2px solid #0078D4;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
QTextEdit:disabled, QPlainTextEdit:disabled {
|
||||
background-color: #F9F9F9;
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QComboBox === */
|
||||
QComboBox {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QComboBox:hover {
|
||||
background-color: #F9F9F9;
|
||||
border-color: #D1CFCD;
|
||||
}
|
||||
|
||||
QComboBox:focus {
|
||||
border: 2px solid #0078D4;
|
||||
}
|
||||
|
||||
QComboBox:disabled {
|
||||
background-color: #F9F9F9;
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
QComboBox::drop-down {
|
||||
border: none;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow {
|
||||
image: url(:/icons/down-arrow-light.png);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
selection-background-color: #0078D4;
|
||||
selection-color: #FFFFFF;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView::item {
|
||||
min-height: 28px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView::item:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
/* === QSpinBox & QDoubleSpinBox === */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QSpinBox:hover, QDoubleSpinBox:hover {
|
||||
border-color: #D1CFCD;
|
||||
}
|
||||
|
||||
QSpinBox:focus, QDoubleSpinBox:focus {
|
||||
border: 2px solid #0078D4;
|
||||
}
|
||||
|
||||
QSpinBox:disabled, QDoubleSpinBox:disabled {
|
||||
background-color: #F9F9F9;
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
QSpinBox::up-button, QDoubleSpinBox::up-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
QSpinBox::up-button:hover, QDoubleSpinBox::up-button:hover {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
QSpinBox::down-button, QDoubleSpinBox::down-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
/* === QCheckBox === */
|
||||
QCheckBox {
|
||||
spacing: 8px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
QCheckBox::indicator {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #8A8886;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:hover {
|
||||
background-color: #F9F9F9;
|
||||
border-color: #605E5C;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #0078D4;
|
||||
border-color: #0078D4;
|
||||
image: url(:/icons/checkmark-white.png);
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked:hover {
|
||||
background-color: #106EBE;
|
||||
border-color: #106EBE;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:disabled {
|
||||
background-color: #F9F9F9;
|
||||
border-color: #E1DFDD;
|
||||
}
|
||||
|
||||
QCheckBox:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QRadioButton === */
|
||||
QRadioButton {
|
||||
spacing: 8px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
QRadioButton::indicator {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 9px;
|
||||
border: 1px solid #8A8886;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:hover {
|
||||
background-color: #F9F9F9;
|
||||
border-color: #605E5C;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked {
|
||||
background-color: #0078D4;
|
||||
border-color: #0078D4;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked:hover {
|
||||
background-color: #106EBE;
|
||||
border-color: #106EBE;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked::after {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:disabled {
|
||||
background-color: #F9F9F9;
|
||||
border-color: #E1DFDD;
|
||||
}
|
||||
|
||||
QRadioButton:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QSlider === */
|
||||
QSlider::groove:horizontal {
|
||||
height: 4px;
|
||||
background-color: #E1DFDD;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #0078D4;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -7px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal:hover {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #106EBE;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal:pressed {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
QSlider::sub-page:horizontal {
|
||||
background-color: #0078D4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QSlider::groove:vertical {
|
||||
width: 4px;
|
||||
background-color: #E1DFDD;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QSlider::handle:vertical {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px solid #0078D4;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 -7px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
QSlider::sub-page:vertical {
|
||||
background-color: #0078D4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* === QProgressBar === */
|
||||
QProgressBar {
|
||||
background-color: #E1DFDD;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
height: 4px;
|
||||
text-align: center;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background-color: #0078D4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QProgressBar:disabled {
|
||||
background-color: #E1DFDD;
|
||||
}
|
||||
|
||||
/* === QScrollBar === */
|
||||
QScrollBar:horizontal {
|
||||
background-color: transparent;
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
background-color: #C8C6C4;
|
||||
min-width: 40px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:hover {
|
||||
background-color: #A19F9D;
|
||||
}
|
||||
|
||||
QScrollBar::handle:horizontal:pressed {
|
||||
background-color: #8A8886;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal,
|
||||
QScrollBar::sub-line:horizontal {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:horizontal,
|
||||
QScrollBar::sub-page:horizontal {
|
||||
background: none;
|
||||
}
|
||||
|
||||
QScrollBar:vertical {
|
||||
background-color: transparent;
|
||||
width: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background-color: #C8C6C4;
|
||||
min-height: 40px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background-color: #A19F9D;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:pressed {
|
||||
background-color: #8A8886;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical,
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* === QTabWidget === */
|
||||
QTabWidget::pane {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
QTabBar::tab {
|
||||
background-color: transparent;
|
||||
color: #605E5C;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: 8px 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
QTabBar::tab:hover {
|
||||
color: #000000;
|
||||
background-color: #F9F9F9;
|
||||
border-bottom: 2px solid #C8C6C4;
|
||||
}
|
||||
|
||||
QTabBar::tab:selected {
|
||||
color: #000000;
|
||||
background-color: #FFFFFF;
|
||||
border-bottom: 2px solid #0078D4;
|
||||
}
|
||||
|
||||
QTabBar::tab:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QGroupBox === */
|
||||
QGroupBox {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 6px;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top left;
|
||||
padding: 0 8px;
|
||||
color: #000000;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QLabel === */
|
||||
QLabel {
|
||||
background-color: transparent;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
QLabel:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QToolButton === */
|
||||
QToolButton {
|
||||
background-color: transparent;
|
||||
color: #000000;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
QToolButton:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QToolButton:pressed {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
QToolButton:checked {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QToolButton:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QMenu === */
|
||||
QMenu {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QMenu::item {
|
||||
background-color: transparent;
|
||||
padding: 6px 24px 6px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QMenu::item:selected {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QMenu::item:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
QMenu::separator {
|
||||
height: 1px;
|
||||
background-color: #E1DFDD;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
QMenu::icon {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
/* === QMenuBar === */
|
||||
QMenuBar {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border-bottom: 1px solid #E1DFDD;
|
||||
}
|
||||
|
||||
QMenuBar::item {
|
||||
background-color: transparent;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QMenuBar::item:selected {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QMenuBar::item:pressed {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
/* === QToolBar === */
|
||||
QToolBar {
|
||||
background-color: #FFFFFF;
|
||||
border: none;
|
||||
border-bottom: 1px solid #E1DFDD;
|
||||
spacing: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QToolBar::handle {
|
||||
background-color: #E1DFDD;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
QToolBar::separator {
|
||||
background-color: #E1DFDD;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
/* === QStatusBar === */
|
||||
QStatusBar {
|
||||
background-color: #FFFFFF;
|
||||
color: #605E5C;
|
||||
border-top: 1px solid #E1DFDD;
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* === QDockWidget === */
|
||||
QDockWidget {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
titlebar-close-icon: url(:/icons/close-light.png);
|
||||
titlebar-normal-icon: url(:/icons/float-light.png);
|
||||
}
|
||||
|
||||
QDockWidget::title {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E1DFDD;
|
||||
padding: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
QDockWidget::close-button,
|
||||
QDockWidget::float-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QDockWidget::close-button:hover,
|
||||
QDockWidget::float-button:hover {
|
||||
background-color: #F9F9F9;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* === QListView & QListWidget === */
|
||||
QListView, QListWidget {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QListView::item, QListWidget::item {
|
||||
padding: 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QListView::item:hover, QListWidget::item:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QListView::item:selected, QListWidget::item:selected {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QListView::item:disabled, QListWidget::item:disabled {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
||||
/* === QTreeView & QTreeWidget === */
|
||||
QTreeView, QTreeWidget {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
show-decoration-selected: 1;
|
||||
}
|
||||
|
||||
QTreeView::item, QTreeWidget::item {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QTreeView::item:hover, QTreeWidget::item:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QTreeView::item:selected, QTreeWidget::item:selected {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QTreeView::branch, QTreeWidget::branch {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QTreeView::branch:closed:has-children, QTreeWidget::branch:closed:has-children {
|
||||
image: url(:/icons/branch-closed-light.png);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children, QTreeWidget::branch:open:has-children {
|
||||
image: url(:/icons/branch-open-light.png);
|
||||
}
|
||||
|
||||
/* === QTableView & QTableWidget === */
|
||||
QTableView, QTableWidget {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
gridline-color: #E1DFDD;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QTableView::item, QTableWidget::item {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QTableView::item:hover, QTableWidget::item:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QTableView::item:selected, QTableWidget::item:selected {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QHeaderView::section {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
border-right: 1px solid #E1DFDD;
|
||||
border-bottom: 1px solid #E1DFDD;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
QHeaderView::section:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
/* === QDialog === */
|
||||
QDialog {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QMessageBox === */
|
||||
QMessageBox {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QMessageBox QLabel {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* === QToolTip === */
|
||||
QToolTip {
|
||||
background-color: #F9F9F9;
|
||||
color: #000000;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
/* === QCalendarWidget === */
|
||||
QCalendarWidget {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QCalendarWidget QToolButton {
|
||||
color: #000000;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QCalendarWidget QToolButton:hover {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
QCalendarWidget QMenu {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
QCalendarWidget QSpinBox {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
selection-background-color: #0078D4;
|
||||
}
|
||||
|
||||
QCalendarWidget QAbstractItemView {
|
||||
background-color: #FFFFFF;
|
||||
color: #000000;
|
||||
selection-background-color: #0078D4;
|
||||
selection-color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* === QSplitter === */
|
||||
QSplitter::handle {
|
||||
background-color: #E1DFDD;
|
||||
}
|
||||
|
||||
QSplitter::handle:hover {
|
||||
background-color: #0078D4;
|
||||
}
|
||||
|
||||
QSplitter::handle:horizontal {
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
QSplitter::handle:vertical {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
/* === Custom Classes === */
|
||||
.accent-button {
|
||||
background-color: #0078D4;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.accent-button:hover {
|
||||
background-color: #106EBE;
|
||||
}
|
||||
|
||||
.accent-button:pressed {
|
||||
background-color: #005A9E;
|
||||
}
|
||||
|
||||
.danger-button {
|
||||
background-color: #C42B1C;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.danger-button:hover {
|
||||
background-color: #A52314;
|
||||
}
|
||||
|
||||
.success-button {
|
||||
background-color: #107C10;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.success-button:hover {
|
||||
background-color: #0E6B0E;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E1DFDD;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.surface {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E1DFDD;
|
||||
}
|
||||
|
||||
.divider {
|
||||
background-color: #E1DFDD;
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
}
|
||||
|
||||
.secondary-text {
|
||||
color: #605E5C;
|
||||
}
|
||||
|
||||
.disabled-text {
|
||||
color: #A19F9D;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 1.4 KiB |
1
resources/connect.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.25 4a.75.75 0 0 1 .743.648L9 4.75v2.773l1.874 2.815a.75.75 0 0 1 .117.306l.009.11v4.496a.75.75 0 0 1-.649.743L10.25 16H8.996v3.254a.75.75 0 0 1-1.492.101l-.007-.101L7.496 16 5.5 15.999v3.258a.75.75 0 0 1-1.493.101l-.006-.101L4 15.999 2.75 16a.75.75 0 0 1-.742-.648l-.007-.102v-4.496a.75.75 0 0 1 .071-.32l.055-.096 1.874-2.815V4.75a.75.75 0 0 1 1.493-.102l.007.102v3a.75.75 0 0 1-.072.32l-.054.096-1.874 2.815V14.5H9.5v-3.52L7.625 8.167a.75.75 0 0 1-.117-.306L7.5 7.75v-3A.75.75 0 0 1 8.25 4Zm7.004.001h4.496a.75.75 0 0 1 .743.649l.007.101L20.499 8h.75a.75.75 0 0 1 .744.648L22 8.75v4.496c0 .111-.025.22-.072.32l-.054.096L20 16.477v2.773a.75.75 0 0 1-1.494.102l-.006-.102v-3c0-.11.024-.22.071-.32l.054-.096L20.5 13.02V9.5h-5.998v3.52l1.874 2.814a.749.749 0 0 1 .118.306l.008.11v3a.75.75 0 0 1-1.493.102l-.007-.102v-2.773l-1.874-2.815a.75.75 0 0 1-.118-.306l-.008-.11V8.75a.75.75 0 0 1 .648-.743L13.752 8h.752V4.751a.75.75 0 0 1 .649-.743l.101-.007h4.496-4.496ZM19 5.501h-2.996V8h2.995V5.501Z" fill="#888888"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 1.7 KiB |
1
resources/exit.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2Zm0 1.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17Zm3.446 4.897.084.073a.75.75 0 0 1 .073.976l-.073.084L13.061 12l2.47 2.47a.75.75 0 0 1 .072.976l-.073.084a.75.75 0 0 1-.976.073l-.084-.073L12 13.061l-2.47 2.47a.75.75 0 0 1-.976.072l-.084-.073a.75.75 0 0 1-.073-.976l.073-.084L10.939 12l-2.47-2.47a.75.75 0 0 1-.072-.976l.073-.084a.75.75 0 0 1 .976-.073l.084.073L12 10.939l2.47-2.47a.75.75 0 0 1 .976-.072Z" fill="#000000"/></svg>
|
||||
|
After Width: | Height: | Size: 599 B |
BIN
resources/exit_red.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
1
resources/exit_red.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2Zm0 1.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17Zm3.446 4.897.084.073a.75.75 0 0 1 .073.976l-.073.084L13.061 12l2.47 2.47a.75.75 0 0 1 .072.976l-.073.084a.75.75 0 0 1-.976.073l-.084-.073L12 13.061l-2.47 2.47a.75.75 0 0 1-.976.072l-.084-.073a.75.75 0 0 1-.073-.976l.073-.084L10.939 12l-2.47-2.47a.75.75 0 0 1-.072-.976l.073-.084a.75.75 0 0 1 .976-.073l.084.073L12 10.939l2.47-2.47a.75.75 0 0 1 .976-.072Z" fill="#FF0000"/></svg>
|
||||
|
After Width: | Height: | Size: 599 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
resources/smile/face-angel.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
resources/smile/face-angry.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
resources/smile/face-cool.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
resources/smile/face-crying.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
resources/smile/face-embarrassed.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/smile/face-glasses.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
resources/smile/face-kiss.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
resources/smile/face-laugh.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
resources/smile/face-monkey.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
resources/smile/face-plain.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/smile/face-raspberry.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
resources/smile/face-sad.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/smile/face-sick.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
resources/smile/face-smile-big.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/smile/face-smile.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
resources/smile/face-smirk.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/smile/face-surprise.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 514 KiB |
BIN
resources/sync.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
1
resources/sync.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M16 8.25a.75.75 0 0 1 1.5 0v3.25a.75.75 0 0 1-.75.75H14a.75.75 0 0 1 0-1.5h1.27A3.502 3.502 0 0 0 12 8.5c-1.093 0-2.037.464-2.673 1.23a.75.75 0 1 1-1.154-.96C9.096 7.66 10.463 7 12 7c1.636 0 3.088.785 4 2v-.75ZM8 15v.75a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 .75-.75H10a.75.75 0 0 1 0 1.5H8.837a3.513 3.513 0 0 0 5.842.765.75.75 0 1 1 1.142.972A5.013 5.013 0 0 1 8 15Zm4-13C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2Zm8.5 10a8.5 8.5 0 1 1-17 0 8.5 8.5 0 0 1 17 0Z" fill="#888888"/></svg>
|
||||
|
After Width: | Height: | Size: 609 B |