Merge branch 'master' into features/effectnode

This commit is contained in:
Uwe Rathmann 2024-09-11 18:21:39 +02:00
commit 621923c5dd
277 changed files with 4573 additions and 4418 deletions

View File

@ -175,7 +175,7 @@ jobs:
}
- {
name: "macOS Latest Clang Qt5",
os: macos-latest,
os: macos-13,
artifact: "macos_clang.7z",
build_type: "Release",
cc: "clang",
@ -277,7 +277,8 @@ jobs:
- name: Install dependencies on macos
if: startsWith(matrix.config.os, 'macos')
run: |
brew install p7zip cmake ninja
find /opt/homebrew/ -name EXTERNALLY-MANAGED|xargs rm
brew install cmake ninja
ninja --version
cmake --version
@ -322,7 +323,7 @@ jobs:
- name: Install Qt5
if: endsWith(matrix.config.name, 'Qt5')
uses: jurplel/install-qt-action@v3
uses: jurplel/install-qt-action@v4
with:
version: "5.15.2"
target: "desktop"
@ -336,7 +337,7 @@ jobs:
- name: Install Qt6
if: endsWith(matrix.config.name, 'Qt6')
uses: jurplel/install-qt-action@v3
uses: jurplel/install-qt-action@v4
with:
version: "6.5.0"
target: "desktop"
@ -430,7 +431,7 @@ jobs:
if: startsWith(matrix.config.name, 'Ubuntu')
run: |
killall iotdashboard
killall Xvfb
# killall Xvfb
- name: Configure ( CMake Integration Test )
shell: bash
@ -446,6 +447,8 @@ jobs:
-DQSkinny_DIR:PATH=$GITHUB_WORKSPACE/qskinny_install/lib/cmake/QSkinny
- name: Build ( CMake Integration Test )
env:
DISPLAY: ":1"
shell: bash
run: cmake --build qskinny_build_test --config ${{ matrix.config.build_type }}

View File

@ -130,6 +130,22 @@ install(
COMPONENT
Devel)
# install cmake helper scripts
install(
FILES
${QSK_CMAKE_DIR}/scripts/QSkinnySvg2Qvg.lin.sh
${QSK_CMAKE_DIR}/scripts/QSkinnySvg2Qvg.mac.sh
${QSK_CMAKE_DIR}/scripts/QSkinnySvg2Qvg.win.bat
DESTINATION
${PACKAGE_LOCATION}/scripts
PERMISSIONS
OWNER_READ OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
COMPONENT
Devel)
# Build other libraries
if(BUILD_QML_EXPORT)
add_subdirectory(qmlexport)

View File

@ -19,3 +19,13 @@ b) Cassowary constraint solving algorithm
Code: https://github.com/nucleic/kiwi
SPDX-License-Identifier: BSD 3-Clause "New" or "Revised" License
Copyright (c) 2013, Nucleic Development Team
c) Material3 Icons
Code: https://github.com/marella/material-design-icons
SPDX-License-Identifier: Apache License 2.0
d) Fluent2 Icons
Code: https://github.com/microsoft/fluentui-system-icons
SPDX-License-Identifier: MIT License

View File

@ -1,3 +1,4 @@
include("${CMAKE_CURRENT_LIST_DIR}/QSkinnyTargets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/QSkinnyTools.cmake" OPTIONAL)
include("${CMAKE_CURRENT_LIST_DIR}/QSkinnyToolsTargets.cmake" OPTIONAL)
include("${CMAKE_CURRENT_LIST_DIR}/QSkinnyQmlExportTargets.cmake" OPTIONAL)

View File

@ -8,11 +8,41 @@
function(qsk_svg2qvg SVG_FILENAME QVG_FILENAME)
get_filename_component(QVG_FILENAME ${QVG_FILENAME} ABSOLUTE)
get_filename_component(SVG_FILENAME ${SVG_FILENAME} ABSOLUTE)
if(TARGET Qt6::Svg)
set(QtSvgTarget Qt6::Svg)
elseif(TARGET Qt5::Svg)
set(QtSvgTarget Qt5::Svg)
endif()
# find svg2qvg target location
get_target_property(Svg2QvgLocation Qsk::Svg2Qvg LOCATION)
get_filename_component(Svg2QvgDirectory ${Svg2QvgLocation} DIRECTORY)
message(STATUS "Svg2QvgLocation: ${Svg2QvgLocation}")
message(STATUS "Svg2QvgDirectory: ${Svg2QvgDirectory}")
# find qt svg target location
get_target_property(QtSvgTargetLocation ${QtSvgTarget} LOCATION)
get_filename_component(QtSvgTargetDirectory ${QtSvgTargetLocation} DIRECTORY)
message(STATUS "QtSvgTargetLocation: ${QtSvgTargetLocation}")
message(STATUS "QtSvgTargetDirectory: ${QtSvgTargetDirectory}")
# select platform specific wrapper script
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(script ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/scripts/QSkinnySvg2Qvg.win.bat)
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
set(script ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/scripts/QSkinnySvg2Qvg.mac.sh)
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(script ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/scripts/QSkinnySvg2Qvg.lin.sh)
else()
message(FATAL "Unsupported operating system")
endif()
add_custom_command(
COMMAND svg2qvg ${SVG_FILENAME} ${QVG_FILENAME}
COMMAND ${script} ${Svg2QvgLocation} ${SVG_FILENAME} ${QVG_FILENAME} ${QtSvgTargetDirectory}
OUTPUT ${QVG_FILENAME}
DEPENDS ${SVG_FILENAME}
WORKING_DIRECTORY $<TARGET_FILE_DIR:${Qt}::Svg>
COMMENT "Compiling ${SVG_FILENAME} to ${QVG_FILENAME}")
COMMENT "Compiling ${SVG_FILENAME} to ${QVG_FILENAME}"
VERBATIM)
endfunction()

View File

@ -0,0 +1,7 @@
#!/bin/bash
SVG2QVG=$1
SVG=$2
QVG=$3
LD_LIBRARY_PATH=$4:$LD_LIBRARY_PATH $SVG2QVG $SVG $QVG

View File

@ -0,0 +1,10 @@
#!/bin/bash
SVG2QVG=$1
SVG=$2
QVG=$3
export DYLD_LIBRARY_PATH=$4:$DYLD_LIBRARY_PATH
otool -L $SVG2QVG
DYLD_LIBRARY_PATH=$4:$DYLD_LIBRARY_PATH $SVG2QVG $SVG $QVG

View File

@ -0,0 +1,6 @@
set SVG2QVG=%1
set SVG=%2
set QVG=%3
set PATH=%4;%PATH%
%SVG2QVG% %SVG% %QVG%

View File

@ -9,7 +9,7 @@ set(SOURCES
QskFluent2Skin.h QskFluent2Skin.cpp
QskFluent2SkinFactory.h QskFluent2SkinFactory.cpp
)
qt_add_resources(SOURCES icons.qrc)
qt_add_resources(SOURCES QskFluent2Icons.qrc)
qsk_add_plugin(fluent2skin skins QskFluent2SkinFactory ${SOURCES})
set_target_properties(fluent2skin PROPERTIES DEFINE_SYMBOL QSK_FLUENT2_MAKEDLL )

View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/fluent2">
<file>icons/qvg/checkmark.qvg</file>
<file>icons/qvg/chevron_down.qvg</file>
<file>icons/qvg/chevron_up.qvg</file>
</qresource>
</RCC>

View File

@ -56,6 +56,7 @@
#include <QskCheckBox.h>
#include <QskComboBox.h>
#include <QskDialogButtonBox.h>
#include <QskDialogSubWindow.h>
#include <QskDrawer.h>
#include <QskFocusIndicator.h>
#include <QskGraphicLabel.h>
@ -94,27 +95,53 @@
#include <QskGraphicIO.h>
#include <QskMargins.h>
#include <QskRgbValue.h>
#include <QskFontRole.h>
#include <QskNamespace.h>
#include <QskPlatform.h>
#include <QGuiApplication>
#include <QScreen>
#include <qguiapplication.h>
#include <qfontinfo.h>
static void qskFluent2InitResources()
{
Q_INIT_RESOURCE( QskFluent2Icons );
}
Q_CONSTRUCTOR_FUNCTION( qskFluent2InitResources )
namespace Fluent2
{
using F = QskFontRole;
/*
Fluent2/Windows font roles according to:
https://fluent2.microsoft.design/typography
*/
constexpr F Caption = { F::Caption, F::Normal };
constexpr F Body = { F::Body, F::Normal };
constexpr F BodyStrong = { F::Body, F::High };
constexpr F BodyStronger = { F::Body, F::VeryHigh };
constexpr F Subtitle = { F::Subtitle, F::Normal };
constexpr F Title = { F::Title, F::Normal };
constexpr F LargeTitle = { F::Headline, F::Normal };
constexpr F Display = { F::Display, F::Normal };
}
namespace
{
inline QFont createFont( const QString& name, qreal lineHeight,
qreal size, qreal tracking, QFont::Weight weight )
Q_DECL_UNUSED inline double operator ""_px( long double value )
{
QFont font( name, qRound( size ) );
font.setPixelSize( qRound( lineHeight ) );
return qskPxToPixels( static_cast< qreal >( value ) );
}
if( !qskFuzzyCompare( tracking, 0.0 ) )
font.setLetterSpacing( QFont::AbsoluteSpacing, tracking );
font.setWeight( weight );
return font;
Q_DECL_UNUSED inline double operator ""_px( unsigned long long value )
{
return qskPxToPixels( value );
}
inline constexpr QRgb rgbGray( int value, qreal opacity = 1.0 )
@ -197,6 +224,7 @@ namespace
private:
void setupPopup( const QskFluent2Theme& );
void setupSubWindow( const QskFluent2Theme& );
void setupDialogSubWindow( const QskFluent2Theme& );
void setupBoxMetrics();
void setupBoxColors( QskAspect::Section, const QskFluent2Theme& );
@ -338,6 +366,7 @@ void Editor::setupColors( QskAspect::Section section, const QskFluent2Theme& the
// TODO
setupPopup( theme );
setupSubWindow( theme );
setupDialogSubWindow( theme );
}
setupBoxColors( section, theme );
@ -384,15 +413,14 @@ void Editor::setupCheckBoxMetrics()
{
using Q = QskCheckBox;
setStrutSize( Q::Panel, 126, 38 );
setSpacing( Q::Panel, 8 );
setStrutSize( Q::Panel, 126_px, 38_px );
setSpacing( Q::Panel, 8_px );
setStrutSize( Q::Box, { 20, 20 } ); // 18 + 2*1 border
setBoxShape( Q::Box, 4 ); // adapt to us taking the border into account
setBoxBorderMetrics( Q::Box, 1 );
setPadding( Q::Box, 5 ); // "icon size"
setStrutSize( Q::Box, { 20_px, 20_px } ); // 18 + 2*1 border
setBoxShape( Q::Box, 4_px ); // adapt to us taking the border into account
setBoxBorderMetrics( Q::Box, 1_px );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
}
void Editor::setupCheckBoxColors(
@ -508,23 +536,23 @@ void Editor::setupComboBoxMetrics()
{
using Q = QskComboBox;
setStrutSize( Q::Panel, { -1, 32 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 3 );
setPadding( Q::Panel, { 11, 0, 11, 0 } );
setStrutSize( Q::Panel, { -1, 32_px } );
setBoxBorderMetrics( Q::Panel, 1_px );
setBoxShape( Q::Panel, 3_px );
setPadding( Q::Panel, { 11_px, 0_px, 11_px, 0_px } );
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 0, 0, 8, 0 } );
setStrutSize( Q::Icon, 12_px, 12_px );
setPadding( Q::Icon, { 0, 0, 8_px, 0 } );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
setStrutSize( Q::StatusIndicator, 12, 12 );
setSymbol( Q::StatusIndicator, symbol( "spin-box-arrow-down" ) );
setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "spin-box-arrow-up" ) );
setStrutSize( Q::StatusIndicator, 16_px, 16_px );
setSymbol( Q::StatusIndicator, symbol( "chevron_down" ) );
// setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "chevron_up" ) );
// Using Focused (Pressed doesn't exist yet):
setBoxBorderMetrics( Q::Panel | Q::Focused, { 1, 1, 1, 2 } );
setBoxBorderMetrics( Q::Panel | Q::Focused, { 1_px, 1_px, 1_px, 2_px } );
}
void Editor::setupComboBoxColors(
@ -608,7 +636,7 @@ void Editor::setupComboBoxColors(
void Editor::setupDialogButtonBoxMetrics()
{
setPadding( QskDialogButtonBox::Panel, 20 );
setPadding( QskDialogButtonBox::Panel, 20_px );
}
void Editor::setupDialogButtonBoxColors(
@ -637,9 +665,9 @@ void Editor::setupFocusIndicatorMetrics()
{
using Q = QskFocusIndicator;
setBoxBorderMetrics( Q::Panel, 2 );
setPadding( Q::Panel, 3 );
setBoxShape( Q::Panel, 4 );
setBoxBorderMetrics( Q::Panel, 2_px );
setPadding( Q::Panel, 3_px );
setBoxShape( Q::Panel, 4_px );
}
void Editor::setupFocusIndicatorColors(
@ -666,10 +694,10 @@ void Editor::setupListViewMetrics()
using A = QskAspect;
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed } )
setBoxBorderMetrics( Q::Cell | state | Q::Selected, { 3, 0, 0, 0 } );
setBoxBorderMetrics( Q::Cell | state | Q::Selected, { 3_px, 0, 0, 0 } );
#if 1
// taken from M3 - what are the actual values, TODO ...
setPadding( Q::Cell, { 16, 12, 16, 12 } );
setPadding( Q::Cell, { 16_px, 12_px, 16_px, 12_px } );
#endif
}
@ -756,18 +784,18 @@ void Editor::setupMenuMetrics()
using Q = QskMenu;
using A = QskAspect;
setPadding( Q::Panel, { 4, 6, 4, 6 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 7 );
setPadding( Q::Panel, { 4_px, 6_px, 4_px, 6_px } );
setBoxBorderMetrics( Q::Panel, 1_px );
setBoxShape( Q::Panel, 7_px );
setPadding( Q::Segment, { 0, 10, 10, 10 } );
setSpacing( Q::Segment, 15 );
setBoxBorderMetrics( Q::Segment | Q::Selected, { 3, 0, 0, 0 } );
setPadding( Q::Segment, { 0, 10_px, 10_px, 10_px } );
setSpacing( Q::Segment, 15_px );
setBoxBorderMetrics( Q::Segment | Q::Selected, { 3_px, 0, 0, 0 } );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 8, 8, 0, 8 } );
setStrutSize( Q::Icon, 12_px, 12_px );
setPadding( Q::Icon, { 8_px, 8_px, 0, 8_px } );
setAnimation( Q::Panel | A::Position, 100 );
}
@ -821,8 +849,8 @@ void Editor::setupPageIndicatorMetrics()
using Q = QskPageIndicator;
using A = QskAspect;
setPadding( Q::Panel, 5 );
setSpacing( Q::Panel, 6 );
setPadding( Q::Panel, 5_px );
setSpacing( Q::Panel, 6_px );
// circles, without border
@ -839,7 +867,7 @@ void Editor::setupPageIndicatorMetrics()
- Q::Hovered | Q::Selected : 7
*/
setStrutSize( Q::Bullet, 6, 6 );
setStrutSize( Q::Bullet, 6_px, 6_px );
/*
Using the margin to adjust sizes is a weired type of implementation.
@ -848,7 +876,7 @@ void Editor::setupPageIndicatorMetrics()
for ( auto state : { A::NoState, Q::Disabled } )
{
setMargin( Q::Bullet | state | Q::Selected, 0 );
setMargin( Q::Bullet | state, 1 );
setMargin( Q::Bullet | state, 1_px );
}
}
@ -893,10 +921,10 @@ void Editor::setupProgressBarMetrics()
using Q = QskProgressBar;
using A = QskAspect;
setMetric( Q::Groove | A::Size, 1 );
setMetric( Q::Groove | A::Size, 1_px );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
setMetric( Q::Fill | A::Size, 3 );
setMetric( Q::Fill | A::Size, 3_px );
setBoxShape( Q::Fill, 100, Qt::RelativeSize );
}
@ -920,9 +948,9 @@ void Editor::setupProgressRingMetrics()
static constexpr QskAspect::Variation NormalSize = A::NoVariation;
static constexpr QskAspect::Variation LargeSize = A::Large;
setStrutSize( Q::Fill | SmallSize, { 16, 16 } );
setStrutSize( Q::Fill | NormalSize, { 32, 32 } );
setStrutSize( Q::Fill | LargeSize, { 64, 64 } );
setStrutSize( Q::Fill | SmallSize, { 16_px, 16_px } );
setStrutSize( Q::Fill | NormalSize, { 32_px, 32_px } );
setStrutSize( Q::Fill | LargeSize, { 64_px, 64_px } );
const auto startAngle = 90, spanAngle = -360;
setArcMetrics( Q::Fill | SmallSize, startAngle, spanAngle, 1.5 );
@ -943,19 +971,26 @@ void Editor::setupProgressRingColors(
void Editor::setupPushButtonMetrics()
{
using Q = QskPushButton;
using A = QskAspect;
using W = QskFluent2Skin;
setStrutSize( Q::Panel, { 120, 32 } );
setBoxShape( Q::Panel, 4 );
setBoxBorderMetrics( Q::Panel, 1 );
const qreal h = 32_px;
setStrutSize( Q::Panel, { 120_px, h } );
// 60: not covered by any spec, but 120 is too big for a menu bar
setStrutSize( Q::Panel | A::Header, { 60_px, h } );
setStrutSize( Q::Panel | A::Footer, { 60_px, h } );
setBoxShape( Q::Panel, 4_px );
setBoxBorderMetrics( Q::Panel, 1_px );
setBoxBorderMetrics( Q::Panel | W::Accent | Q::Disabled, 0 );
// Fluent buttons don't really have icons,
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 0, 0, 8, 0 } );
setStrutSize( Q::Icon, 12_px, 12_px );
setPadding( Q::Icon, { 0, 0, 8_px, 0 } );
setFontRole( Q::Text, W::Body );
setFontRole( Q::Text, Fluent2::Body );
}
void Editor::setupPushButtonColors(
@ -1061,8 +1096,8 @@ void Editor::setupRadioBoxMetrics()
{
using Q = QskRadioBox;
setSpacing( Q::Button, 8 );
setStrutSize( Q::Button, { 115, 38 } );
setSpacing( Q::Button, 8_px );
setStrutSize( Q::Button, { 115_px, 38_px } );
/*
We do not have an indicator - states are indicated by the panel border
@ -1075,27 +1110,27 @@ void Editor::setupRadioBoxMetrics()
setBoxShape( Q::CheckIndicator, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::CheckIndicator, 0 );
setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1 );
setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed | Q::Selected, 1 );
setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1_px );
setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed | Q::Selected, 1_px );
setBoxShape( Q::CheckIndicatorPanel, 100, Qt::RelativeSize );
setStrutSize( Q::CheckIndicatorPanel, { 20, 20 } );
setStrutSize( Q::CheckIndicatorPanel, { 20_px, 20_px } );
setBoxBorderMetrics( Q::CheckIndicatorPanel, 1 );
setBoxBorderMetrics( Q::CheckIndicatorPanel, 1_px );
setBoxBorderMetrics( Q::CheckIndicatorPanel | Q::Selected, 0 );
setPadding( Q::CheckIndicatorPanel | Q::Selected, { 5, 5 } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Selected, { 5_px, 5_px } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4, 4 } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Pressed, { 7, 7 } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4_px, 4_px } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Pressed, { 7_px, 7_px } ); // indicator "strut size"
setBoxBorderMetrics( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, 0 );
setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6, 6 } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6_px, 6_px } ); // indicator "strut size"
setBoxBorderMetrics( Q::CheckIndicatorPanel | Q::Disabled | Q::Selected, 0 );
setPadding( Q::CheckIndicatorPanel | Q::Disabled | Q::Selected, { 6, 6 } ); // indicator "strut size"
setPadding( Q::CheckIndicatorPanel | Q::Disabled | Q::Selected, { 6_px, 6_px } ); // indicator "strut size"
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
}
void Editor::setupRadioBoxColors(
@ -1189,11 +1224,11 @@ void Editor::setupScrollViewMetrics()
for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } )
{
setMetric( subControl | A::Size, 6 );
setMetric( subControl | A::Size, 6_px );
// The scrollbar is expanding, when being hovered/pressed
const qreal padding = 4;
const qreal padding = 4_px;
if ( subControl == Q::HorizontalScrollBar )
setPadding( Q::HorizontalScrollBar, 0, padding, 0, 0 );
@ -1217,7 +1252,7 @@ void Editor::setupScrollViewMetrics()
setBoxShape( Q::HorizontalScrollHandle, 100, Qt::RelativeSize );
setBoxShape( Q::VerticalScrollHandle, 100, Qt::RelativeSize );
const auto handleExtent = 40.0;
const auto handleExtent = 40_px;
setStrutSize( Q::HorizontalScrollHandle, handleExtent, 0.0 );
setStrutSize( Q::VerticalScrollHandle, 0.0, handleExtent );
}
@ -1270,20 +1305,20 @@ void Editor::setupSegmentedBarMetrics()
using Q = QskSegmentedBar;
using A = QskAspect;
const QSizeF segmentStrutSize( 120, 32 );
const QSizeF segmentStrutSize( 120_px, 32_px );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderMetrics( Q::Panel, 1_px );
setBoxBorderMetrics( Q::Panel | Q::Selected | Q::Disabled, 0 );
setSpacing( Q::Panel, 8 );
setSpacing( Q::Panel, 8_px );
setStrutSize( Q::Icon, { 12, 12 } );
setStrutSize( Q::Icon, { 12_px, 12_px } );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize );
setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() );
setBoxShape( Q::Segment, 4 );
setPadding( Q::Segment, { 8, 0, 8, 0 } );
setBoxShape( Q::Segment, 4_px );
setPadding( Q::Segment, { 8_px, 0, 8_px, 0 } );
}
void Editor::setupSegmentedBarColors(
@ -1373,7 +1408,7 @@ void Editor::setupSeparatorMetrics()
using Q = QskSeparator;
using A = QskAspect;
setMetric( Q::Panel | A::Size, 1 );
setMetric( Q::Panel | A::Size, 1_px );
setBoxShape( Q::Panel, 0 );
setBoxBorderMetrics( Q::Panel, 0 );
}
@ -1392,7 +1427,7 @@ void Editor::setupSliderMetrics()
using Q = QskSlider;
using A = QskAspect;
const qreal extent = 22;
const qreal extent = 22_px;
setMetric( Q::Panel | A::Size, extent );
setBoxShape( Q::Panel, 0 );
setBoxBorderMetrics( Q::Panel, 0 );
@ -1400,22 +1435,22 @@ void Editor::setupSliderMetrics()
setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) );
setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) );
setMetric( Q::Groove | A::Size, 4 );
setMetric( Q::Groove | A::Size, 4_px );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
setMetric( Q::Fill | A::Size, 4 );
setMetric( Q::Fill | A::Size, 4_px );
setBoxShape( Q::Fill, 100, Qt::RelativeSize );
setStrutSize( Q::Handle, { 22, 22 } );
setStrutSize( Q::Handle, { 22_px, 22_px } );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::Handle, 1 );
setBoxBorderMetrics( Q::Handle, 1_px );
setStrutSize( Q::Ripple, { 12, 12 } );
setStrutSize( Q::Ripple, { 12_px, 12_px } );
setBoxShape( Q::Ripple, 100, Qt::RelativeSize );
setStrutSize( Q::Ripple | Q::Hovered, { 14, 14 } );
setStrutSize( Q::Ripple | Q::Hovered, { 14_px, 14_px } );
setStrutSize( Q::Ripple | Q::Pressed, { 10, 10 } );
setStrutSize( Q::Ripple | Q::Pressed, { 10_px, 10_px } );
}
void Editor::setupSliderColors(
@ -1468,28 +1503,38 @@ void Editor::setupSpinBoxMetrics()
{
using Q = QskSpinBox;
/*
The F2 NumberBox has 2 modes for the Up/Down panels ( a.k.a Spinner ):
- compact ( -> QskSpinBox::UpDownControl )
- inline ( -> QskSpinBox::ButtonsRight )
TODO: in compact mode the panels/indicators are blown up, when being hovered
*/
setHint( Q::Panel | QskAspect::Style, Q::ButtonsRight );
setStrutSize( Q::Panel, { -1, 32 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 3 );
setPadding( Q::Panel, { 11, 0, 11, 0 } );
setAlignment( Q::Text, Qt::AlignLeft );
setFontRole( Q::Text, QskFluent2Skin::Body );
setStrutSize( Q::Panel, { -1, 32_px } );
setBoxBorderMetrics( Q::Panel, 1_px );
setBoxShape( Q::Panel, 3_px );
setPadding( Q::TextPanel, { 11, 5, 0, 0 } );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setFontRole( Q::Text, Fluent2::Body );
setStrutSize( Q::UpPanel, 32, 20 );
setPadding( Q::UpPanel, { 11, 7, 11, 7 } );
setPadding( Q::TextPanel, { 11_px, 0, 11_px, 0 } );
setStrutSize( Q::DownPanel, 34, 20 );
setPadding( Q::DownPanel, { 11, 7, 13, 7 } );
for ( auto panel : { Q::UpPanel, Q::DownPanel } )
setStrutSize( panel, 32_px, 18_px );
setSymbol( Q::UpIndicator, symbol( "spin-box-arrow-up" ) );
setSymbol( Q::DownIndicator, symbol( "spin-box-arrow-down" ) );
setSymbol( Q::UpIndicator, symbol( "chevron_up" ) );
setSymbol( Q::DownIndicator, symbol( "chevron_down" ) );
// Focused (Pressed doesn't exist yet):
setBoxBorderMetrics( Q::Panel | Q::Focused, { 1, 1, 1, 2 } );
setPadding( Q::UpPanel, { 0, 1_px, 0, 0 } );
setPadding( Q::DownPanel, { 0, 0, 0, 1_px } );
#if 0
// QskSpinBox::Pressed is missing yet
setBoxBorderMetrics( Q::Panel | Q::Pressed, { 1_px, 1_px, 1_px, 2_px } );
#endif
}
void Editor::setupSpinBoxColors(
@ -1552,8 +1597,17 @@ void Editor::setupSpinBoxColors(
panelColor = rgbSolid( panelColor, pal.background.solid.base );
setGradient( panel, panelColor );
setBoxBorderGradient( panel, borderColor1, borderColor2, panelColor );
if ( state == Q::Focused )
{
const auto colors = boxBorderColors( panel );
setBoxBorderColors( panel | Q::Decreasing, colors );
setBoxBorderColors( panel | Q::Increasing, colors );
}
setColor( text, textColor );
setGraphicRole( upIndicator, graphicRole );
@ -1574,17 +1628,17 @@ void Editor::setupTabButtonMetrics()
{
using Q = QskTabButton;
setStrutSize( Q::Panel, { -1, 31 } );
setPadding( Q::Panel, { 7, 0, 7, 0 } );
setBoxShape( Q::Panel, { 7, 7, 0, 0 } );
setStrutSize( Q::Panel, { -1, 31_px } );
setPadding( Q::Panel, { 7_px, 0, 7_px, 0 } );
setBoxShape( Q::Panel, { 7_px, 7_px, 0, 0 } );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setBoxBorderMetrics( Q::Panel, { 0, 0, 0, 1 } );
setBoxBorderMetrics( Q::Panel | Q::Checked, { 1, 1, 1, 0 } );
setBoxBorderMetrics( Q::Panel, { 0, 0, 0, 1_px } );
setBoxBorderMetrics( Q::Panel | Q::Checked, { 1_px, 1_px, 1_px, 0 } );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text | Q::Checked, QskFluent2Skin::BodyStrong );
setFontRole( Q::Text, Fluent2::Body );
setFontRole( Q::Text | Q::Checked, Fluent2::BodyStrong );
}
void Editor::setupTabButtonColors(
@ -1654,9 +1708,9 @@ void Editor::setupGraphicLabelMetrics()
{
using Q = QskGraphicLabel;
setPadding( Q::Panel, 10 );
setBoxShape( Q::Panel, 3 );
setBoxBorderMetrics( Q::Panel, 1 );
setPadding( Q::Panel, 10_px );
setBoxShape( Q::Panel, 3_px );
setBoxBorderMetrics( Q::Panel, 1_px );
}
void Editor::setupGraphicLabelColors(
@ -1675,11 +1729,11 @@ void Editor::setupTextLabelMetrics()
{
using Q = QskTextLabel;
setPadding( Q::Panel, 10 );
setBoxShape( Q::Panel, 3 );
setBoxBorderMetrics( Q::Panel, 1 );
setPadding( Q::Panel, 10_px );
setBoxShape( Q::Panel, 3_px );
setBoxBorderMetrics( Q::Panel, 1_px );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
}
void Editor::setupTextLabelColors(
@ -1699,17 +1753,17 @@ void Editor::setupTextInputMetrics()
{
using Q = QskTextInput;
setStrutSize( Q::Panel, { -1, 30 } );
setPadding( Q::Panel, { 11, 0, 11, 0 } );
setStrutSize( Q::Panel, { -1, 30_px } );
setPadding( Q::Panel, { 11_px, 0, 11_px, 0 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderMetrics( Q::Panel, 1_px );
for( const auto& state : { Q::Focused, Q::Editing } )
setBoxBorderMetrics( Q::Panel | state, { 1, 1, 1, 2 } );
setBoxBorderMetrics( Q::Panel | state, { 1_px, 1_px, 1_px, 2_px } );
setBoxShape( Q::Panel, 3 );
setBoxShape( Q::Panel, 3_px );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setFontRole( Q::Text, QskFluent2Skin::Body );
setFontRole( Q::Text, Fluent2::Body );
}
void Editor::setupTextInputColors(
@ -1772,12 +1826,12 @@ void Editor::setupSwitchButtonMetrics()
using Q = QskSwitchButton;
using A = QskAspect;
const QSizeF strutSize( 38, 18 );
const QSizeF strutSize( 38_px, 18_px );
setStrutSize( Q::Groove | A::Horizontal, strutSize );
setStrutSize( Q::Groove | A::Vertical, strutSize.transposed() );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::Groove, 1 );
setBoxBorderMetrics( Q::Groove, 1_px );
setBoxBorderMetrics( Q::Groove | Q::Checked, 0 );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
@ -1786,15 +1840,15 @@ void Editor::setupSwitchButtonMetrics()
{ QskStateCombination::CombinationNoState, Q::Disabled } );
setBoxBorderMetrics( Q::Handle, 0 );
setBoxBorderMetrics( Q::Handle | Q::Checked, 1 );
setBoxBorderMetrics( Q::Handle | Q::Checked, 1_px );
setBoxBorderMetrics( Q::Handle | Q::Disabled | Q::Checked, 0 );
setStrutSize( Q::Handle, 12, 12 );
setStrutSize( Q::Handle, 12_px, 12_px );
setStrutSize( Q::Handle | Q::Hovered, 14, 14,
setStrutSize( Q::Handle | Q::Hovered, 14_px, 14_px,
{ QskStateCombination::CombinationNoState, Q::Checked } );
const QSizeF pressedSize( 17, 14 );
const QSizeF pressedSize( 17_px, 14_px );
setStrutSize( Q::Handle | Q::Pressed | A::Horizontal,
pressedSize, { QskStateCombination::CombinationNoState, Q::Checked } );
@ -1802,7 +1856,7 @@ void Editor::setupSwitchButtonMetrics()
setStrutSize( Q::Handle | Q::Pressed | A::Vertical,
pressedSize.transposed(), { QskStateCombination::CombinationNoState, Q::Checked } );
setStrutSize( Q::Handle | Q::Disabled, 12, 12,
setStrutSize( Q::Handle | Q::Disabled, 12_px, 12_px,
{ QskStateCombination::CombinationNoState, Q::Checked } );
setAnimation( Q::Handle | A::Metric, 100 );
@ -1895,18 +1949,17 @@ void Editor::setupSubWindow( const QskFluent2Theme& theme )
const auto& pal = theme.palette;
setPadding( Q::Panel, { 0, 31, 0, 0 } );
setBoxShape( Q::Panel, 7 );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 7_px );
setBoxBorderMetrics( Q::Panel, 1_px );
setBoxBorderColors( Q::Panel, pal.strokeColor.surface.defaultColor );
setGradient( Q::Panel, pal.background.layer.alt );
setShadowMetrics( Q::Panel, theme.shadow.dialog.metrics );
setShadowColor( Q::Panel, theme.shadow.dialog.color );
setHint( Q::TitleBarPanel | QskAspect::Style, Q::TitleBar | Q::Title );
setPadding( Q::TitleBarPanel, { 24, 31, 24, 0 } );
setHint( Q::TitleBarPanel | QskAspect::Style, Q::NoDecoration );
setPadding( Q::TitleBarPanel, { 24_px, 31_px, 24_px, 0 } );
setFontRole( Q::TitleBarText, QskFluent2Skin::Subtitle );
setFontRole( Q::TitleBarText, Fluent2::Subtitle );
setColor( Q::TitleBarText, pal.fillColor.text.primary );
setAlignment( Q::TitleBarText, Qt::AlignLeft );
setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap );
@ -1914,13 +1967,22 @@ void Editor::setupSubWindow( const QskFluent2Theme& theme )
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
}
void Editor::setupDialogSubWindow( const QskFluent2Theme& )
{
using Q = QskDialogSubWindow;
setFontRole( Q::DialogTitle, Fluent2::Subtitle );
setAlignment( Q::DialogTitle, Qt::AlignLeft | Qt::AlignVCenter );
setTextOptions( Q::DialogTitle, Qt::ElideRight, QskTextOptions::WordWrap );
}
void Editor::setupVirtualKeyboardMetrics()
{
using Q = QskVirtualKeyboard;
setMargin( Q::ButtonPanel, 2 );
setFontRole( Q::ButtonText, QskFluent2Skin::BodyLarge );
setPadding( Q::Panel, 8 );
setMargin( Q::ButtonPanel, 2_px );
setFontRole( Q::ButtonText, Fluent2::BodyStrong );
setPadding( Q::Panel, 8_px );
}
void Editor::setupVirtualKeyboardColors(
@ -1985,13 +2047,13 @@ void QskFluent2Skin::initHints()
{
colors[0].baseColors = { rgbGray( 32 ), rgbGray( 40 ), rgbGray( 28 ) };
colors[0].accentColors = { 0xff0078d4, 0xff0093f9, 0xff60ccfe, 0xff98ecfe };
colors[1].baseColors = { rgbGray( 40 ), rgbGray( 44 ), rgbGray( 28 ) };
colors[1].accentColors = colors[0].accentColors;
}
setupFonts();
Editor editor( &hintTable() );
editor.setupMetrics();
@ -2006,19 +2068,49 @@ void QskFluent2Skin::initHints()
addTheme( QskAspect::Footer, themeHeader );
}
static inline QFont createFont( int size, int lineHeight, QFont::Weight weight )
{
Q_UNUSED( lineHeight ); // TODO ...
const int pixelSize = qRound( qskPxToPixels( size ) );
QFont font( QStringLiteral( "Segoe UI" ), -1, weight );
static bool checkFont = true;
if ( checkFont )
{
const QFontInfo info( font );
if ( info.family() != font.family() )
{
qWarning() << font.family() <<
"not found, using" << info.family() << "instead.";
}
checkFont = false;
}
font.setPixelSize( pixelSize );
return font;
}
void QskFluent2Skin::setupFonts()
{
static QString fontName( QStringLiteral( "Segoe UI Variable" ) );
Inherited::setupFonts( fontName );
// see: https://fluent2.microsoft.design/typography ( Windows )
setFont( Caption, createFont( fontName, 12, 16, 0.0, QFont::Normal ) );
setFont( Body, createFont( fontName, 14, 20, 0.0, QFont::Normal ) );
setFont( BodyStrong, createFont( fontName, 14, 20, 0.0, QFont::DemiBold ) );
setFont( BodyLarge, createFont( fontName, 18, 24, 0.0, QFont::Medium ) );
setFont( Subtitle, createFont( fontName, 20, 28, 0.0, QFont::DemiBold ) );
setFont( Title, createFont( fontName, 28, 36, 0.0, QFont::DemiBold ) );
setFont( TitleLarge, createFont( fontName, 40, 52, 0.0, QFont::DemiBold ) );
setFont( Display, createFont( fontName, 68, 92, 0.0, QFont::DemiBold ) );
setFont( Fluent2::Caption, createFont( 12, 16, QFont::Normal ) );
setFont( Fluent2::Body, createFont( 14, 20, QFont::Normal ) );
setFont( Fluent2::BodyStrong, createFont( 14, 20, QFont::DemiBold ) );
setFont( Fluent2::BodyStronger, createFont( 18, 24, QFont::Normal ) );
setFont( Fluent2::Subtitle, createFont( 20, 28, QFont::DemiBold ) );
setFont( Fluent2::Title, createFont( 28, 36, QFont::Normal ) );
setFont( Fluent2::LargeTitle, createFont( 40, 52, QFont::DemiBold ) );
setFont( Fluent2::Display, createFont( 68, 92, QFont::DemiBold ) );
// to have something for the unused roles
QskSkin::completeFontTable();
}
void QskFluent2Skin::setGraphicColor( GraphicRole role, QRgb rgb )

View File

@ -31,18 +31,6 @@ class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
GraphicRoleFillColorTextSecondary,
};
enum FontRole
{
Caption = TinyFont,
Body = DefaultFont,
BodyStrong = SmallFont,
BodyLarge = MediumFont,
Subtitle = LargeFont,
Title = HugeFont,
TitleLarge,
Display,
};
static constexpr QskAspect::Variation Standard = QskAspect::NoVariation;
static constexpr QskAspect::Variation Accent = QskAspect::Large;

View File

@ -1,10 +0,0 @@
<RCC>
<qresource prefix="/fluent2">
<file>icons/qvg/checkmark.qvg</file>
<file>icons/qvg/combo-box-arrow-closed.qvg</file>
<file>icons/qvg/combo-box-arrow-open.qvg</file>
<file>icons/qvg/segmented-button-check.qvg</file>
<file>icons/qvg/spin-box-arrow-down.qvg</file>
<file>icons/qvg/spin-box-arrow-up.qvg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,10 @@
SVGs have been taken from https://github.com/microsoft/fluentui-system-icons/tree/main/assets.
Icons are available in different sizes. As SVGs can be scaled we only need
one version of them - chosing the '12'.
As we are replacing the colors of the SVGs using graphic filters we set the
color in the SVGs manually to black ( instead of #212121 ). So they are in
line with icons coming from somewhere else.
Names have been shortened ( ic_fluent_xyz_16_regular.svg -> xyz.svg )

View File

@ -1,4 +1,3 @@
<svg width="11" height="8" viewBox="0 0 11 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.00195312 3.49805C0.00195312 3.36133 0.0507812 3.24414 0.148438 3.14648C0.246094 3.04883 0.363281 3 0.5 3C0.636719 3 0.753906 3.04883 0.851562 3.14648L3.5 5.79492L9.14844 0.146484C9.24609 0.0488281 9.36328 0 9.5 0C9.57031 0 9.63477 0.0136719 9.69336 0.0410156C9.75586 0.0644531 9.80859 0.0996094 9.85156 0.146484C9.89844 0.189453 9.93555 0.242187 9.96289 0.304688C9.99023 0.363281 10.0039 0.427734 10.0039 0.498047C10.0039 0.634766 9.95312 0.753906 9.85156 0.855469L3.85156 6.85547C3.75391 6.95312 3.63672 7.00195 3.5 7.00195C3.36328 7.00195 3.24609 6.95312 3.14844 6.85547L0.148438 3.85547C0.0507812 3.75781 0.00195312 3.63867 0.00195312 3.49805Z" fill="black"/>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.85355 3.14645C10.0488 3.34171 10.0488 3.65829 9.85355 3.85355L5.35355 8.35355C5.15829 8.54882 4.84171 8.54882 4.64645 8.35355L2.64645 6.35355C2.45118 6.15829 2.45118 5.84171 2.64645 5.64645C2.84171 5.45118 3.15829 5.45118 3.35355 5.64645L5 7.29289L9.14645 3.14645C9.34171 2.95118 9.65829 2.95118 9.85355 3.14645Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 777 B

After

Width:  |  Height:  |  Size: 444 B

View File

@ -0,0 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.14645 4.64645C2.34171 4.45118 2.65829 4.45118 2.85355 4.64645L6 7.79289L9.14645 4.64645C9.34171 4.45118 9.65829 4.45118 9.85355 4.64645C10.0488 4.84171 10.0488 5.15829 9.85355 5.35355L6.35355 8.85355C6.15829 9.04882 5.84171 9.04882 5.64645 8.85355L2.14645 5.35355C1.95118 5.15829 1.95118 4.84171 2.14645 4.64645Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 444 B

View File

@ -0,0 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.14645 7.35355C2.34171 7.54882 2.65829 7.54882 2.85355 7.35355L6 4.20711L9.14645 7.35355C9.34171 7.54882 9.65829 7.54882 9.85355 7.35355C10.0488 7.15829 10.0488 6.84171 9.85355 6.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645L2.14645 6.64645C1.95118 6.84171 1.95118 7.15829 2.14645 7.35355Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 444 B

View File

@ -1,4 +0,0 @@
<svg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.25 0.5L4 4.25L7.75 0.5H0.25Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 157 B

View File

@ -1,4 +0,0 @@
<svg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.25 0.5L4 4.25L7.75 0.5H0.25Z" transform="rotate(180 4 2.5)" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 187 B

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +0,0 @@
<svg width="14" height="11" viewBox="0 0 14 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.24914 8.12738L1.12164 4.99988L0.0566406 6.05738L4.24914 10.2499L13.2491 1.24988L12.1916 0.192383L4.24914 8.12738Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 246 B

View File

@ -1,4 +0,0 @@
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 1.125C0.5 1.02344 0.537109 0.935547 0.611328 0.861328C0.685547 0.787109 0.773438 0.75 0.875 0.75C0.976562 0.75 1.06445 0.787109 1.13867 0.861328L5 4.7168L8.86133 0.861328C8.93555 0.787109 9.02344 0.75 9.125 0.75C9.22656 0.75 9.31445 0.787109 9.38867 0.861328C9.46289 0.935547 9.5 1.02344 9.5 1.125C9.5 1.22656 9.46289 1.31445 9.38867 1.38867L5.26367 5.51367C5.18945 5.58789 5.10156 5.625 5 5.625C4.89844 5.625 4.81055 5.58789 4.73633 5.51367L0.611328 1.38867C0.537109 1.31445 0.5 1.22656 0.5 1.125Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 631 B

View File

@ -1,4 +0,0 @@
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 4.875C0.5 4.77344 0.537109 4.68555 0.611328 4.61133L4.73633 0.486328C4.81055 0.412109 4.89844 0.375 5 0.375C5.10156 0.375 5.18945 0.412109 5.26367 0.486328L9.38867 4.61133C9.46289 4.68555 9.5 4.77344 9.5 4.875C9.5 4.97656 9.46289 5.06445 9.38867 5.13867C9.31445 5.21289 9.22656 5.25 9.125 5.25C9.02344 5.25 8.93555 5.21289 8.86133 5.13867L5 1.2832L1.13867 5.13867C1.06445 5.21289 0.976562 5.25 0.875 5.25C0.773438 5.25 0.685547 5.21289 0.611328 5.13867C0.537109 5.06445 0.5 4.97656 0.5 4.875Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 625 B

View File

@ -13,8 +13,10 @@
#include <QskComboBox.h>
#include <QskColorFilter.h>
#include <QskDialogButtonBox.h>
#include <QskDialogSubWindow.h>
#include <QskDrawer.h>
#include <QskFocusIndicator.h>
#include <QskFontRole.h>
#include <QskFunctions.h>
#include <QskGraphic.h>
#include <QskGraphicIO.h>
@ -110,6 +112,7 @@ namespace
Q_INVOKABLE void setupCheckBox();
Q_INVOKABLE void setupComboBox();
Q_INVOKABLE void setupDialogButtonBox();
Q_INVOKABLE void setupDialogSubWindow();
Q_INVOKABLE void setupDrawer();
Q_INVOKABLE void setupFocusIndicator();
Q_INVOKABLE void setupGraphicLabel();
@ -142,13 +145,21 @@ namespace
if ( strcmp( name, "checkMark" ) == 0 )
{
graphic.setViewBox( QRectF( 0.0, 0.0, 14.0, 14.0 ) );
QPainterPath path;
path.moveTo( 0.11, 0.47 );
path.lineTo( 0.5, 1.0);
path.lineTo( 1.0, 0.0 );
path.moveTo( 3.5, 7.0 );
path.lineTo( 6.5, 14.0 );
path.lineTo( 11.0, 1.0 );
QPen pen( Qt::black, 2.8 );
pen.setCapStyle( Qt::FlatCap );
pen.setJoinStyle( Qt::BevelJoin );
QPainter painter( &graphic );
painter.setPen( QPen( Qt::black, 0.25 ) );
painter.setRenderHint( QPainter::Antialiasing );
painter.setPen( pen );
painter.drawPath( path );
}
@ -206,19 +217,12 @@ void Editor::setupCheckBox()
}
}
setGraphicRole( Q::Indicator, QskFusionSkin::GraphicNormal );
setGraphicRole( Q::Indicator, QskFusionSkin::GraphicIndicator );
setGraphicRole( Q::Indicator | Q::Disabled, QskFusionSkin::GraphicDisabled );
setGraphicRole( Q::Indicator | Q::Error, QskFusionSkin::GraphicError );
#if 0
// aligning/scaling of the symbols needs to be fixed in the skinlet TODO ..
setPadding( Q::Box, 4_dp );
setPadding( Q::Box, 3_dp );
const auto checkMark = symbol( "checkMark" );
#else
setPadding( Q::Box, 2_dp );
const auto checkMark = QskStandardSymbol::graphic( QskStandardSymbol::CheckMark );
#endif
for ( auto state : { QskAspect::NoState, Q::Disabled } )
{
@ -274,6 +278,7 @@ void Editor::setupComboBox()
setGraphicRole( Q::Icon | Q::Disabled, QskFusionSkin::GraphicDisabled );
setStrutSize( Q::StatusIndicator, 10_dp, 10_dp );
setGraphicRole( Q::StatusIndicator, QskFusionSkin::GraphicIndicator );
setGraphicRole( Q::StatusIndicator | Q::Disabled, QskFusionSkin::GraphicDisabled );
setAlignment( Q::StatusIndicator, Qt::AlignRight | Qt::AlignVCenter );
@ -363,7 +368,6 @@ void Editor::setupTextLabel()
{
using Q = QskTextLabel;
setAlignment( Q::Text, Qt::AlignCenter );
setColor( Q::Text, m_pal.color( QPalette::Active, QPalette::Text ) );
setColor( Q::Text | Q::Disabled, m_pal.color( QPalette::Disabled, QPalette::Text ) );
@ -680,7 +684,7 @@ void Editor::setupPageIndicator()
void Editor::setupPushButton()
{
/*
QC2/Fusion offers flat/highlighted. We could the emphasis variations to
QC2/Fusion offers flat/highlighted. We could the emphasis variations to
have the same: TODO ...
*/
using Q = QskPushButton;
@ -735,6 +739,17 @@ void Editor::setupDialogButtonBox()
setGradient( Q::Panel | Q::Disabled, m_pal.disabled( P::Base ) );
}
void Editor::setupDialogSubWindow()
{
using Q = QskDialogSubWindow;
#if 1
setFontRole( Q::DialogTitle, QskFontRole::Headline );
#endif
setAlignment( Q::DialogTitle, Qt::AlignLeft | Qt::AlignVCenter );
setTextOptions( Q::DialogTitle, Qt::ElideRight, QskTextOptions::WordWrap );
}
void Editor::setupDrawer()
{
using Q = QskDrawer;
@ -846,8 +861,6 @@ void Editor::setupSpinBox()
setPadding( Q::TextPanel, 5_dp );
setBoxShape( Q::TextPanel, 2, 0, 2, 0 );
setColor( Q::Text, m_pal.active( P::Text ) );
setGradient( Q::TextPanel | Q::Disabled, m_pal.disabled( P::Base ) );
setBoxBorderMetrics( Q::TextPanel, 1_dp );
@ -859,6 +872,9 @@ void Editor::setupSpinBox()
Combination( { Q::Increasing, Q::Decreasing, Q::Hovered } ) );
#endif
setColor( Q::Text, m_pal.active( P::Text ) );
setAlignment( Q::Text, Qt::AlignCenter );
setBoxShape( Q::UpPanel, 0, 2_dp, 0, 0 );
setBoxBorderMetrics( Q::UpPanel, 0_dp, 1_dp, 1_dp, 0_dp );
@ -1272,7 +1288,7 @@ void Editor::setupSubWindow()
// TitleBarPanel
setHint( Q::TitleBarPanel | QskAspect::Style, Q::TitleBar | Q::Title );
setHint( Q::TitleBarPanel | QskAspect::Style, Q::NoDecoration );
setMargin( Q::TitleBarPanel, -1 );
setGradient( Q::TitleBarPanel, m_pal.active( P::Mid ) );
@ -1312,7 +1328,10 @@ void QskFusionSkin::initHints()
using P = QPalette;
setupFonts( QStringLiteral( "Roboto" ) );
#if 1
// we should use QApplication::font somehow: TODO ...
setupFontTable( QStringLiteral( "Roboto" ) );
#endif
const QskFusionPalette palette( colorScheme() );
@ -1322,6 +1341,13 @@ void QskFusionSkin::initHints()
setGraphicColor( GraphicError, palette.error );
setGraphicColor( GraphicHighlighted, palette.active( P::HighlightedText ) );
{
auto rgb = palette.darker( P::Active, P::Text, 120 );
rgb = QskRgb::toTransparent( rgb, 180 );
setGraphicColor( GraphicIndicator, rgb );
}
Editor editor( palette, &hintTable() );
editor.setup();
}

View File

@ -24,7 +24,8 @@ class QSK_FUSION_EXPORT QskFusionSkin : public QskSkin
GraphicNormal,
GraphicDisabled,
GraphicHighlighted,
GraphicError
GraphicError,
GraphicIndicator
};
protected:

View File

@ -7,7 +7,7 @@ set(SOURCES
QskMaterial3Global.h QskMaterial3Skin.h QskMaterial3Skin.cpp
QskMaterial3SkinFactory.h QskMaterial3SkinFactory.cpp
)
qt_add_resources(SOURCES icons.qrc)
qt_add_resources(SOURCES QskMaterial3Icons.qrc)
qsk_add_plugin(material3skin skins QskMaterial3SkinFactory ${SOURCES})
set_target_properties(material3skin PROPERTIES DEFINE_SYMBOL QSK_MATERIAL3_MAKEDLL )

View File

@ -0,0 +1,19 @@
<RCC>
<qresource prefix="/m3">
<!-- needed until we have fixed a rendering bug for small icons -->
<file>icons/qvg/check_small.qvg</file>
<file>icons/qvg/combo-box-arrow-closed.qvg</file>
<file>icons/qvg/combo-box-arrow-open.qvg</file>
<file>icons/qvg/segmented-button-check.qvg</file>
<!-- https://github.com/marella/material-design-icons/tree/main/svg/round -->
<file>icons/qvg/add.qvg</file>
<file>icons/qvg/arrow_drop_down.qvg</file>
<file>icons/qvg/arrow_drop_up.qvg</file>
<file>icons/qvg/check.qvg</file>
<file>icons/qvg/remove.qvg</file>
</qresource>
</RCC>

View File

@ -3,6 +3,11 @@
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
/*
Definitions ( where possible ) taken from
https://www.figma.com/file/O4H724CKmUVPocw6JoSUrd/Material-3-Design-Kit-(Community)
*/
#include "QskMaterial3Skin.h"
#include <QskSkinHintTableEditor.h>
@ -12,6 +17,7 @@
#include <QskComboBox.h>
#include <QskColorFilter.h>
#include <QskDialogButtonBox.h>
#include <QskDialogSubWindow.h>
#include <QskDrawer.h>
#include <QskFocusIndicator.h>
#include <QskFunctions.h>
@ -50,15 +56,50 @@
#include <QskMargins.h>
#include <QskHctColor.h>
#include <QskRgbValue.h>
#include <QskFontRole.h>
#include <QskNamespace.h>
#include <QskPlatform.h>
#include <QGuiApplication>
#include <QScreen>
#include <qguiapplication.h>
#include <qfontinfo.h>
static void qskMaterial3InitResources()
{
Q_INIT_RESOURCE( QskMaterial3Icons );
}
Q_CONSTRUCTOR_FUNCTION( qskMaterial3InitResources )
static const int qskDuration = 150;
namespace
{
using F = QskFontRole;
// M3 font roles: https://m3.material.io/styles/typography/type-scale-tokens
constexpr F LabelSmall = { F::Caption, F::Low };
constexpr F LabelMedium = { F::Caption, F::Normal };
constexpr F LabelLarge = { F::Caption, F::High };
constexpr F BodySmall = { F::Body, F::Low };
constexpr F BodyMedium = { F::Body, F::Normal };
constexpr F BodyLarge = { F::Body, F::High };
constexpr F TitleSmall = { F::Title, F::Low };
constexpr F TitleMedium = { F::Title, F::Normal };
constexpr F TitleLarge = { F::Title, F::High };
constexpr F HeadlineSmall = { F::Headline, F::Low };
constexpr F HeadlineMedium = { F::Headline, F::Normal };
constexpr F HeadlineLarge = { F::Headline, F::High };
constexpr F DisplaySmall = { F::Display, F::Low };
constexpr F DisplayMedium = { F::Display, F::Normal };
constexpr F DisplayLarge = { F::Display, F::High };
}
namespace
{
Q_DECL_UNUSED inline double operator ""_dp( long double value )
@ -71,6 +112,15 @@ namespace
return qskDpToPixels( value );
}
class Combination : public QskStateCombination
{
public:
constexpr Combination( const QskAspect::States states )
: QskStateCombination( CombinationNoState, states )
{
}
};
class Editor : private QskSkinHintTableEditor
{
Q_GADGET
@ -93,6 +143,7 @@ namespace
Q_INVOKABLE void setupCheckBox();
Q_INVOKABLE void setupComboBox();
Q_INVOKABLE void setupDialogButtonBox();
Q_INVOKABLE void setupDialogSubWindow();
Q_INVOKABLE void setupDrawer();
Q_INVOKABLE void setupFocusIndicator();
Q_INVOKABLE void setupInputPanel();
@ -129,20 +180,6 @@ namespace
const QskMaterial3Theme& m_pal;
};
QFont createFont( const QString& name, qreal lineHeight,
qreal size, qreal tracking, QFont::Weight weight )
{
QFont font( name, qRound( size ) );
font.setPixelSize( qRound( lineHeight ) );
if( !qskFuzzyCompare( tracking, 0.0 ) )
font.setLetterSpacing( QFont::AbsoluteSpacing, tracking );
font.setWeight( weight );
return font;
}
inline QRgb flattenedColor(
QRgb foregroundColor, QRgb backgroundColor, qreal ratio )
{
@ -268,7 +305,7 @@ void Editor::setupComboBox()
setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleOnSurface );
setColor( Q::Text, m_pal.onSurface );
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setFontRole( Q::Text, BodyMedium );
setStrutSize( Q::StatusIndicator, 12_dp, 12_dp );
setGraphicRole( Q::StatusIndicator, QskMaterial3Skin::GraphicRoleOnSurface );
@ -351,7 +388,7 @@ void Editor::setupMenu()
setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleOnSurface );
setColor( Q::Text, m_pal.onSurface );
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setFontRole( Q::Text, BodyMedium );
setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic );
@ -362,9 +399,7 @@ void Editor::setupTextLabel()
{
using Q = QskTextLabel;
setAlignment( Q::Text, Qt::AlignCenter );
setColor( Q::Text, m_pal.onSurface );
setPadding( Q::Panel, 5_dp );
}
@ -392,7 +427,7 @@ void Editor::setupTextInput()
// ### Also add a pressed state
setColor( Q::Text, m_pal.onSurface );
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setFontRole( Q::Text, BodyMedium );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
const auto disabledPanelColor = QskRgb::toTransparentF( m_pal.onSurface, 0.04 );
@ -553,7 +588,7 @@ void Editor::setupSegmentedBar()
{
// Text
setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge );
setFontRole( Q::Text, LabelLarge );
setTextOptions( Q::Text, Qt::ElideMiddle, QskTextOptions::NoWrap );
setColor( Q::Text, m_pal.onSurface );
@ -566,7 +601,7 @@ void Editor::setupSegmentedBar()
{
// Icon
setSymbol( Q::Icon, symbol( "segmented-button-check" ) );
setSymbol( Q::Icon, symbol( "check" ) );
setStrutSize( Q::Icon, 18_dp, 18_dp );
setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleOnSurface );
@ -630,7 +665,7 @@ void Editor::setupPushButton()
setPadding( Q::Icon, { 0, 0, 8_dp, 0 } );
setGraphicRole( Q::Icon, QskMaterial3Skin::GraphicRoleOnPrimary );
setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge );
setFontRole( Q::Text, LabelLarge );
setPadding( Q::Text, 0 );
setBoxShape( Q::Splash, 40_dp );
@ -779,6 +814,17 @@ void Editor::setupDialogButtonBox()
setBoxBorderMetrics( Q::Panel, 0 );
}
void Editor::setupDialogSubWindow()
{
using Q = QskDialogSubWindow;
#if 1
setFontRole( Q::DialogTitle, BodyLarge );
#endif
setAlignment( Q::DialogTitle, Qt::AlignLeft | Qt::AlignVCenter );
setTextOptions( Q::DialogTitle, Qt::ElideRight, QskTextOptions::WordWrap );
}
void Editor::setupDrawer()
{
using Q = QskDrawer;
@ -851,13 +897,21 @@ void Editor::setupSpinBox()
using Q = QskSpinBox;
setHint( Q::Panel | QskAspect::Style, Q::ButtonsLeftAndRight );
setBoxShape( Q::Panel, 4_dp );
setBoxBorderMetrics( Q::Panel, 1_dp );
setBoxBorderColors( Q::Panel, m_pal.outline );
setBoxBorderColors( Q::Panel | Q::Focused, m_pal.primary,
Combination( { Q::Increasing, Q::Decreasing } ) );
setPadding( Q::Panel, 4_dp );
setSpacing( Q::Panel, 4_dp );
setStrutSize( Q::TextPanel, 80_dp, 40_dp );
setStrutSize( Q::UpPanel, 40_dp,40_dp );
setStrutSize( Q::DownPanel, 40_dp, 40_dp );
setAlignment( Q::Panel, Qt::AlignHCenter );
setAlignment( Q::Text, Qt::AlignCenter );
for( const auto subControl : { Q::DownPanel, Q::UpPanel, Q::TextPanel } )
@ -868,31 +922,31 @@ void Editor::setupSpinBox()
for( const auto subControl : { Q::DownPanel, Q::UpPanel } )
{
setGradient( subControl, m_pal.primary );
setGradient( subControl | Q::Disabled, m_pal.onSurface12 );
setGradient( subControl | Q::Hovered, m_pal.primary8 );
setPadding( subControl, 10 );
}
{
const auto focusColor = flattenedColor( m_pal.onPrimary, m_pal.primary, 0.12 );
setGradient( Q::DownPanel | Q::Decreasing, focusColor );
setGradient( Q::UpPanel | Q::Increasing, focusColor );
setGradient( Q::DownPanel | Q::Decreasing, m_pal.primary12 );
setGradient( Q::UpPanel | Q::Increasing, m_pal.primary12 );
}
setSymbol( Q::UpIndicator, symbol( "combo-box-arrow-open" ) );
setSymbol( Q::DownIndicator, symbol( "combo-box-arrow-closed" ) );
setSymbol( Q::UpIndicator, symbol( "add" ) );
setSymbol( Q::DownIndicator, symbol( "remove" ) );
for( const auto subControl : { Q::DownIndicator, Q::UpIndicator } )
{
setAlignment( subControl, Qt::AlignCenter );
#if 0
setGraphicRole( subControl, QskMaterial3Skin::GraphicRoleOnPrimary );
setGraphicRole( subControl | Q::Disabled, QskMaterial3Skin::GraphicRoleOnSurface38 );
#endif
}
setColor( Q::Text, m_pal.onBackground );
setColor( Q::Text | Q::Disabled, m_pal.onSurface38 );
#if 0
setPadding( Q::TextPanel, 5_dp );
setBoxShape( Q::TextPanel, 4_dp, 4_dp, 0, 0 );
setBoxBorderMetrics( Q::TextPanel, 0, 0, 0, 1_dp );
@ -909,6 +963,7 @@ void Editor::setupSpinBox()
setColor( Q::TextPanel | Q::Disabled, m_pal.onSurface38 );
setBoxBorderColors( Q::TextPanel | Q::Disabled, m_pal.onSurface38 );
#endif
}
void Editor::setupSwitchButton()
@ -1024,7 +1079,7 @@ void Editor::setupTabButton()
setAnimation( Q::Panel | A::Color, qskDuration );
setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge );
setFontRole( Q::Text, LabelLarge );
setAlignment( Q::Text, Qt::AlignCenter );
}
@ -1095,7 +1150,7 @@ void Editor::setupVirtualKeyboard()
setAnimation( Q::ButtonPanel | A::Metric, qskDuration );
setColor( Q::ButtonText, m_pal.onBackground );
setFontRole( Q::ButtonText, QskMaterial3Skin::M3HeadlineSmall );
setFontRole( Q::ButtonText, HeadlineSmall );
// panel
setGradient( Q::Panel, m_pal.background );
@ -1191,7 +1246,7 @@ void Editor::setupListView()
}
}
setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium );
setFontRole( Q::Text, BodyMedium );
setColor( Q::Text, m_pal.onSurface );
setColor( Q::Text | Q::Disabled, m_pal.onSurface38 );
@ -1220,13 +1275,12 @@ void Editor::setupSubWindow()
// TitleBarPanel
setBoxShape( Q::TitleBarPanel, { 28_dp, 28_dp, 0, 0 } );
setPadding( Q::TitleBarPanel, { 24_dp, 24_dp, 24_dp, 16_dp } );
setHint( Q::TitleBarPanel | QskAspect::Style,
Q::TitleBar | Q::Title | Q::Symbol );
setHint( Q::TitleBarPanel | QskAspect::Style, Q::NoDecoration );
setGradient( Q::TitleBarPanel, m_pal.secondaryContainer );
// TitleBarText
setFontRole( Q::TitleBarText, QskMaterial3Skin::M3HeadlineSmall );
setFontRole( Q::TitleBarText, HeadlineSmall );
setColor( Q::TitleBarText, m_pal.onSurface );
setAlignment( Q::TitleBarText, Qt::AlignCenter );
@ -1402,17 +1456,63 @@ QskMaterial3Skin::~QskMaterial3Skin()
{
}
static inline QFont createFont( int size, int lineHeight,
qreal spacing, QFont::Weight weight )
{
Q_UNUSED( lineHeight );
const int pixelSize = qRound( qskDpToPixels( size ) );
QFont font( QStringLiteral( "Roboto" ), -1, weight );
static bool checkFont = true;
if ( checkFont )
{
const QFontInfo info( font );
if ( info.family() != font.family() )
{
qWarning() << font.family() <<
"not found, using" << info.family() << "instead.";
}
checkFont = false;
}
font.setPixelSize( pixelSize );
if ( spacing > 0.0 )
font.setLetterSpacing( QFont::AbsoluteSpacing, spacing );
return font;
}
void QskMaterial3Skin::setupFonts()
{
Inherited::setupFonts( QStringLiteral( "Roboto" ) );
setFont( LabelSmall, createFont( 11, 16, 0.5, QFont::Medium ) );
setFont( LabelMedium, createFont( 12, 16, 0.5, QFont::Medium ) );
setFont( LabelLarge, createFont( 14, 20, 0.1, QFont::Medium ) );
setFont( M3BodyMedium,
createFont( QStringLiteral( "Roboto Regular"), 20_dp, 14_dp, 0.25, QFont::Normal ) );
setFont( M3BodyLarge,
createFont( QStringLiteral( "Roboto Medium" ), 24_dp, 16_dp, 0.5, QFont::Normal ) );
setFont( M3HeadlineSmall,
createFont( QStringLiteral( "Roboto Regular" ), 32_dp, 28_dp, 0.0, QFont::Normal ) );
setFont( M3LabelLarge, createFont( "Roboto Medium", 20_dp, 14_dp, 0.1, QFont::Medium ) );
setFont( BodySmall, createFont( 12, 16, 0.4, QFont::Normal ) );
setFont( BodyMedium, createFont( 14, 20, 0.25, QFont::Normal ) );
setFont( BodyLarge, createFont( 16, 24, 0.5, QFont::Normal ) );
setFont( TitleSmall, createFont( 14, 20, 0.1, QFont::Medium ) );
setFont( TitleMedium, createFont( 16, 24, 0.15, QFont::Medium ) );
setFont( TitleLarge, createFont( 22, 28, 0.0, QFont::Normal ) );
setFont( HeadlineSmall, createFont( 24, 32, 0.0, QFont::Normal ) );
setFont( HeadlineMedium, createFont( 28, 36, 0.0, QFont::Medium ) );
setFont( HeadlineLarge, createFont( 32, 40, 0.0, QFont::Medium ) );
setFont( DisplaySmall, createFont( 36, 44, 0.0, QFont::Normal ) );
setFont( DisplayMedium, createFont( 45, 52, 0.0, QFont::Normal ) );
setFont( DisplayLarge, createFont( 57, 64, 0.0, QFont::Normal ) );
// to have something for the unused roles
setFont( { QskFontRole::Subtitle, QskFontRole::Normal },
createFont( 16, 24, 0.0, QFont::Normal ) );
QskSkin::completeFontTable();
}
void QskMaterial3Skin::setGraphicColor( GraphicRole role, QRgb rgb )

View File

@ -103,9 +103,6 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin
using Inherited = QskSkin;
public:
QskMaterial3Skin( QObject* parent = nullptr );
~QskMaterial3Skin() override;
enum GraphicRole
{
GraphicRoleOnError,
@ -118,13 +115,8 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin
GraphicRoleSurface,
};
enum FontRole
{
M3BodyMedium = DefaultFont,
M3BodyLarge = LargeFont,
M3HeadlineSmall = SmallFont,
M3LabelLarge = HugeFont,
};
QskMaterial3Skin( QObject* parent = nullptr );
~QskMaterial3Skin() override;
static constexpr QskAspect::Variation Filled = QskAspect::NoVariation;
static constexpr QskAspect::Variation Tonal = QskAspect::Huge;

View File

@ -1,8 +0,0 @@
<RCC>
<qresource prefix="/m3">
<file>icons/qvg/check_small.qvg</file>
<file>icons/qvg/combo-box-arrow-closed.qvg</file>
<file>icons/qvg/combo-box-arrow-open.qvg</file>
<file>icons/qvg/segmented-button-check.qvg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18 13h-5v5c0 .55-.45 1-1 1s-1-.45-1-1v-5H6c-.55 0-1-.45-1-1s.45-1 1-1h5V6c0-.55.45-1 1-1s1 .45 1 1v5h5c.55 0 1 .45 1 1s-.45 1-1 1z"/></svg>

After

Width:  |  Height:  |  Size: 232 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m8.71 11.71 2.59 2.59c.39.39 1.02.39 1.41 0l2.59-2.59c.63-.63.18-1.71-.71-1.71H9.41c-.89 0-1.33 1.08-.7 1.71z"/></svg>

After

Width:  |  Height:  |  Size: 211 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M8.71 12.29 11.3 9.7a.996.996 0 0 1 1.41 0l2.59 2.59c.63.63.18 1.71-.71 1.71H9.41c-.89 0-1.33-1.08-.7-1.71z"/></svg>

After

Width:  |  Height:  |  Size: 208 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9 16.17 5.53 12.7a.996.996 0 1 0-1.41 1.41l4.18 4.18c.39.39 1.02.39 1.41 0L20.29 7.71a.996.996 0 1 0-1.41-1.41L9 16.17z"/></svg>

After

Width:  |  Height:  |  Size: 221 B

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18 13H6c-.55 0-1-.45-1-1s.45-1 1-1h12c.55 0 1 .45 1 1s-.45 1-1 1z"/></svg>

After

Width:  |  Height:  |  Size: 167 B

View File

@ -8,7 +8,7 @@
what is needed to support a layout system, that is on par with what
is known from Qt/Widgets.
\todo Explain: QskQuickItem::geometry(), QskQuickItem::rect(),
\todo Explain: QskItem::geometry(), QskItem::rect(),
QQuickItem::boundingRect(), layoutRect(), contentsRect(),
subControlRect(), focusIndicatorRect(), QQuickItem::clipRect(),
QQuickItem::contains()
@ -22,7 +22,7 @@
A state bit that is set, when QQuickItem::isEnabled() == false.
\extends QskAspect::State
\sa QskQuickItem::setDisabled()
\sa QskItem::setDisabled()
\saqt QQuickItem::enabled
\var QskControl::Hovered
@ -71,7 +71,7 @@
\accessors autoLayoutChildren(), setAutoLayoutChildren()
\sa layoutRect(), layoutHints(), layoutAlignmentHint(),
QskQuickItem::transparentForPositioners
QskItem::transparentForPositioners
\saqt QQuickItem::updatePolish()
\note Auto layouting is similar to what happens when putting several items
@ -274,7 +274,7 @@
\aspect QskControl::Background | QskAspect::Color
\sa setBackground()
\sa QskQuickItem::DebugForceBackground
\sa QskItem::DebugForceBackground
*/
/*!
@ -554,7 +554,7 @@
A control has an impact on the layout calutaions, when:
- isTransparentForPositioner() is false
- QskQuickItem::isVisibleToParent() is true, or RetainSizeWhenHidden is set
- QskItem::isVisibleToParent() is true, or RetainSizeWhenHidden is set
\sa isVisibleToParent(), RetainSizeWhenHidden
*/

View File

@ -1,25 +1,25 @@
/*!
\class QskQuickItem QskQuickItem.h
\class QskItem QskItem.h
\ingroup Framework
QskQuickItem completes the C++ API of QQuickItem and re-establishs basic
QskItem completes the C++ API of QQuickItem and re-establishs basic
concepts like events. It also offers better control over the operations
happening in the update cycle.
*/
/*!
\enum QskQuickItem::UpdateFlag
\enum QskItem::UpdateFlag
Qt/Quick classes have a tendency to update items too early
and too often. To avoid processing of unwanted operations
QskQuickItem implements a couple of modifications, that
QskItem implements a couple of modifications, that
can be en/disabled individually.
\sa updateFlags(), resetUpdateFlags()
testUpdateFlag(), setUpdateFlag(), resetUpdateFlag()
\var QskQuickItem::UpdateFlag QskQuickItem::DeferredUpdate
\var QskItem::UpdateFlag QskItem::DeferredUpdate
Creating of scene graph nodes is blocked when being invisible.
@ -37,7 +37,7 @@
such as viewport frustrum culling (i.e. hiding items outside of the
window geometry).
\var QskQuickItem::UpdateFlag QskQuickItem::DeferredPolish
\var QskItem::UpdateFlag QskItem::DeferredPolish
Polishing an item is blocked when being invisible.
F.e for all items being derived from QskControl the layout calculations
@ -45,7 +45,7 @@
\saqt QQuickItem::updatePolish(), QQuickItem::polish()
\var QskQuickItem::UpdateFlag QskQuickItem::DeferredLayout
\var QskItem::UpdateFlag QskItem::DeferredLayout
Recalculations of the implicitSize are blocked until being explicitly requested.
@ -54,15 +54,15 @@
without recalculating the actual size hints ( f.e the implicitSize ).
When having layout code that relies on binding the implicit width/height
the QskQuickItem::DeferredLayout flag needs to be disabled.
the QskItem::DeferredLayout flag needs to be disabled.
\note All layout classes offered by the Qt/Quick modules of the Qt Company
( f.e anchors ) do require immediate updates of the implicit size.
\sa QskQuickItem::resetImplicitSize()
\sa QskItem::resetImplicitSize()
\saqt QQuickItem::implicitSize()
\var QskQuickItem::UpdateFlag QskQuickItem::CleanupOnVisibility
\var QskItem::UpdateFlag QskItem::CleanupOnVisibility
Delete scene graph nodes, when the item becomes hidden.
Enabling this mode will reduce the memory footprint, but comes at the cost
@ -70,12 +70,12 @@
\saqt QQuickItem::isVisible()
\var QskQuickItem::UpdateFlag QskQuickItem::PreferRasterForTextures
\var QskItem::UpdateFlag QskItem::PreferRasterForTextures
When creating textures from QskGraphic, prefer the raster paint
engine over the OpenGL paint engine.
\var QskQuickItem::UpdateFlag QskQuickItem::DebugForceBackground
\var QskItem::UpdateFlag QskItem::DebugForceBackground
Always fill the background of the item with a random color.
@ -84,7 +84,7 @@
*/
/*!
\property QskQuickItem::geometry
\property QskItem::geometry
This property holds the geometry of the item relative to its parent item.
When changing the geometry, the item receives a QskEvent::GeometryChange event.
@ -93,7 +93,7 @@
*/
/*!
\property QskQuickItem::rect
\property QskItem::rect
This property returns the internal geometry of the item.
It equals QRect(0, 0, width(), height() ).
@ -102,7 +102,7 @@
*/
/*!
\var QskQuickItem::transparentForPositioners
\var QskItem::transparentForPositioners
When transparentForPositioners is set the item indicates, that it should be excluded
from any layout calculations. This flag is actually a concept of QQuickItem, that
@ -112,7 +112,7 @@
*/
/*!
\property QskQuickItem::tabFence
\property QskItem::tabFence
The tabFence flag can be used to create local tab focus chains. It is usually
used in combination with QQuickItem::ItemIsFocusScope.
@ -125,7 +125,7 @@
*/
/*!
\property QskQuickItem::visibleToParent
\property QskItem::visibleToParent
Flag indicating if an item would become visible if its parentItem() is shown.
The implementation relies on the internal explicitVisible flag, that has not
@ -142,7 +142,7 @@
*/
/*!
\property QskQuickItem::polishOnResize
\property QskItem::polishOnResize
When polishOnResize is set QQuickItem::polish() will be called automatically
whenever the size of the item has been changed. This is usually necessary
@ -153,7 +153,7 @@
*/
/*!
\property QskQuickItem::initiallyPainted
\property QskItem::initiallyPainted
Status flag indicating that there has already been a call
of QQuickItem::updatePaintNode() since the item has become visible.
@ -165,7 +165,7 @@
*/
/*!
\property QskQuickItem::hasChildItems
\property QskItem::hasChildItems
A property indicating if the item has child items.
@ -173,40 +173,40 @@
*/
/*!
\property QskQuickItem::updateFlags
\property QskItem::updateFlags
QskQuickItem offers several tweaks to the Qt/Quick update cycle,
QskItem offers several tweaks to the Qt/Quick update cycle,
that can be en/disabled individually.
The flags are a combination from bits that have been explicitly set
by setUpdateFlag() and those being derived from the aapplication
wide default settings, that can be set with QskSetup.
\sa QskQuickItem::UpdateFlag, QskQuickItem::updateFlags(), QskSetup::itemUpdateFlags()
\sa QskItem::UpdateFlag, QskItem::updateFlags(), QskSetup::itemUpdateFlags()
*/
/*!
\fn QskQuickItem::QskQuickItem
\fn QskItem::QskItem
Sets the QQuickItem::ItemHasContents flag to true.
*/
*!
\fn QskQuickItem::~QskQuickItem
\fn QskItem::~QskItem
Sets the componentComplete to false, so that its about-to-delete state is known
when detaching it from parent/window.
*/
/*!
\fn QskQuickItem::className
\fn QskItem::className
A convenience wrapper for metaObject()->className()
\return Class name
*/
/*!
\fn QskQuickItem::isVisibleTo
\fn QskItem::isVisibleTo
The true case occurs if neither the item itself nor any parent up to but excluding
ancestor has been explicitly hidden.
@ -218,7 +218,7 @@
*/
/*!
\fn QskQuickItem::isVisibleToParent
\fn QskItem::isVisibleToParent
An item might be invisible because it has been explicitly hidden or
one of its ancestors has been hidden. isVisibleToParent() indicates
@ -231,14 +231,14 @@
*/
/*!
\fn QskQuickItem::hasChildItems() const
\fn QskItem::hasChildItems() const
\return true, if the item has child items
\sa hasChildItems
*/
/*!
\fn QskQuickItem::setGeometry( qreal, qreal, qreal, qreal )
\fn QskItem::setGeometry( qreal, qreal, qreal, qreal )
Set the position and the size of an item
@ -252,7 +252,7 @@
*/
/*!
\fn QskQuickItem::setGeometry( const QPointF &, const QSizeF & )
\fn QskItem::setGeometry( const QPointF &, const QSizeF & )
Set the position and the size of an item
@ -261,7 +261,7 @@
*/
/*!
\fn QskQuickItem::setGeometry( const QRectF& )
\fn QskItem::setGeometry( const QRectF& )
Set the position and the size of an item
@ -272,14 +272,14 @@
*/
/*!
\fn QskQuickItem::geometry() const
\fn QskItem::geometry() const
\return Position and size relative to the parent item
\sa geometry, setGeometry()
*/
/*!
\fn QskQuickItem::geometryChange
\fn QskItem::geometryChange
This overloaded notifier calls QQuickItem::polish() depending on the
polishOnResize() flag and forwards the notification to the event queue.
@ -288,14 +288,14 @@
*/
/*!
\fn QskQuickItem::rect() const
\fn QskItem::rect() const
\return Internal geometry of the item, where the position is always at ( 0, 0 )
\sa geometry
*/
/*!
\fn QskQuickItem::implicitSize
\fn QskItem::implicitSize
Qt/Quick offers an oversimplified layout system that is based on the
property bindings of implicit width and height. QSkinny restablishs a layout
@ -308,56 +308,56 @@
\return Implicit size,
\note Layout code that relies on property bindings of the implicit width a height
needs to disable the QskQuickItem::DeferredLayout flag
needs to disable the QskItem::DeferredLayout flag
\sa QskControl::preferredSize(), QskControl::sizeHint()
\saqt QQuickItem::implicitWidth(), QQuickItem::implicitHeight()
*/
/*!
\fn QskQuickItem::setPolishOnResize
\fn QskItem::setPolishOnResize
Set or clear the polishOnResize flag.
\sa polishOnResize
*/
/*!
\fn QskQuickItem::polishOnResize() const
\fn QskItem::polishOnResize() const
\return Value of the polishOnResize flag
\sa setPolishOnResize()
*/
/*!
\fn QskQuickItem::setTransparentForPositioner
\fn QskItem::setTransparentForPositioner
Set or clear the transparentForPositioner flag
\sa isTransparentForPositioner()
*/
/*!
\fn QskQuickItem::isTransparentForPositioner
\fn QskItem::isTransparentForPositioner
\return Value of the transparentForPositioner flag
\sa transparentForPositioner
*/
/*!
\fn QskQuickItem::setTabFence
\fn QskItem::setTabFence
Set or clear the tabFence property
\sa isTabFence()
*/
/*!
\fn QskQuickItem::isTabFence
\fn QskItem::isTabFence
\return Value of the tabFence property
\sa setTransparentForPositioner()
*/
/*!
\fn QskQuickItem::setLayoutMirroring
\fn QskItem::setLayoutMirroring
Change the direction how the content is laid out horizontally.
@ -373,7 +373,7 @@
*/
/*!
\fn QskQuickItem::resetLayoutMirroring
\fn QskItem::resetLayoutMirroring
Clear the layoutMirroring property
@ -381,7 +381,7 @@
*/
/*!
\fn QskQuickItem::layoutMirroring() const
\fn QskItem::layoutMirroring() const
Direction how the content is layed out horizontally.
@ -402,7 +402,7 @@
*/
/*!
\fn QskQuickItem::resetUpdateFlags
\fn QskItem::resetUpdateFlags
Reset all flags to the default settings
@ -410,16 +410,16 @@
*/
/*!
\fn QskQuickItem::updateFlags() const
\fn QskItem::updateFlags() const
\return Flags affecting the item update process
\sa testUpdateFlag(), setUpdateFlag(), updateFlags
*/
/*!
\fn QskQuickItem::setUpdateFlag
\fn QskItem::setUpdateFlag
QskQuickItem offers several tweaks to the Qt/Quick update cycle,
QskItem offers several tweaks to the Qt/Quick update cycle,
that can be en/disables individually.
The default settings for these flags are taken from QskSetup::itemUpdateFlags()
@ -434,7 +434,7 @@
*/
/*!
\fn QskQuickItem::resetUpdateFlag
\fn QskItem::resetUpdateFlag
Reset the value for flag to the default settings from QskSetup. Future
changes of the corresponding bit with QskSetup::setItemUpdateFlag() will affect
@ -445,7 +445,7 @@
*/
/*!
\fn QskQuickItem::testUpdateFlag
\fn QskItem::testUpdateFlag
\param Flag affecting the item update process
\return true, when the corresponding bit is effective
@ -454,7 +454,7 @@
*/
/*!
\fn QskQuickItem::updateFlagsChanged
\fn QskItem::updateFlagsChanged
Signal indicating, that the effective update flags have changed
@ -463,7 +463,7 @@
*/
/*!
\fn QskQuickItem::classBegin
\fn QskItem::classBegin
The QML engine initializes an item as being incomplete by
explicitly calling classBegin(). Once the item
@ -481,7 +481,7 @@
*/
/*!
\fn QskQuickItem::componentComplete
\fn QskItem::componentComplete
The QML engine initilizes an item as being incomplete by
explicitly calling QQuickItem::classBegin(). Once the item
@ -499,7 +499,7 @@
*/
/*!
\fn QskQuickItem::releaseResources
\fn QskItem::releaseResources
This specific hook is called, when the item is about to be removed
from the window it was previously rendering to.
@ -510,7 +510,7 @@
*/
/*!
\fn QskQuickItem::isPolishScheduled
\fn QskItem::isPolishScheduled
\return True, if the item will be polished in the next
scene graph update cycle.
@ -519,21 +519,21 @@
*/
/*!
\fn QskQuickItem::isUpdateNodeScheduled
\fn QskItem::isUpdateNodeScheduled
\return True, if the item will update the paint node in
the next scene graph update cycle
*/
/*!
\fn QskQuickItem::isInitiallyPainted
\fn QskItem::isInitiallyPainted
\return Value of the initiallyPainted property
\sa initiallyPainted
*/
/*!
\fn QskQuickItem::maybeUnresized
\fn QskItem::maybeUnresized
Flag indicating a potential state, where the item is waiting to be
sized by the layout system.
@ -547,7 +547,7 @@
*/
/*!
\fn QskQuickItem::itemFlagsChanged
\fn QskItem::itemFlagsChanged
Signal indicating that at least one if the following attributes has changed:
@ -557,7 +557,7 @@
*/
/*!
\fn QskQuickItem::show
\fn QskItem::show
An alternative way to call setVisible( true ).
Useful for signal/slot connections
@ -567,7 +567,7 @@
*/
/*!
\fn QskQuickItem::hide
\fn QskItem::hide
An alternative way to call setVisible( false ).
Useful for signal/slot connections
@ -577,7 +577,7 @@
*/
/*!
\fn QskQuickItem::setHidden
\fn QskItem::setHidden
Convenience function, equivalent to setVisible( !on ).
@ -586,19 +586,19 @@
*/
/*!
\fn QskQuickItem::setDisabled
\fn QskItem::setDisabled
Convenience function, equivalent to setEnabled( !on ).
\saqt QQuickItem::setEnabled()
*/
/*!
\fn QskQuickItem::resetImplicitSize
\fn QskItem::resetImplicitSize
Notifies the layout system that attributes affecting the layout
system have changed.
If the QskQuickItem::DeferredLayout flag is enabled ( = default )
If the QskItem::DeferredLayout flag is enabled ( = default )
the cached implicitSize() gets invalidated and a QEvent::LayoutRequest is sent
to the parent item ( like QWidget::updateGeometry ).
@ -607,13 +607,13 @@
*/
/*!
\fn QskQuickItem::event
\fn QskItem::event
QskQuickItem handles the additional type of events.
QskItem handles the additional type of events.
For some reason the QQuick classes introduced proprietory notfier hooks
instead of using the well established and powerful concept of events.
QskQuickItem tries to revert this decision by mapping notifications
QskItem tries to revert this decision by mapping notifications
to events, when possible.
The following notification events are added by QSkinny - usually with a
@ -633,37 +633,28 @@
*/
/*!
\fn QskQuickItem::changeEvent
\fn QskItem::changeEvent
This event handler can be reimplemented to handle certain state changes:
- QEvent::StyleChange
- QEvent::ContentsRectChange
- QEvent::FontChange
- QEvent::PaletteChange
- QEvent::ReadOnlyChange
- QEvent::EnabledChange
- QEvent::LocaleChange
- QEvent::ParentChange
- QEvent::LayoutDirectionChange
\param event Qt event
\note QEvent::PaletteChange, QEvent::FontChange are handled, but both event types
do not fit to the themeing concept of QSkinny and are not posted. However
it is possible to post them if an application has a concept, where they
make sense.
*/
/*!
\fn QskQuickItem::geometryChangeEvent
\fn QskItem::geometryChangeEvent
For no known reason QQuickItem propagates changes of position and size
by calling QQuickItem::geometryChange(), instead of using events.
QskQuickItem reestablished the more powerful concept of events by sending/posting
QskItem reestablished the more powerful concept of events by sending/posting
events, that can be preprocessed by event filtering.
\param event Event indicating the geometry change
@ -673,7 +664,7 @@
*/
/*!
\fn QskQuickItem::windowChangeEvent
\fn QskItem::windowChangeEvent
This event handler can be reimplemented to handle situations, where
an item is added, removed or transferred between windows. It corresponds
@ -686,7 +677,7 @@
*/
/*!
\fn QskQuickItem::itemChange
\fn QskItem::itemChange
For no obvious reason Qt/Quick has introduced an additional callback
mechanism beside events and signals.
@ -707,7 +698,7 @@
*/
/*!
\fn QskQuickItem::aboutToShow
\fn QskItem::aboutToShow
A specific hook that is intended to be overloaded by controls that need
to do some specific operations, when an item is painted the first time
@ -720,7 +711,7 @@
*/
/*!
\fn QskQuickItem::mouseUngrabEvent
\fn QskItem::mouseUngrabEvent
Notification, that is overloaded for debuging purposes, without
doing anything beside calling the base class.
@ -729,7 +720,7 @@
*/
/*!
\fn QskQuickItem::touchUngrabEvent
\fn QskItem::touchUngrabEvent
Notification, that is overloaded for debuging purposes, without
doing anything beside calling the base class.

View File

@ -53,7 +53,7 @@
The default value
\accessors visiblePolicy(), setVisiblePolicy()
\sa hiddenPolicy, QskQuickItem::isVisibleToParent(), qskIsVisibleToParent()
\sa hiddenPolicy, QskItem::isVisibleToParent(), qskIsVisibleToParent()
\note QskPlacementPolicy::Ignore is stored in the transparentForPositioner
bit in QQuickItem and might have an impact on Qt/Quick layout code.
@ -78,7 +78,7 @@
Sometimes an item wants to have its proper size even when being hidden.
\accessors hiddenPolicy(), setHiddenPolicy()
\sa visiblePolicy, QskQuickItem::isVisibleToParent(), qskIsVisibleToParent()
\sa visiblePolicy, QskItem::isVisibleToParent(), qskIsVisibleToParent()
\note QskPlacementPolicy::Ignore is stored in the transparentForPositioner
bit in QQuickItem and might have an impact on Qt/Quick layout code.

View File

@ -0,0 +1,51 @@
---
title: 10. Building QSkinny for WebAssembly (Wasm)
layout: docs
---
:doctitle: 10. Building QSkinny for WebAssembly (Wasm)
:notitle:
== 10. Building QSkinny for WebAssembly (Wasm)
=== Build Qt for Wasm
Build Qt for Wasm from source as described here: https://doc.qt.io/qt-6/wasm.html#building-qt-from-source ; The verified Qt version for QSkinny as of this writing was 6.6.0. It might also work to use a downloaded version of Qt for Wasm, but some additional libraries will need to be built.
After configuring Qt as described in the link above, for QSkinny you will need the qtbase, qtdeclarative, qtshadertools and qtsvg modules.
Assuming the Emscripten SDK in `~/dev/emscripten` and Qt in `~/dev/qt6`, Qt can be compiled the following way:
[source]
....
cd ~/dev/qt6
source "~/dev/emsdk/emsdk_env.sh"
cmake --build . -t qtbase -t qtdeclarative -t qtshadertools -t qtsvg
....
This will install all required libs in `~/dev/qt6/qtbase/lib`.
=== Build QSkinny for Wasm
With the Qt version from above QSkinny can be built for WAsm, assuming it has been checked out at `~/dev/qskinny`. Note the configuration option `BUILD_QSKDLL=OFF` for static
builds:
[source]
....
mkdir -p ~/dev/qskinny-wasm-build
source "~/dev/emsdk/emsdk_env.sh"
~/dev/qt6/qtbase/bin/qt-cmake -S ~/dev/qskinny -B ~/dev/qskinny-wasm-build -DBUILD_QSKDLL=OFF
....
=== Run QSkinny for Wasm
Qt creates the HTML wrappers automatically, so there is not much to do except letting Emscripten start the server and open our app in the browser:
[source]
....
/usr/bin/python3 ~/dev/emsdk/upstream/emscripten/emrun.py --browser firefox --port 30001 --no_emrun_detect ~/dev/qskinny-wasm-build/examples/bin/iotdashboard.html
....
.The IOT dashboard example in a browser
image::../images/iotdashboard-wasm.png[The IOT dashboard example in a browser]

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -26,6 +26,7 @@ class SubWindow : public QskSubWindow
: QskSubWindow( parent )
{
setObjectName( iconSource );
setDecorations( TitleBar | Title | Symbol );
const QUrl url( iconSource );

View File

@ -4,7 +4,6 @@
############################################################################
set(SOURCES
label/LabelPage.h label/LabelPage.cpp
inputs/InputPage.h inputs/InputPage.cpp
progressbar/ProgressBarPage.h progressbar/ProgressBarPage.cpp
button/ButtonPage.h button/ButtonPage.cpp

View File

@ -8,8 +8,60 @@
#include <QskDialog.h>
#include <QskLinearBox.h>
#include <QskPushButton.h>
#include <QskStandardSymbol.h>
#include <QskBoxShapeMetrics.h>
#if QT_CONFIG(thread)
/*
WebAssembly without asyncify support does not allow recursive
event loops. As we did not implement QskDialog::message and friends
with callbacks yet ( TODO ) we do have some dummy code here to avoid
crashes.
*/
#define QSK_USE_EXEC
#endif
#ifndef QSK_USE_EXEC
#include <QskMessageSubWindow.h>
#include <QskSelectionSubWindow.h>
#include <qquickwindow.h>
namespace
{
void openMessageSubWindow( QQuickWindow* window, const QString& title,
const QString& text, QskDialog::Actions actions, QskDialog::Action defaultAction )
{
auto subWindow = new QskMessageSubWindow( window->contentItem() );
subWindow->setPopupFlag( QskPopup::DeleteOnClose );
subWindow->setModal( true );
subWindow->setTitle( title );
subWindow->setDialogActions( actions );
subWindow->setDefaultDialogAction( defaultAction );
subWindow->setText( text );
( void ) subWindow->open();
}
void openSelectSubWindow( QQuickWindow* window, const QString& title,
QskDialog::Actions actions, QskDialog::Action defaultAction,
const QStringList& entries, int selectedRow )
{
auto subWindow = new QskSelectionSubWindow( window->contentItem() );
subWindow->setPopupFlag( QskPopup::DeleteOnClose );
subWindow->setModal( true );
subWindow->setTitle( title );
subWindow->setDialogActions( actions );
subWindow->setDefaultDialogAction( defaultAction );
subWindow->setEntries( entries );
subWindow->setSelectedRow( selectedRow );
( void ) subWindow->open();
}
}
#endif
namespace
{
@ -19,6 +71,7 @@ namespace
Button( const QString& text, QQuickItem* parent = nullptr )
: QskPushButton( text, parent )
{
setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
}
};
@ -26,9 +79,10 @@ namespace
{
public:
ButtonBox( QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Horizontal, 2, parent )
: QskLinearBox( Qt::Vertical, parent )
{
setObjectName( "ButtonBox" );
setDefaultAlignment( Qt::AlignCenter );
setMargins( 10 );
setSpacing( 20 );
@ -36,18 +90,9 @@ namespace
auto messageButton = new Button( "Message", this );
connect( messageButton, &Button::clicked, this, &ButtonBox::execMessage );
auto informationButton = new Button( "Information", this );
connect( informationButton, &Button::clicked, this, &ButtonBox::execInformation );
auto questionButton = new Button( "Question", this );
connect( questionButton, &Button::clicked, this, &ButtonBox::execQuestion );
auto warningButton = new Button( "Warning", this );
connect( warningButton, &Button::clicked, this, &ButtonBox::execWarning );
auto criticalButton = new Button( "Critical", this );
connect( criticalButton, &Button::clicked, this, &ButtonBox::execCritical );
auto selectButton = new Button( "Selection", this );
connect( selectButton, &Button::clicked, this, &ButtonBox::execSelection );
@ -57,35 +102,32 @@ namespace
private:
void execMessage()
{
qskDialog->message( "Message", "Request vector, over.",
QskStandardSymbol::NoSymbol, QskDialog::Close );
}
void execInformation()
{
qskDialog->information( "Information",
"We have clearance, Clarence." );
const QString title( "Message" );
const QString message( "Request vector, over." );
#ifndef QSK_USE_EXEC
openMessageSubWindow( window(), title, message,
QskDialog::Ok, QskDialog::Ok );
#else
qskDialog->information( title, message );
#endif
}
void execQuestion()
{
qskDialog->question( "Question",
"Roger, Roger. Do we have a vector, Victor ?" );
}
void execWarning()
{
qskDialog->warning( "Warning", "We have clearance, Clarence." );
}
void execCritical()
{
qskDialog->critical( "Critical", "That's Clarence Oveur. Over." );
const QString title( "Question" );
const QString question( "Roger, Roger. Do we have a vector, Victor ?" );
#ifndef QSK_USE_EXEC
openMessageSubWindow( window(), title, question,
QskDialog::Yes | QskDialog::No, QskDialog::Yes );
#else
(void )qskDialog->question( title, question );
#endif
}
void execSelection()
{
// of course we all love "The Teens"
const QString title( "The Teens" );
const QStringList entries =
{
"Give Me More",
@ -108,7 +150,12 @@ namespace
"Gimme Gimme Gimme Gimme Gimme Your Love"
};
qskDialog->select( "Here we go ...", "Hot Hot Hot", entries, 7 );
#ifndef QSK_USE_EXEC
openSelectSubWindow( window(), title,
QskDialog::Ok | QskDialog::Cancel, QskDialog::Ok, entries, 7 );
#else
(void )qskDialog->select( title, entries, 7 );
#endif
}
};
}

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

Binary file not shown.

View File

@ -62,16 +62,10 @@ namespace
{
auto spinBox = new QskSpinBox( 0.0, 100.0, 1.0, this );
spinBox->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
spinBox->setPageSize( 5 );
spinBox->setValue( 35 );
}
{
auto spinBox = new QskSpinBox( 10.0, 100.0, 1.0, this );
spinBox->setPageSize( 10 );
spinBox->setDecoration( QskSpinBox::NoDecoration );
spinBox->setValue( 50 );
}
}
};
}

View File

@ -1,97 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "LabelPage.h"
#include <QskTextLabel.h>
#include <QskGraphicLabel.h>
#include <QskSeparator.h>
#include <QskRgbValue.h>
#include <QskSkin.h>
namespace
{
class TextLabel : public QskTextLabel
{
public:
TextLabel( int role, QQuickItem* parent = nullptr )
: QskTextLabel( parent )
{
setText( textFromRole( role ) );
setFontRole( role );
setSizePolicy( Qt::Horizontal, QskSizePolicy::Ignored );
}
private:
QString textFromRole( int role ) const
{
static QMetaEnum metaEnum;
if ( !metaEnum.isValid() )
{
const auto& mo = QskSkin::staticMetaObject;
metaEnum = mo.enumerator( mo.indexOfEnumerator( "SkinFontRole" ) );
}
QString s( metaEnum.valueToKey( role ) );
s.remove( QStringLiteral( "Font" ) );
return s;
}
};
class TextBox : public QskLinearBox
{
public:
TextBox( QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Horizontal, 3, parent )
{
setMargins( 10 );
setDefaultAlignment( Qt::AlignCenter );
for ( int i = 0; i <= QskSkin::HugeFont; i++ )
( void ) new TextLabel( i, this );
}
};
class IconBox : public QskLinearBox
{
public:
IconBox( QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Horizontal, 3, parent )
{
setMargins( 10 );
setSpacing( 20 );
const char* icons[] =
{
"rectangle/royalblue",
"triangleright/thistle",
"ellipse/khaki",
"ring/sandybrown",
"star/darkviolet",
"hexagon/darkslategray"
};
const auto prefix = QStringLiteral( "image://shapes/" );
for ( const auto icon : icons )
{
auto label = new QskGraphicLabel( prefix + icon, this );
label->setAlignment( Qt::AlignCenter );
}
}
};
}
LabelPage::LabelPage( QQuickItem* parent )
: Page( Qt::Vertical, parent )
{
setSpacing( 40 );
(void) new TextBox( this );
(void) new QskSeparator( this );
(void) new IconBox( this );
}

View File

@ -3,7 +3,6 @@
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "label/LabelPage.h"
#include "progressbar/ProgressBarPage.h"
#include "inputs/InputPage.h"
#include "button/ButtonPage.h"
@ -261,7 +260,6 @@ namespace
{
auto tabView = new TabView( this );
tabView->addPage( "Buttons", new ButtonPage() );
tabView->addPage( "Labels", new LabelPage() );
tabView->addPage( "Inputs", new InputPage() );
tabView->addPage( "Indicators", new ProgressBarPage() );
tabView->addPage( "Selectors", new SelectorPage() );

View File

@ -159,6 +159,7 @@ void ProgressBarPage::populate()
{
auto* ring = new QskProgressRing( determinateRingsHBox );
ring->setSize( size );
ring->setLayoutAlignmentHint( Qt::AlignCenter );
QQuickItem* parentItem;
@ -178,7 +179,7 @@ void ProgressBarPage::populate()
}
}
connect( this, &QskQuickItem::windowChanged, this, [this, determinateIndicators]( QQuickWindow* window )
connect( this, &QskItem::windowChanged, this, [this, determinateIndicators]( QQuickWindow* window )
{
if( window )
{

View File

@ -7,6 +7,7 @@
#include "Skin.h"
#include <QskTextLabel.h>
#include <QskFontRole.h>
QSK_SUBCONTROL( Box, Panel )
@ -19,7 +20,7 @@ Box::Box( const QString& title, QQuickItem* parent )
if ( !title.isEmpty() )
{
auto label = new QskTextLabel( title, this );
label->setFontRole( Skin::TitleFont );
label->setFontRole( { QskFontRole::Caption, QskFontRole::High } );
}
}

View File

@ -10,6 +10,7 @@
#include <QskTextLabel.h>
#include <QskLinearBox.h>
#include <QskFontRole.h>
QSK_SUBCONTROL( BoxWithButtons, ValueText )
QSK_SUBCONTROL( BoxWithButtons, ValuePanel )
@ -66,7 +67,7 @@ BoxWithButtons::BoxWithButtons(
titleAndValue->setSubcontrolProxy( QskBox::Panel, ValuePanel );
auto* titleLabel = new QskTextLabel( title, titleAndValue );
titleLabel->setFontRole( Skin::TitleFont );
titleLabel->setFontRole( { QskFontRole::Caption, QskFontRole::High } );
m_valueLabel = new QskTextLabel( titleAndValue );
m_valueLabel->setSubcontrolProxy( QskTextLabel::Text, ValueText );

View File

@ -6,11 +6,8 @@
set(SOURCES
Box.h Box.cpp
BoxWithButtons.h BoxWithButtons.cpp
CircularProgressBar.h CircularProgressBar.cpp
CircularProgressBarSkinlet.h CircularProgressBarSkinlet.cpp
Diagram.h Diagram.cpp
DiagramSkinlet.h DiagramSkinlet.cpp
EnergyMeter.h EnergyMeter.cpp
GraphicProvider.h GraphicProvider.cpp
GridBox.h GridBox.cpp
LightDisplaySkinlet.h LightDisplaySkinlet.cpp
@ -31,7 +28,7 @@ set(SOURCES
UsageBox.h UsageBox.cpp
UsageDiagram.h UsageDiagram.cpp
StoragePage.h StoragePage.cpp
StorageMeter.h StorageMeter.cpp
ValueMeter.h ValueMeter.cpp
StorageBar.h StorageBar.cpp
StorageBarSkinlet.h StorageBarSkinlet.cpp
nodes/DiagramDataNode.h nodes/DiagramDataNode.cpp

View File

@ -1,197 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "CircularProgressBar.h"
#include <QskAnimator.h>
#include <QskFunctions.h>
QSK_SUBCONTROL( CircularProgressBar, Groove )
QSK_SUBCONTROL( CircularProgressBar, Bar )
namespace
{
class PositionAnimator : public QskAnimator
{
public:
PositionAnimator( CircularProgressBar* progressBar )
: m_progressBar( progressBar )
{
setAutoRepeat( true );
setDuration( 1300 );
setWindow( progressBar->window() );
}
void advance( qreal value ) override
{
const auto aspect = CircularProgressBar::Bar | QskAspect::Position;
m_progressBar->setMetric( aspect, value );
m_progressBar->update();
}
private:
CircularProgressBar* m_progressBar;
};
}
class CircularProgressBar::PrivateData
{
public:
void updateIndeterminateAnimator( CircularProgressBar* progressBar )
{
if ( !isIndeterminate )
{
delete animator;
animator = nullptr;
return;
}
if ( progressBar->window() && progressBar->isVisible() )
{
if ( animator == nullptr )
animator = new PositionAnimator( progressBar );
animator->start();
}
else
{
if ( animator )
animator->stop();
}
}
PositionAnimator* animator = nullptr;
qreal value = 0.0;
qreal origin = 0.0;
bool hasOrigin = false;
bool isIndeterminate = false;
};
CircularProgressBar::~CircularProgressBar() = default;
CircularProgressBar::CircularProgressBar( qreal min, qreal max, QQuickItem* parent )
: QskBoundedControl( min, max, parent )
, m_data( new PrivateData )
{
m_data->value = minimum();
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::MinimumExpanding );
connect( this, &QskBoundedControl::boundariesChanged,
this, &CircularProgressBar::adjustValue );
}
CircularProgressBar::CircularProgressBar( QQuickItem* parent )
: CircularProgressBar( 0.0, 100.0, parent )
{
}
bool CircularProgressBar::isIndeterminate() const
{
return m_data->isIndeterminate;
}
void CircularProgressBar::setIndeterminate( bool on )
{
if ( on == m_data->isIndeterminate )
return;
m_data->isIndeterminate = on;
m_data->updateIndeterminateAnimator( this );
update();
Q_EMIT indeterminateChanged( on );
}
void CircularProgressBar::resetOrigin()
{
if ( m_data->hasOrigin )
{
m_data->hasOrigin = false;
update();
Q_EMIT originChanged( origin() );
}
}
qreal CircularProgressBar::origin() const
{
if ( m_data->hasOrigin )
{
return boundedValue( m_data->origin );
}
return minimum();
}
qreal CircularProgressBar::value() const
{
return m_data->value;
}
qreal CircularProgressBar::valueAsRatio() const
{
return QskBoundedControl::valueAsRatio( m_data->value );
}
void CircularProgressBar::setValue( qreal value )
{
if ( isComponentComplete() )
value = boundedValue( value );
setValueInternal( value );
}
void CircularProgressBar::setValueAsRatio( qreal ratio )
{
ratio = qBound( 0.0, ratio, 1.0 );
setValue( minimum() + ratio * boundaryLength() );
}
void CircularProgressBar::setOrigin( qreal origin )
{
if ( isComponentComplete() )
origin = boundedValue( origin );
if( !m_data->hasOrigin || !qskFuzzyCompare( m_data->origin, origin ) )
{
m_data->hasOrigin = true;
m_data->origin = origin;
update();
Q_EMIT originChanged( origin );
}
}
void CircularProgressBar::componentComplete()
{
Inherited::componentComplete();
adjustValue();
}
void CircularProgressBar::setValueInternal( qreal value )
{
if ( !qskFuzzyCompare( value, m_data->value ) )
{
m_data->value = value;
Q_EMIT valueChanged( value );
update();
}
}
void CircularProgressBar::adjustValue()
{
if ( isComponentComplete() )
setValueInternal( boundedValue( m_data->value ) );
}
#include "moc_CircularProgressBar.cpp"

View File

@ -1,61 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskBoundedControl.h>
class CircularProgressBar : public QskBoundedControl
{
Q_OBJECT
Q_PROPERTY( bool indeterminate READ isIndeterminate
WRITE setIndeterminate NOTIFY indeterminateChanged )
Q_PROPERTY( qreal origin READ origin
WRITE setOrigin RESET resetOrigin NOTIFY originChanged )
Q_PROPERTY( qreal value READ value WRITE setValue NOTIFY valueChanged )
Q_PROPERTY( qreal valueAsRatio READ valueAsRatio
WRITE setValueAsRatio NOTIFY valueChanged )
using Inherited = QskBoundedControl;
public:
QSK_SUBCONTROLS( Groove, Bar )
CircularProgressBar( qreal min, qreal max, QQuickItem* parent = nullptr );
CircularProgressBar( QQuickItem* parent = nullptr );
~CircularProgressBar() override;
bool isIndeterminate() const;
void setIndeterminate( bool on = true );
void resetOrigin();
qreal origin() const;
qreal value() const;
qreal valueAsRatio() const; // [0.0, 1.0]
public Q_SLOTS:
void setValue( qreal );
void setValueAsRatio( qreal );
void setOrigin( qreal );
Q_SIGNALS:
void indeterminateChanged( bool );
void valueChanged( qreal );
void originChanged( qreal );
protected:
void componentComplete() override;
private:
void setValueInternal( qreal value );
void adjustValue();
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};

View File

@ -1,49 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "CircularProgressBarSkinlet.h"
#include "CircularProgressBar.h"
CircularProgressBarSkinlet::CircularProgressBarSkinlet( QskSkin* skin )
: QskSkinlet( skin )
{
setNodeRoles( { GrooveRole, BarRole } );
}
CircularProgressBarSkinlet::~CircularProgressBarSkinlet()
{
}
QRectF CircularProgressBarSkinlet::subControlRect(
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const
{
return contentsRect;
}
QSGNode* CircularProgressBarSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
switch( nodeRole )
{
case GrooveRole:
{
return updateArcNode( skinnable, node, CircularProgressBar::Groove );
}
case BarRole:
{
const auto bar = static_cast< const CircularProgressBar* >( skinnable );
const qreal startAngle = 90.0;
const qreal spanAngle = 360.0 * bar->valueAsRatio();
return updateArcNode( skinnable, node, startAngle, -spanAngle,
CircularProgressBar::Bar );
}
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
#include "moc_CircularProgressBarSkinlet.cpp"

View File

@ -1,36 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskSkinlet.h>
class CircularProgressBar;
class CircularProgressBarSkinlet : public QskSkinlet
{
Q_GADGET
using Inherited = QskSkinlet;
public:
enum NodeRole
{
GrooveRole,
BarRole,
RoleCount,
};
Q_INVOKABLE CircularProgressBarSkinlet( QskSkin* = nullptr );
~CircularProgressBarSkinlet() override;
QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const override;
protected:
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
};

View File

@ -14,17 +14,6 @@
#include "TopBar.h"
#include "UsageBox.h"
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxShapeMetrics.h>
#include <QskGridBox.h>
#include <QskSetup.h>
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QskQuick.h>
#include <QTimer>
QSK_SUBCONTROL( DashboardPage, Panel )
namespace

View File

@ -5,8 +5,8 @@
#include "DevicesPage.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QskFontRole.h>
QSK_SUBCONTROL( DevicesPage, Panel )
@ -15,7 +15,7 @@ DevicesPage::DevicesPage( QQuickItem* parent )
{
auto* const textLabel = new QskTextLabel( "devices page", this );
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
textLabel->setFontRole( QskSkin::HugeFont );
textLabel->setFontRole( QskFontRole::Display );
}
#include "moc_DevicesPage.cpp"

View File

@ -1,69 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "EnergyMeter.h"
#include "CircularProgressBar.h"
#include <QskTextLabel.h>
#include <QskSkin.h>
namespace
{
class ValueLabel : public QskTextLabel
{
public:
ValueLabel( QQuickItem* parent )
: QskTextLabel( parent )
{
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
setLayoutAlignmentHint( Qt::AlignCenter );
setFontRole( QskSkin::SmallFont );
}
void setValue( int value )
{
setText( locale().toString( value ) + " " + locale().percent() );
}
};
}
EnergyMeter::EnergyMeter( const QColor& textColor,
const QskGradient& gradient, int value, QQuickItem* parent )
: QskControl( parent )
{
setAutoLayoutChildren( true );
auto valueBar = new CircularProgressBar( this );
valueBar->setGradientHint( CircularProgressBar::Bar, gradient );
valueBar->setValue( value );
auto valueLabel = new ValueLabel( this );
valueLabel->setTextColor( textColor );
valueLabel->setValue( value );
}
QSizeF EnergyMeter::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
qreal size;
if ( constraint.width() > 0 )
{
size = constraint.width();
}
else if ( constraint.height() > 0 )
{
size = constraint.height();
}
else
{
size = 57;
}
return QSizeF( size, size );
}

View File

@ -1,18 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskControl.h>
class EnergyMeter : public QskControl
{
public:
EnergyMeter( const QColor&, const QskGradient&,
int progress, QQuickItem* parent = nullptr );
protected:
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
};

View File

@ -51,17 +51,6 @@ bool LightDisplay::isPressed() const
return hasSkinState( Pressed );
}
void LightDisplay::setGradient( const QskGradient& gradient )
{
m_gradient = gradient;
update();
}
const QskGradient& LightDisplay::gradient() const
{
return m_gradient;
}
void LightDisplay::mousePressEvent( QMouseEvent* event )
{
QRectF handleRect = subControlRect( LightDisplay::Knob );

View File

@ -6,7 +6,6 @@
#pragma once
#include <QskBoundedValueInput.h>
#include <QskBoxShapeMetrics.h>
#include <QskShadowMetrics.h>
class LightDisplay : public QskBoundedValueInput
@ -22,9 +21,6 @@ class LightDisplay : public QskBoundedValueInput
bool isPressed() const;
void setGradient( const QskGradient& );
const QskGradient& gradient() const;
protected:
void mousePressEvent( QMouseEvent* e ) override;
void mouseMoveEvent( QMouseEvent* e ) override;
@ -33,9 +29,4 @@ class LightDisplay : public QskBoundedValueInput
private:
qreal angleFromPoint( const QRectF&, const QPointF& ) const;
bool arcContainsPoint( const QRectF&, const QPointF& ) const;
QskShadowMetrics m_shadow;
QColor m_shadowColor = Qt::black;
QskGradient m_gradient;
};

View File

@ -7,6 +7,7 @@
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QskFontRole.h>
QSK_SUBCONTROL( MembersPage, Panel )
@ -15,7 +16,7 @@ MembersPage::MembersPage( QQuickItem* parent )
{
auto* const textLabel = new QskTextLabel( "members page", this );
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
textLabel->setFontRole( QskSkin::HugeFont );
textLabel->setFontRole( QskFontRole::Display );
}
#include "moc_MembersPage.cpp"

View File

@ -11,6 +11,7 @@
#include <QskGridBox.h>
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QskFontRole.h>
#include <QImage>
@ -32,7 +33,7 @@ namespace
icon->setCheckable( true );
auto textLabel = new QskTextLabel( name, this );
textLabel->setFontRole( QskSkin::TinyFont );
textLabel->setFontRole( { QskFontRole::Caption, QskFontRole::Low } );
textLabel->setAlignment( Qt::AlignHCenter );
}
};

View File

@ -7,8 +7,6 @@
#include "Box.h"
#include "BoxWithButtons.h"
#include "CircularProgressBar.h"
#include "CircularProgressBarSkinlet.h"
#include "DashboardPage.h"
#include "Diagram.h"
#include "DiagramSkinlet.h"
@ -21,7 +19,6 @@
#include "RoundedIcon.h"
#include "StorageBar.h"
#include "StorageBarSkinlet.h"
#include "StorageMeter.h"
#include "StoragePage.h"
#include "TopBar.h"
#include "UsageBox.h"
@ -37,23 +34,18 @@
#include <QskSkinHintTableEditor.h>
#include <QskStateCombination.h>
#include <QskTextLabel.h>
#include <QskProgressRing.h>
#include <QskGraphicLabel.h>
#include <QskFontRole.h>
#include <QFontDatabase>
namespace
{
static inline QFont qskFont( qreal pointSize, bool semiBold = false )
inline QFont createFont( qreal pointSize,
QFont::Weight weight = QFont::Normal )
{
QFont font( "Proxima Nova" );
if ( semiBold )
{
font.setWeight( QFont::Bold );
}
font.setPointSizeF( pointSize /*/ qskDpiScaled( 1.0 )*/ );
return font;
return QFont( QStringLiteral( "Proxima Nova" ), pointSize, weight );
}
}
@ -62,7 +54,6 @@ Skin::Skin( QObject* parent )
{
setObjectName( "iot" );
declareSkinlet< CircularProgressBar, CircularProgressBarSkinlet >();
declareSkinlet< Diagram, DiagramSkinlet >();
declareSkinlet< LightDisplay, LightDisplaySkinlet >();
declareSkinlet< StorageBar, StorageBarSkinlet >();
@ -78,25 +69,24 @@ void Skin::initHints()
{
const auto palette = Skin::palette( colorScheme() );
QFontDatabase db;
db.addApplicationFont( ":/fonts/ProximaNova-Regular.otf" ); // ### use fontconfig
QFontDatabase::addApplicationFont( ":/fonts/ProximaNova-Regular.otf" );
setFont( QskSkin::DefaultFont, qskFont( 12 ) );
setFont( QskSkin::TinyFont, qskFont( 9 ) );
setFont( QskSkin::SmallFont, qskFont( 10 ) );
setFont( QskSkin::MediumFont, qskFont( 13 ) );
setFont( QskSkin::LargeFont, qskFont( 20 ) );
setFont( QskSkin::HugeFont, qskFont( 27, true ) );
setFont( { QskFontRole::Caption, QskFontRole::Low }, createFont( 9 ) );
setFont( { QskFontRole::Caption, QskFontRole::Normal }, createFont( 10 ) );
setFont( { QskFontRole::Caption, QskFontRole::High }, createFont( 10, QFont::Bold ) );
setFont( Skin::TitleFont, qskFont( 10, true ) );
setFont( { QskFontRole::Body, QskFontRole::Normal }, createFont( 12 ) );
setFont( { QskFontRole::Subtitle, QskFontRole::Normal }, createFont( 13 ) );
setFont( { QskFontRole::Headline, QskFontRole::Normal }, createFont( 20 ) );
setFont( { QskFontRole::Display, QskFontRole::Normal }, createFont( 27, QFont::Bold ) );
QskSkinHintTableEditor ed( &hintTable() );
ed.setPadding( MainContentGridBox::Panel, { 19, 0, 27, 24 } );
// menu bar:
{
// menu bar:
using Q = QskPushButton;
using A = QskAspect;
@ -112,7 +102,7 @@ void Skin::initHints()
ed.setSpacing( Q::Panel | A::Header, 10 );
ed.setColor( Q::Text | A::Header, Qt::white );
ed.setFontRole( Q::Text | A::Header, QskSkin::SmallFont );
ed.setFontRole( Q::Text | A::Header, QskFontRole::Caption );
ed.setAlignment( Q::Text | A::Header, Qt::AlignLeft | Qt::AlignVCenter );
ed.setPadding( Q::Icon | A::Header, { 30, 0, 0, 0 } );
@ -120,36 +110,38 @@ void Skin::initHints()
ed.setAlignment( Q::Icon | A::Header, Qt::AlignCenter );
}
// top bar:
ed.setPadding( TopBar::Panel, { 25, 35, 25, 0 } );
{
// top bar:
ed.setColor( TopBarItem::Item1 | QskAspect::TextColor, 0xffff3122 );
ed.setColor( TopBarItem::Item2 | QskAspect::TextColor, 0xff6776ff );
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, 0xfff99055 );
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, 0xff6776ff );
ed.setPadding( TopBar::Panel, { 25, 35, 25, 0 } );
// arcs are counterclockwise, so specify the 2nd color first:
ed.setGradient( TopBarItem::Item1, 0xffff3122, 0xffff5c00 );
ed.setGradient( TopBarItem::Item2, 0xff6100ff, 0xff6776ff );
ed.setGradient( TopBarItem::Item3, 0xffff3122, 0xffffce50 );
ed.setGradient( TopBarItem::Item4, 0xff6100ff, 0xff6776ff );
ed.setColor( TopBarItem::Item1 | QskAspect::TextColor, 0xffff3122 );
ed.setColor( TopBarItem::Item2 | QskAspect::TextColor, 0xff6776ff );
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, 0xfff99055 );
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, 0xff6776ff );
ed.setGradient( TopBarItem::Item1, 0xffff5c00, 0xffff3122 );
ed.setGradient( TopBarItem::Item2, 0xff6776ff, 0xff6100ff );
ed.setGradient( TopBarItem::Item3, 0xffffce50, 0xffff3122 );
ed.setGradient( TopBarItem::Item4, 0xff6776ff, 0xff6100ff );
}
// the bar gradient is defined through the top bar items above
ed.setArcMetrics( CircularProgressBar::Groove, 90, -360, 8.53 );
ed.setArcMetrics( QskProgressRing::Groove, 90, -360, 8.53 );
// the span angle will be set in the progress bar, we just give a dummy
// value here:
ed.setArcMetrics( CircularProgressBar::Bar, 90, -180, 8.53 );
ed.setArcMetrics( QskProgressRing::Fill, ed.arcMetrics( QskProgressRing::Groove ) );
ed.setFontRole( TimeTitleLabel::Text, Skin::TitleFont );
ed.setFontRole( TimeTitleLabel::Text, { QskFontRole::Caption, QskFontRole::High } );
ed.setFontRole( TimeLabel::Text, QskSkin::HugeFont );
ed.setFontRole( TimeLabel::Text, QskFontRole::Display );
ed.setColor( TimeLabel::Text, 0xff6776ff );
// boxes:
ed.setPadding( Box::Panel, 8 );
// content in boxes (indoor temperature, humidity etc.):
ed.setFontRole( UsageBox::Separator, QskSkin::SmallFont );
ed.setFontRole( UsageBox::Separator, QskFontRole::Caption );
ed.setColor( UsageBox::Separator, 0xffdddddd );
ed.setPadding( BoxWithButtons::Panel, 8 );
@ -199,7 +191,7 @@ void Skin::initHints()
ed.setGradient( subControl | RoundedIcon::Bright, bright );
}
ed.setFontRole( BoxWithButtons::ValueText, QskSkin::HugeFont );
ed.setFontRole( BoxWithButtons::ValueText, QskFontRole::Display );
ed.setColor( BoxWithButtons::ValueText, 0xff929cb2 );
ed.setPadding( BoxWithButtons::ValuePanel, 0, 10, 0, 0 );
@ -210,7 +202,7 @@ void Skin::initHints()
// diagram:
ed.setBoxBorderMetrics( UsageDiagramBox::DaysBox, 0, 0, 3, 3 );
ed.setFontRole( UsageDiagramBox::DayText, QskSkin::TinyFont );
ed.setFontRole( UsageDiagramBox::DayText, { QskFontRole::Caption, QskFontRole::Low } );
ed.setStrutSize( UsageDiagramLegend::Symbol, 8, 8 );
ed.setBoxShape( UsageDiagramLegend::Symbol, 100, Qt::RelativeSize ); // a circle
@ -246,7 +238,7 @@ void Skin::initHints()
ed.setArcMetrics( LightDisplay::Tickmarks, 0, 180, 4.69 );
ed.setColor( LightDisplay::Tickmarks, 0x55929cb2 );
ed.setFontRole( LightDisplay::ValueText, QskSkin::LargeFont );
ed.setFontRole( LightDisplay::ValueText, QskFontRole::Headline );
ed.setColor( LightDisplay::ValueText, 0xff929cb2 );
ed.setStrutSize( LightDisplay::Knob, { 20, 20 } );
@ -290,8 +282,8 @@ void Skin::initHints()
ed.setColor( QskTextLabel::Text, palette.text );
ed.setColor( UsageDiagramBox::DayText, palette.text );
ed.setMetric( CircularProgressBar::Groove | QskAspect::Border, 2 );
ed.setColor( CircularProgressBar::Groove | QskAspect::Border,
ed.setMetric( QskProgressRing::Groove | QskAspect::Border, 2 );
ed.setColor( QskProgressRing::Groove | QskAspect::Border,
palette.circularProgressBarGroove );
// storage bar
@ -309,9 +301,13 @@ void Skin::initHints()
// storage meter
{
ed.setGradient( StorageMeter::Status,
{ { { 0.00, "#00ff00" }, { 0.33, "#00ff00" }, { 0.33, "#ffaf00" }, { 0.66, "#ffaf00" },
{ 0.66, "#ff0000" }, { 1.00, "#ff0000" } } } );
ed.setGradient( StoragePage::Status,
{ {
{ 0.00, "#00ff00" }, { 0.33, "#00ff00" },
{ 0.33, "#ffaf00" }, { 0.66, "#ffaf00" },
{ 0.66, "#ff0000" }, { 1.00, "#ff0000" }
} }
);
}
}
@ -329,7 +325,7 @@ Skin::Palette Skin::palette( QskSkin::ColorScheme colorScheme ) const
Qt::white,
0xff4a4a4a,
0xff555555,
{ { { 0.0, 0xff991100 }, { 0.2, 0xff9a7a57 }, { 0.5, 0xff3726af }, { 1.0, Qt::black } } },
{ { { 0.0, 0xff991100 }, { 0.4, 0xff9a7a57 }, { 1.0, 0xff3726af } } },
0x10ffffff,
0xff222222
};
@ -346,8 +342,7 @@ Skin::Palette Skin::palette( QskSkin::ColorScheme colorScheme ) const
Qt::black,
0xffe5e5e5,
0xffc4c4c4,
{ { { 0.0, 0xffff3122 }, { 0.2, 0xfffeeeb7 }, { 0.3, 0xffa7b0ff }, { 0.5, 0xff6776ff },
{ 1.0, Qt::black } } },
{ { { 0.0, 0xffff3122 }, { 0.4, 0xfffeeeb7 }, { 0.6, 0xffa7b0ff }, { 1.0, 0xff6776ff } } },
0x10000000,
0xffdddddd
};

View File

@ -30,14 +30,8 @@ class Skin : public QskSkin
Skin( QObject* parent = nullptr );
~Skin() override;
enum SkinFontRole
{
TitleFont = QskSkin::HugeFont + 1,
};
private:
void initHints() override;
Palette palette( ColorScheme ) const;
void initHints( const Palette& );
};

View File

@ -5,8 +5,8 @@
#include "StatisticsPage.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QskFontRole.h>
QSK_SUBCONTROL( StatisticsPage, Panel )
@ -15,7 +15,7 @@ StatisticsPage::StatisticsPage( QQuickItem* parent )
{
auto* const textLabel = new QskTextLabel( "statistics page", this );
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
textLabel->setFontRole( QskSkin::HugeFont );
textLabel->setFontRole( QskFontRole::Display );
}
#include "moc_StatisticsPage.cpp"

View File

@ -18,7 +18,7 @@ QSK_SUBCONTROL( StorageBar, Free )
using S = StorageBar;
StorageBar::StorageBar( QskQuickItem* const parent )
StorageBar::StorageBar( QskItem* const parent )
: Inherited( parent )
{
static constexpr qreal size = 16.0;

View File

@ -20,7 +20,7 @@ class StorageBar final : public QskControl
public:
QSK_SUBCONTROLS( Pictures, Music, Videos, Documents, Others, Free )
explicit StorageBar( QskQuickItem* parent = nullptr );
explicit StorageBar( QskItem* parent = nullptr );
qreal pictures() const;
void setPictures( qreal newPictures );

View File

@ -1,65 +0,0 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "StorageMeter.h"
#include "CircularProgressBar.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( StorageMeter, Status )
namespace
{
inline QString make_text( const QLocale& locale, const qreal value )
{
return locale.toString( static_cast< int >( value ) ) + " " + locale.percent();
}
}
StorageMeter::StorageMeter( QQuickItem* parent ) noexcept
: CircularProgressBar( parent )
, label( new QskTextLabel( this ) )
{
setAutoLayoutChildren( true );
setSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Constrained );
label->setText( make_text( locale(), value() ) );
label->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
label->setLayoutAlignmentHint( Qt::AlignCenter );
label->setFontRole( QskSkin::SmallFont );
}
void StorageMeter::setValue( const qreal value )
{
const auto gradient = gradientHint( StorageMeter::Status );
const auto color = gradient.extracted( value / 100.0, value / 100.0 ).startColor();
setGradientHint( StorageMeter::Bar, { color, color.lighter() } );
CircularProgressBar::setValue( value );
label->setTextColor( color );
label->setText( make_text( locale(), value ) );
}
QSizeF StorageMeter::contentsSizeHint( Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
qreal size;
if ( constraint.width() > 0 )
{
size = constraint.width();
}
else if ( constraint.height() > 0 )
{
size = constraint.height();
}
else
{
size = 57;
}
return QSizeF( size, size );
}

View File

@ -1,22 +0,0 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include "CircularProgressBar.h"
#include <QskControl.h>
class StorageMeter final : public CircularProgressBar
{
public:
QSK_SUBCONTROLS( Status )
explicit StorageMeter( QQuickItem* parent = nullptr ) noexcept;
public Q_SLOTS:
void setValue( qreal value );
private:
QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& constraint ) const override;
class QskTextLabel* label = nullptr;
};

View File

@ -6,7 +6,7 @@
#include "StoragePage.h"
#include "Box.h"
#include "StorageBar.h"
#include "StorageMeter.h"
#include "ValueMeter.h"
#include <QTimer>
#include <QskAnimator.h>
#include <QskBox.h>
@ -15,11 +15,65 @@
#include <QskGradientStop.h>
#include <QskGraphicLabel.h>
#include <QskPushButton.h>
#include <QskSkin.h>
#include <QskFontRole.h>
#include <QskStackBox.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( StoragePage, Panel )
QSK_SUBCONTROL( StoragePage, Status )
namespace
{
struct Storage
{
struct Media
{
qreal pictures = 0;
qreal music = 0;
qreal videos = 0;
qreal documents = 0;
qreal others = 0;
inline constexpr bool operator==( const Media& rhs ) const noexcept
{
return pictures == rhs.pictures && music == rhs.music && videos == rhs.videos &&
documents == rhs.documents && others == rhs.others;
}
inline constexpr qreal free() const noexcept
{
return 1.0 - pictures - music - videos - documents - others;
}
};
QString title;
QString description;
Media distribution;
};
class StorageMeter final : public ValueMeter
{
public:
StorageMeter( QQuickItem* parent = nullptr )
: ValueMeter( parent )
{
setFixedSize( 64, 64 );
connect( this, &ValueMeter::valueChanged,
this, &StorageMeter::setStatusColor );
}
private:
void setStatusColor( qreal value )
{
const auto color = qskInterpolatedColorAt(
gradientHint( StoragePage::Status ).stops(), value / 100.0 );
setFillGradient( { color, color.lighter() } );
setTextColor( color );
}
};
}
struct StorageRowAnimator final : public QObject, public QskAnimator
{
@ -85,13 +139,11 @@ void StoragePage::addRow( const QString& title, const QString& description,
const auto percent = 100.0 * ( 1.0 - storage.distribution.free() );
auto* const meter = new StorageMeter( left );
meter->setValue( percent );
meter->setMinimumSize( 64, 64 );
meter->setMaximumSize( 64, 64 );
auto* const maintitle = new QskTextLabel( storage.title, center );
maintitle->setFontRole( QskSkin::LargeFont );
maintitle->setFontRole( QskFontRole::Headline );
auto* const subtitle = new QskTextLabel( storage.description, center );
subtitle->setFontRole( QskSkin::MediumFont );
subtitle->setFontRole( QskFontRole::Subtitle );
const auto& media = storage.distribution;
@ -106,7 +158,7 @@ void StoragePage::addRow( const QString& title, const QString& description,
legend->setSpacing( 12 );
legend->addSpacer( 1, 999 );
auto* const sync = new QskPushButton( "Update", legend );
sync->setFontRoleHint( QskPushButton::Text, QskSkin::SmallFont );
sync->setFontRoleHint( QskPushButton::Text, QskFontRole::Caption );
using S = StorageBar;
for ( const auto& pair : QVector< QPair< QString, QskGradient > >{
@ -124,7 +176,7 @@ void StoragePage::addRow( const QString& title, const QString& description,
dot->setMaximumSize( size, size );
dot->setGradientHint( QskBox::Panel, pair.second );
auto* const label = new QskTextLabel( pair.first, legend );
label->setFontRole( QskSkin::SmallFont );
label->setFontRole( QskFontRole::Caption );
}
auto* const animator = new StorageRowAnimator( window(), sync );
@ -136,5 +188,6 @@ void StoragePage::addRow( const QString& title, const QString& description,
bar->setDocuments( media.documents * v );
bar->setOthers( media.others * v );
};
connect( sync, &QskPushButton::clicked, animator, [ animator ]() { animator->start(); } );
connect( sync, &QskPushButton::clicked,
animator, [ animator ]() { animator->start(); } );
}

View File

@ -7,44 +7,15 @@
#include <QVector>
#include <QskLinearBox.h>
#include <memory>
class QQuickItem;
class StoragePage final : public QskLinearBox
{
public:
QSK_SUBCONTROLS( Panel )
explicit StoragePage( QQuickItem* parent = nullptr );
QSK_SUBCONTROLS( Panel, Status )
StoragePage( QQuickItem* parent = nullptr );
private:
struct Storage
{
struct Media
{
qreal pictures = 0;
qreal music = 0;
qreal videos = 0;
qreal documents = 0;
qreal others = 0;
inline constexpr bool operator==( const Media& rhs ) const noexcept
{
return pictures == rhs.pictures && music == rhs.music && videos == rhs.videos &&
documents == rhs.documents && others == rhs.others;
}
inline constexpr qreal free() const noexcept
{
return 1.0 - pictures - music - videos - documents - others;
}
};
QString title;
QString description;
Media distribution;
};
void addRow( const QString& title, const QString& description,
qreal pictures, qreal music, qreal videos, qreal documents, qreal others );
};

View File

@ -4,9 +4,9 @@
*****************************************************************************/
#include "TopBar.h"
#include "EnergyMeter.h"
#include "ValueMeter.h"
#include <QskSkin.h>
#include <QskFontRole.h>
#include <QskTextLabel.h>
#include <QTime>
@ -41,6 +41,22 @@ namespace
return TopBarItem::Item4;
}
}
class EnergyMeter : public ValueMeter
{
public:
EnergyMeter( const QColor& textColor,
const QskGradient& gradient, int value, QQuickItem* parent )
: ValueMeter( parent )
{
setFillGradient( gradient );
setValue( value );
setTextColor( textColor );
setFixedSize( 57, 57 );
}
};
}
TopBarItem::TopBarItem(
@ -54,7 +70,7 @@ TopBarItem::TopBarItem(
setSpacing( 15 );
auto* textLabel = new QskTextLabel( name, this );
textLabel->setFontRole( QskSkin::SmallFont );
textLabel->setFontRole( QskFontRole::Caption );
auto* pieChartAndDisplay = new QskLinearBox( Qt::Horizontal, this );
pieChartAndDisplay->setSpacing( 10 );
@ -62,19 +78,17 @@ TopBarItem::TopBarItem(
const auto subcontrol = subcontrolForIndex( index );
const auto textColor = color( subcontrol | QskAspect::TextColor );
auto pieChart = new EnergyMeter(
textColor, gradient, progress, pieChartAndDisplay );
pieChart->setSizePolicy( Qt::Horizontal, QskSizePolicy::Constrained );
(void) new EnergyMeter( textColor, gradient, progress, pieChartAndDisplay );
auto display = new QskLinearBox( Qt::Vertical, pieChartAndDisplay );
display->setSpacing( 0 );
display->addSpacer( 0, 1 );
auto displayValue = new QskTextLabel( QString::number( value ), display );
displayValue->setFontRole( QskSkin::MediumFont );
displayValue->setFontRole( QskFontRole::Subtitle );
auto displayUnit = new QskTextLabel( "kwH", display );
displayUnit->setFontRole( QskSkin::SmallFont );
displayUnit->setFontRole( QskFontRole::Caption );
display->addSpacer( 0, 1 );
}

View File

@ -4,22 +4,28 @@
*****************************************************************************/
#include "UsageBox.h"
#include "Skin.h"
#include <QskFontRole.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( UsageBox, Separator )
namespace
{
class SeparatorLabel : public QskTextLabel
class UsageLine : public QskLinearBox
{
public:
SeparatorLabel( QQuickItem* parent = nullptr )
: QskTextLabel( "_____", parent )
UsageLine( const QString& info, const QString& value, QQuickItem* parent )
: QskLinearBox( Qt::Horizontal, parent )
{
setSubcontrolProxy( QskTextLabel::Text, UsageBox::Separator );
auto infoLabel = new QskTextLabel( info, this );
infoLabel->setFontRole( QskFontRole::Caption );
auto separator = new QskTextLabel( "_____", this );
separator->setSubcontrolProxy( QskTextLabel::Text, UsageBox::Separator );
auto valueLabel = new QskTextLabel( value, this );
valueLabel->setFontRole( QskFontRole::Caption );
}
};
}
@ -27,30 +33,7 @@ namespace
UsageBox::UsageBox( QQuickItem* parent )
: Box( "Usage", parent )
{
auto today = new QskLinearBox( Qt::Horizontal, this );
auto todayText = new QskTextLabel( "Usage today", today );
todayText->setFontRole( QskSkin::SmallFont );
new SeparatorLabel( today );
auto todayValue = new QskTextLabel( "0,5 kwH", today );
todayValue->setFontRole( QskSkin::SmallFont );
auto month = new QskLinearBox( Qt::Horizontal, this );
auto monthText = new QskTextLabel( "Usage this month", month );
monthText->setFontRole( QskSkin::SmallFont );
new SeparatorLabel( month );
auto monthValue = new QskTextLabel( "66 kwH", month );
monthValue->setFontRole( QskSkin::SmallFont );
auto total = new QskLinearBox( Qt::Horizontal, this );
auto totalText = new QskTextLabel( "Total working hours", total );
totalText->setFontRole( QskSkin::SmallFont );
new SeparatorLabel( total );
auto totalValue = new QskTextLabel( "125 hrs", total );
totalValue->setFontRole( QskSkin::SmallFont );
( void ) new UsageLine( "Usage today", "0,5 kwH", this );
( void ) new UsageLine( "Usage this month", "66 kwH", this );
( void ) new UsageLine( "Total working hours", "125 hrs", this );
}

View File

@ -7,7 +7,7 @@
#include "Diagram.h"
#include <QskGridBox.h>
#include <QskSkin.h>
#include <QskFontRole.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( UsageDiagramLegend, Panel )
@ -52,7 +52,7 @@ namespace
}
auto label = new QskTextLabel( text );
label->setFontRole( QskSkin::TinyFont );
label->setFontRole( { QskFontRole::Caption, QskFontRole::Low } );
addItem( symbol );
addItem( label );

View File

@ -0,0 +1,42 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ValueMeter.h"
#include <QskFontRole.h>
#include <QskTextLabel.h>
ValueMeter::ValueMeter( QQuickItem* parent )
: QskProgressRing( parent )
{
setAutoLayoutChildren( true );
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Constrained );
m_label = new QskTextLabel( this );
m_label->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
m_label->setLayoutAlignmentHint( Qt::AlignCenter );
m_label->setFontRole( QskFontRole::Caption );
connect( this, &QskProgressRing::valueChanged,
this, &ValueMeter::updateMeter );
updateMeter( value() );
}
void ValueMeter::updateMeter( const qreal value )
{
m_label->setText( text( value ) );
}
QString ValueMeter::text( qreal value ) const
{
value = static_cast< int >( value );
return locale().toString( value ) + ' ' + locale().percent();
}
void ValueMeter::setTextColor( const QColor& color )
{
m_label->setTextColor( color );
}

Some files were not shown because too many files have changed in this diff Show More