synched with master
This commit is contained in:
parent
6a8d9096be
commit
128ce8f79b
|
|
@ -1008,7 +1008,7 @@ void Editor::setupPushButtonColors(
|
|||
const auto text = Q::Text | section | variation;
|
||||
const auto icon = Q::Icon | section | variation;
|
||||
|
||||
for ( const auto state : { QskAspect::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
||||
for ( const auto state : { QskAspect::NoState, Q::Hovered, Q::Pressed, Q::Checked, Q::Disabled } )
|
||||
{
|
||||
QRgb panelColor, borderColor1, borderColor2, textColor;
|
||||
int graphicRole;
|
||||
|
|
@ -1023,7 +1023,7 @@ void Editor::setupPushButtonColors(
|
|||
textColor = pal.fillColor.textOnAccent.primary;
|
||||
graphicRole = W::GraphicRoleFillColorTextOnAccentPrimary;
|
||||
}
|
||||
else if ( state == Q::Pressed )
|
||||
else if ( state == Q::Pressed || state == Q::Checked )
|
||||
{
|
||||
panelColor = pal.fillColor.accent.tertiary;
|
||||
borderColor1 = borderColor2 = pal.strokeColor.control.onAccentDefault;
|
||||
|
|
@ -1056,7 +1056,7 @@ void Editor::setupPushButtonColors(
|
|||
textColor = pal.fillColor.text.primary;
|
||||
graphicRole = W::GraphicRoleFillColorTextPrimary;
|
||||
}
|
||||
else if ( state == Q::Pressed )
|
||||
else if ( state == Q::Pressed || state == Q::Checked )
|
||||
{
|
||||
panelColor = pal.fillColor.control.tertiary;
|
||||
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
||||
|
|
@ -1450,10 +1450,16 @@ void Editor::setupSliderMetrics()
|
|||
|
||||
setShadowMetrics( Q::Handle, { shadowSpread, 0.0 } );
|
||||
|
||||
setBoxBorderMetrics( Q::Handle, 5 );
|
||||
setBoxBorderMetrics( Q::Handle | Q::Hovered, 4 );
|
||||
setBoxBorderMetrics( Q::Handle | Q::Pressed, 6 );
|
||||
setBoxBorderMetrics( Q::Handle | Q::Disabled, 6 );
|
||||
setBoxBorderMetrics( Q::Handle, 5_px );
|
||||
setBoxBorderMetrics( Q::Handle | Q::Hovered, 4_px );
|
||||
setBoxBorderMetrics( Q::Handle | Q::Pressed, 6_px );
|
||||
setBoxBorderMetrics( Q::Handle | Q::Disabled, 6_px );
|
||||
|
||||
setFlag( Q::Tick | A::Option, Qsk::Maybe );
|
||||
setStrutSize( Q::Tick | A::Horizontal, 1_px, -1 );
|
||||
setStrutSize( Q::Tick | A::Vertical, -1, 1_px );
|
||||
|
||||
setAnimation( Q::Handle | A::Metric | A::Position, 100 );
|
||||
}
|
||||
|
||||
void Editor::setupSliderColors(
|
||||
|
|
@ -1484,30 +1490,35 @@ void Editor::setupSliderColors(
|
|||
|
||||
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
||||
{
|
||||
QRgb grooveColor, handleColor;
|
||||
QRgb grooveColor, fillColor, handleColor;
|
||||
|
||||
if ( state == A::NoState || state == Q::Hovered )
|
||||
{
|
||||
grooveColor = pal.fillColor.controlStrong.defaultColor;
|
||||
fillColor = pal.fillColor.accent.defaultColor;
|
||||
handleColor = pal.fillColor.accent.defaultColor;
|
||||
}
|
||||
else if ( state == Q::Pressed )
|
||||
{
|
||||
grooveColor = pal.fillColor.controlStrong.defaultColor;
|
||||
handleColor = pal.fillColor.accent.tertiary;
|
||||
fillColor = pal.fillColor.accent.defaultColor;
|
||||
}
|
||||
else if ( state == Q::Disabled )
|
||||
{
|
||||
grooveColor = pal.fillColor.controlStrong.disabled;
|
||||
fillColor = pal.fillColor.accent.disabled;
|
||||
handleColor = grooveColor;
|
||||
}
|
||||
|
||||
grooveColor = rgbSolid( grooveColor, pal.background.solid.base );
|
||||
|
||||
setGradient( Q::Groove | section | state, grooveColor );
|
||||
setGradient( Q::Fill | section | state, grooveColor );
|
||||
setGradient( Q::Fill | section | state, fillColor );
|
||||
setGradient( Q::Handle | section | state, handleColor );
|
||||
}
|
||||
|
||||
setGradient( Q::Tick, pal.fillColor.controlSolid.defaultColor );
|
||||
}
|
||||
|
||||
void Editor::setupSpinBoxMetrics()
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
#include <QskTextLabel.h>
|
||||
#include <QskVirtualKeyboard.h>
|
||||
|
||||
#include <QskSliderSkinlet.h>
|
||||
|
||||
#include <QskAnimationHint.h>
|
||||
#include <QskAspect.h>
|
||||
#include <QskBoxBorderColors.h>
|
||||
|
|
@ -773,9 +775,10 @@ void Editor::setupSlider()
|
|||
{
|
||||
using A = QskAspect;
|
||||
using Q = QskSlider;
|
||||
using SK = QskSliderSkinlet;
|
||||
using P = QPalette;
|
||||
|
||||
const qreal extent = 30_px;
|
||||
const qreal extent = 16_px;
|
||||
|
||||
// Panel
|
||||
|
||||
|
|
@ -784,6 +787,7 @@ void Editor::setupSlider()
|
|||
setBoxBorderMetrics( Q::Panel, 0 );
|
||||
setGradient( Q::Panel, QskGradient() );
|
||||
|
||||
// space for the handle
|
||||
setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) );
|
||||
setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) );
|
||||
|
||||
|
|
@ -823,6 +827,39 @@ void Editor::setupSlider()
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
Tick
|
||||
|
||||
QSlider optionally allows to display ticks left/right or top/bottom
|
||||
of the groove. However this not supported by the skinlets yet.
|
||||
( Qt/Quick slider does not support showing ticks at all )
|
||||
|
||||
For the moment we make something up. TODO ...
|
||||
*/
|
||||
|
||||
setFlag( Q::Tick | A::Option, Qsk::Maybe );
|
||||
setStrutSize( Q::Tick, 2_px, 2_px );
|
||||
|
||||
const QskStateCombination combination(
|
||||
QskStateCombination::CombinationNoState, Q::Focused | Q::Pressed );
|
||||
|
||||
const auto rgb = m_pal.active( P::Text );
|
||||
|
||||
setColor( Q::Tick,
|
||||
QskRgb::interpolated( rgb, m_pal.groove, 0.2 ), combination );
|
||||
|
||||
setColor( Q::Tick | Q::Disabled,
|
||||
QskRgb::interpolated( rgb, m_pal.groove, 0.5 ) );
|
||||
|
||||
setColor( Q::Tick | SK::Filled,
|
||||
m_pal.active( P::HighlightedText ), combination );
|
||||
setColor( Q::Tick | SK::Filled | Q::Disabled,
|
||||
m_pal.disabled( P::HighlightedText ) );
|
||||
}
|
||||
|
||||
// Handle
|
||||
|
||||
setBoxShape( Q::Handle, 2 );
|
||||
setBoxBorderMetrics( Q::Handle, 1 );
|
||||
setBoxBorderColors( Q::Handle, m_pal.outline );
|
||||
|
|
@ -832,7 +869,7 @@ void Editor::setupSlider()
|
|||
Combination( { Q::Hovered, Q::Pressed } ) );
|
||||
#endif
|
||||
|
||||
setStrutSize( Q::Handle, 16_px, 16_px );
|
||||
setStrutSize( Q::Handle, extent, extent );
|
||||
|
||||
for ( auto state : { A::NoState, Q::Pressed } )
|
||||
{
|
||||
|
|
@ -845,9 +882,7 @@ void Editor::setupSlider()
|
|||
QskRgb::lighter( rgb, 102 ) );
|
||||
}
|
||||
|
||||
// move the handle smoothly, when using keys
|
||||
setAnimation( Q::Handle | A::Metric | A::Position, 2 * qskDuration );
|
||||
setAnimation( Q::Handle | A::Metric | A::Position | Q::Pressed, 0 );
|
||||
}
|
||||
|
||||
void Editor::setupSpinBox()
|
||||
|
|
|
|||
|
|
@ -3,11 +3,28 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
############################################################################
|
||||
|
||||
set(SOURCES
|
||||
QskMaterial3Global.h QskMaterial3Skin.h QskMaterial3Skin.cpp
|
||||
QskMaterial3SkinFactory.h QskMaterial3SkinFactory.cpp
|
||||
list(APPEND HEADERS
|
||||
QskMaterial3Global.h QskMaterial3Skin.h QskMaterial3SkinFactory.h
|
||||
)
|
||||
|
||||
list(APPEND PRIVATE_HEADERS
|
||||
QskMaterial3ProgressBarSkinlet.h
|
||||
QskMaterial3SliderSkinlet.h
|
||||
)
|
||||
|
||||
list(APPEND SOURCES
|
||||
QskMaterial3Skin.cpp
|
||||
QskMaterial3SkinFactory.cpp
|
||||
QskMaterial3ProgressBarSkinlet.cpp
|
||||
QskMaterial3SliderSkinlet.cpp
|
||||
)
|
||||
|
||||
qt_add_resources(SOURCES QskMaterial3Icons.qrc)
|
||||
|
||||
qsk_add_plugin(material3skin skins QskMaterial3SkinFactory ${SOURCES})
|
||||
set_target_properties(material3skin PROPERTIES DEFINE_SYMBOL QSK_MATERIAL3_MAKEDLL )
|
||||
qsk_add_plugin(material3skin skins QskMaterial3SkinFactory
|
||||
${SOURCES} ${HEADERS} ${PRIVATE_HEADERS}
|
||||
)
|
||||
|
||||
set_target_properties(material3skin PROPERTIES
|
||||
DEFINE_SYMBOL QSK_MATERIAL3_MAKEDLL
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskMaterial3ProgressBarSkinlet.h"
|
||||
#include <QskProgressBar.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
#include <QskBoxBorderMetrics.h>
|
||||
#include <QskBoxBorderColors.h>
|
||||
#include <QskMargins.h>
|
||||
#include <QskClipNode.h>
|
||||
#include <QskSGNode.h>
|
||||
|
||||
using Q = QskProgressBar;
|
||||
|
||||
QskMaterial3ProgressBarSkinlet::QskMaterial3ProgressBarSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
appendNodeRoles( { StopIndicatorRole } );
|
||||
}
|
||||
|
||||
QSGNode* QskMaterial3ProgressBarSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
auto progressBar = static_cast< const QskProgressBar* >( skinnable );
|
||||
|
||||
switch( nodeRole )
|
||||
{
|
||||
case GrooveRole:
|
||||
{
|
||||
auto clippedNode = QskSGNode::findChildNode( node, GrooveRole );
|
||||
clippedNode = Inherited::updateSubNode( skinnable, nodeRole, clippedNode );
|
||||
|
||||
if ( clippedNode == nullptr )
|
||||
return nullptr;
|
||||
|
||||
auto clipNode = updateGrooveClipNode( progressBar, node );
|
||||
QskSGNode::setNodeRole( clippedNode, nodeRole );
|
||||
QskSGNode::setParentNode( clippedNode, clipNode );
|
||||
|
||||
return clipNode;
|
||||
}
|
||||
case StopIndicatorRole:
|
||||
{
|
||||
if ( !( progressBar->isIndeterminate() || progressBar->hasOrigin() ) )
|
||||
return updateStopIndicatorNode( progressBar, node );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSGNode* QskMaterial3ProgressBarSkinlet::updateStopIndicatorNode(
|
||||
const QskProgressBar* progressBar, QSGNode* node ) const
|
||||
{
|
||||
auto rect = progressBar->subControlRect( Q::Groove );
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
if( progressBar->orientation() == Qt::Horizontal )
|
||||
rect.setLeft( rect.right() - rect.height() );
|
||||
else
|
||||
rect.setBottom( rect.top() + rect.width() );
|
||||
|
||||
const auto color = progressBar->gradientHint( Q::Fill ).endColor();
|
||||
const auto shape = progressBar->boxShapeHint( Q::Fill );
|
||||
|
||||
return updateBoxNode( progressBar, node, rect, shape,
|
||||
QskBoxBorderMetrics(), QskBoxBorderColors(), color );
|
||||
}
|
||||
|
||||
QSGNode* QskMaterial3ProgressBarSkinlet::updateGrooveClipNode(
|
||||
const QskProgressBar* progressBar, QSGNode* node ) const
|
||||
{
|
||||
auto rect = progressBar->subControlRect( Q::Fill );
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
QskMargins margins;
|
||||
if ( progressBar->orientation() == Qt::Horizontal )
|
||||
margins.setMargins( rect.height(), 0.0 );
|
||||
else
|
||||
margins.setMargins( 0.0, rect.width() );
|
||||
|
||||
rect = rect.marginsAdded( margins );
|
||||
|
||||
auto clipNode = QskSGNode::ensureNode< QskClipNode >( node );
|
||||
clipNode->setRegion( progressBar->subControlRect( Q::Groove ), rect );
|
||||
|
||||
return clipNode;
|
||||
}
|
||||
|
||||
#include "moc_QskMaterial3ProgressBarSkinlet.cpp"
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_MATERIAL3_PROGRESSBAR_SKINLET_H
|
||||
#define QSK_MATERIAL3_PROGRESSBAR_SKINLET_H
|
||||
|
||||
#include <QskProgressBarSkinlet.h>
|
||||
|
||||
class QskProgressBar;
|
||||
|
||||
class QskMaterial3ProgressBarSkinlet : QskProgressBarSkinlet
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
using Inherited = QskProgressBarSkinlet;
|
||||
|
||||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
StopIndicatorRole = Inherited::RoleCount,
|
||||
RoleCount
|
||||
};
|
||||
|
||||
Q_INVOKABLE QskMaterial3ProgressBarSkinlet( QskSkin* = nullptr );
|
||||
|
||||
protected:
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
private:
|
||||
QSGNode* updateStopIndicatorNode( const QskProgressBar*, QSGNode* ) const;
|
||||
QSGNode* updateGrooveClipNode( const QskProgressBar*, QSGNode* ) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -9,6 +9,8 @@
|
|||
*/
|
||||
|
||||
#include "QskMaterial3Skin.h"
|
||||
#include "QskMaterial3ProgressBarSkinlet.h"
|
||||
#include "QskMaterial3SliderSkinlet.h"
|
||||
|
||||
#include <QskSkinHintTableEditor.h>
|
||||
|
||||
|
|
@ -486,20 +488,13 @@ void Editor::setupProgressBar()
|
|||
using A = QskAspect;
|
||||
using Q = QskProgressBar;
|
||||
|
||||
auto size = 4_dp;
|
||||
|
||||
for ( auto subControl : { Q::Groove, Q::Fill } )
|
||||
{
|
||||
setMetric( subControl | A::Size, size );
|
||||
setPadding( subControl, 0 );
|
||||
|
||||
setBoxShape( subControl, 0 );
|
||||
setBoxBorderMetrics( subControl, 0 );
|
||||
setBoxShape( subControl, { 100, Qt::RelativeSize } );
|
||||
setMetric( subControl | A::Size, 4_dp );
|
||||
}
|
||||
|
||||
setMetric( Q::Groove | A::Size, size );
|
||||
setGradient( Q::Groove, m_pal.surfaceContainerHighest );
|
||||
|
||||
setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 );
|
||||
|
||||
setGradient( Q::Fill, m_pal.primary );
|
||||
|
|
@ -510,9 +505,15 @@ void Editor::setupProgressRing()
|
|||
{
|
||||
using Q = QskProgressRing;
|
||||
|
||||
setArcMetrics( Q::Groove, 90, -360, 4_dp );
|
||||
setGradient( Q::Groove, m_pal.surfaceContainerHighest );
|
||||
setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 );
|
||||
|
||||
setSpacing( Q::Fill, 10 );
|
||||
setStrutSize( Q::Fill, { 48_dp, 48_dp } );
|
||||
setGradient( Q::Fill, m_pal.primary );
|
||||
setArcMetrics( Q::Fill, 90, -360, 4_dp );
|
||||
setGradient( Q::Fill, m_pal.primary );
|
||||
setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 );
|
||||
}
|
||||
|
||||
void Editor::setupRadioBox()
|
||||
|
|
@ -725,6 +726,7 @@ void Editor::setupPushButton()
|
|||
setBoxShape( Q::Splash, 40_dp );
|
||||
setAnimation( Q::Splash | QskAspect::Color, qskDuration );
|
||||
|
||||
const auto checkedOpacity = m_pal.focusOpacity + m_pal.pressedOpacity;
|
||||
|
||||
// elevated buttons:
|
||||
|
||||
|
|
@ -751,8 +753,11 @@ void Editor::setupPushButton()
|
|||
setGradient( Q::Panel | M3::Elevated | Q::Focused, elevatedPressedColor );
|
||||
setShadowMetrics( Q::Panel | M3::Elevated | Q::Focused, m_pal.elevation1 );
|
||||
|
||||
setGradient( Q::Panel | M3::Elevated | Q::Pressed, elevatedPressedColor );
|
||||
setShadowMetrics( Q::Panel | M3::Elevated | Q::Pressed, m_pal.elevation1 );
|
||||
for( const auto state: { Q::Pressed, Q::Checked } )
|
||||
{
|
||||
setGradient( Q::Panel | M3::Elevated | state, elevatedPressedColor );
|
||||
setShadowMetrics( Q::Panel | M3::Elevated | state, m_pal.elevation1 );
|
||||
}
|
||||
|
||||
|
||||
// normal buttons (i.e. Filled):
|
||||
|
|
@ -769,6 +774,8 @@ void Editor::setupPushButton()
|
|||
setGradient( Q::Panel | Q::Focused, focusColor );
|
||||
|
||||
setGradient( Q::Panel | Q::Pressed, focusColor );
|
||||
setGradient( Q::Panel | Q::Checked,
|
||||
flattenedColor( m_pal.onPrimary, m_pal.primary, checkedOpacity ) );
|
||||
|
||||
setGradient( Q::Splash, stateLayerColor( m_pal.onPrimary, m_pal.hoverOpacity ) );
|
||||
|
||||
|
|
@ -806,6 +813,10 @@ void Editor::setupPushButton()
|
|||
setGradient( Q::Panel | M3::Tonal | Q::Pressed, tonalPressedColor );
|
||||
setShadowMetrics( Q::Panel | M3::Tonal | Q::Pressed, m_pal.elevation0 );
|
||||
|
||||
const auto tonalCheckedColor = flattenedColor( m_pal.onSecondaryContainer,
|
||||
m_pal.secondaryContainer, checkedOpacity );
|
||||
setGradient( Q::Panel | M3::Tonal | Q::Checked, tonalCheckedColor );
|
||||
|
||||
|
||||
// outlined buttons:
|
||||
|
||||
|
|
@ -831,6 +842,7 @@ void Editor::setupPushButton()
|
|||
|
||||
setGradient( Q::Panel | M3::Outlined | Q::Pressed, m_pal.primary12 );
|
||||
|
||||
setGradient( Q::Panel | M3::Outlined | Q::Checked, m_pal.primary12 );
|
||||
|
||||
/*
|
||||
text buttons:
|
||||
|
|
@ -857,6 +869,8 @@ void Editor::setupPushButton()
|
|||
setGradient( Q::Panel | M3::Text | Q::Focused, m_pal.primary12 );
|
||||
|
||||
setGradient( Q::Panel | M3::Text | Q::Pressed, m_pal.primary12 );
|
||||
|
||||
setGradient( Q::Panel | M3::Text | Q::Checked, m_pal.primary12 );
|
||||
}
|
||||
|
||||
void Editor::setupDialogButtonBox()
|
||||
|
|
@ -892,41 +906,60 @@ void Editor::setupSlider()
|
|||
{
|
||||
using A = QskAspect;
|
||||
using Q = QskSlider;
|
||||
using SK = QskSliderSkinlet;
|
||||
|
||||
const QSizeF sliderSize( 48_dp, 44_dp );
|
||||
setStrutSize( Q::Panel | A::Horizontal, sliderSize );
|
||||
setStrutSize( Q::Panel | A::Vertical, sliderSize.transposed() );
|
||||
const auto extentGroove = 16_dp;
|
||||
const auto extentPanel = 44_dp;
|
||||
|
||||
setBoxShape( Q::Groove | A::Horizontal, { 0, 100, 0, 100, Qt::RelativeSize } );
|
||||
setBoxShape( Q::Groove | A::Vertical, { 100, 100, 0, 0, Qt::RelativeSize } );
|
||||
setMetric( Q::Groove | A::Size, 16_dp );
|
||||
setMargin( Q::Groove | A::Horizontal, { 6_dp, 0, 0, 0 } );
|
||||
setMargin( Q::Groove | A::Vertical, {0, 0, 0, 6_dp } );
|
||||
setStrutSize( Q::Panel | A::Horizontal, 3 * extentGroove, extentPanel );
|
||||
setStrutSize( Q::Panel | A::Vertical, extentPanel, 3 * extentGroove );
|
||||
|
||||
setMetric( Q::Groove | A::Size, extentGroove );
|
||||
setMetric( Q::Fill | A::Size, extentGroove );
|
||||
|
||||
setGradient( Q::Groove, m_pal.primaryContainer );
|
||||
setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 );
|
||||
|
||||
setBoxShape( Q::Fill | A::Horizontal, { 100, 0, 100, 0, Qt::RelativeSize } );
|
||||
setBoxShape( Q::Fill | A::Vertical, { 0, 0, 100, 100, Qt::RelativeSize } );
|
||||
setMetric( Q::Fill | A::Size, 16_dp );
|
||||
setMargin( Q::Fill | A::Horizontal, { 0, 0, 6_dp, 0 } );
|
||||
setMargin( Q::Fill | A::Vertical, {0, 6_dp, 0, 0 } );
|
||||
|
||||
setGradient( Q::Fill, m_pal.primary );
|
||||
setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 );
|
||||
|
||||
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
|
||||
setBoxBorderMetrics( Q::Handle, 0 );
|
||||
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
|
||||
setBoxShape( Q::Fill, 100, Qt::RelativeSize );
|
||||
|
||||
const QSizeF handleSize( 4_dp, 44_dp );
|
||||
const QSizeF handleSizeFocusedPressed( 2_dp, 44_dp );
|
||||
setStrutSize( Q::Handle | A::Horizontal, handleSize );
|
||||
setStrutSize( Q::Handle | A::Horizontal, handleSizeFocusedPressed,
|
||||
{ QskStateCombination::Combination, Q::Focused | Q::Pressed } );
|
||||
setStrutSize( Q::Tick, { 4_dp, 4_dp } );
|
||||
setBoxShape( Q::Tick, 100, Qt::RelativeSize );
|
||||
|
||||
setStrutSize( Q::Handle | A::Vertical, handleSize.transposed() );
|
||||
setStrutSize( Q::Handle | A::Vertical, handleSizeFocusedPressed.transposed(),
|
||||
{ QskStateCombination::Combination, Q::Focused | Q::Pressed } );
|
||||
setGradient( Q::Tick, m_pal.primary );
|
||||
setGradient( Q::Tick | Q::Disabled, m_pal.onSurface );
|
||||
|
||||
setGradient( Q::Tick | SK::Filled, m_pal.secondaryContainer,
|
||||
{ QskStateCombination::CombinationNoState, Q::Focused | Q::Pressed } );
|
||||
setGradient( Q::Tick | SK::Filled | Q::Disabled, m_pal.inverseOnSurface );
|
||||
|
||||
setFlag( Q::Fill | A::Option, Qsk::Maybe );
|
||||
setFlag( Q::Tick | A::Option, Qsk::Maybe );
|
||||
|
||||
for ( const auto variation : { A::Horizontal, A::Vertical } )
|
||||
{
|
||||
QSizeF handleSize( extentGroove, extentPanel );
|
||||
QskMargins margin1{ 6_dp, 0_dp };
|
||||
QskMargins margin2{ 7_dp, 0_dp };
|
||||
|
||||
if ( variation == A::Vertical )
|
||||
{
|
||||
handleSize = handleSize.transposed();
|
||||
margin1 = margin1.rotated();
|
||||
margin2 = margin2.rotated();
|
||||
}
|
||||
|
||||
const auto aspect = Q::Handle | variation;
|
||||
|
||||
setStrutSize( aspect, handleSize );
|
||||
setMargin( aspect, margin1 );
|
||||
setMargin( aspect, margin2,
|
||||
{ QskStateCombination::Combination, Q::Focused | Q::Pressed } );
|
||||
}
|
||||
|
||||
setGradient( Q::Handle, m_pal.primary );
|
||||
setGradient( Q::Handle | Q::Pressed, m_pal.primary );
|
||||
|
|
@ -934,23 +967,6 @@ void Editor::setupSlider()
|
|||
const auto disabledColor = flattenedColor( m_pal.onSurface, m_pal.background, 0.38 );
|
||||
setGradient( Q::Handle | Q::Disabled, disabledColor );
|
||||
|
||||
for( auto indicator : { Q::GrooveStopIndicators, Q::FillStopIndicators } )
|
||||
{
|
||||
setStrutSize( indicator, { 4_dp, 4_dp } );
|
||||
setBoxShape( indicator, 100, Qt::RelativeSize );
|
||||
}
|
||||
|
||||
const auto p = 6_dp;
|
||||
setPadding( Q::GrooveStopIndicators | A::Horizontal, { p, 0, p, 0 } );
|
||||
setPadding( Q::GrooveStopIndicators | A::Vertical, { 0, p, 0, p } );
|
||||
setPadding( Q::FillStopIndicators | A::Horizontal, { p, 0, p, 0 } );
|
||||
setPadding( Q::FillStopIndicators | A::Vertical, { 0, p, 0, p } );
|
||||
|
||||
setGradient( Q::GrooveStopIndicators, m_pal.primary );
|
||||
setGradient( Q::GrooveStopIndicators | Q::Disabled, m_pal.onSurface );
|
||||
setGradient( Q::FillStopIndicators, m_pal.secondaryContainer );
|
||||
setGradient( Q::FillStopIndicators | Q::Disabled, m_pal.inverseOnSurface );
|
||||
|
||||
for( const auto state : { Q::Focused, Q::Pressed } )
|
||||
{
|
||||
setStrutSize( Q::LabelContainer | state, 48_dp, 44_dp,
|
||||
|
|
@ -966,9 +982,7 @@ void Editor::setupSlider()
|
|||
setColor( Q::LabelText, m_pal.inverseOnSurface );
|
||||
setAlignment( Q::LabelText, Qt::AlignCenter );
|
||||
|
||||
// move the handle smoothly when using keys
|
||||
setAnimation( Q::Handle | A::Metric | A::Position, 2 * qskDuration );
|
||||
setAnimation( Q::Handle | A::Metric | A::Position | Q::Pressed, 0 );
|
||||
}
|
||||
|
||||
void Editor::setupSpinBox()
|
||||
|
|
@ -1596,6 +1610,8 @@ qreal QskMaterial3Theme::stateOpacity( int state ) const
|
|||
QskMaterial3Skin::QskMaterial3Skin( QObject* parent )
|
||||
: Inherited( parent )
|
||||
{
|
||||
declareSkinlet< QskProgressBar, QskMaterial3ProgressBarSkinlet >();
|
||||
declareSkinlet< QskSlider, QskMaterial3SliderSkinlet >();
|
||||
}
|
||||
|
||||
QskMaterial3Skin::~QskMaterial3Skin()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskMaterial3SliderSkinlet.h"
|
||||
|
||||
#include <QskSlider.h>
|
||||
#include <QskClipNode.h>
|
||||
#include <QskSGNode.h>
|
||||
#include <QskFunctions.h>
|
||||
|
||||
using Q = QskSlider;
|
||||
|
||||
static inline bool qskHasOrigin( const QskSlider* slider )
|
||||
{
|
||||
return !qskFuzzyCompare( slider->origin(), slider->minimum() );
|
||||
}
|
||||
|
||||
QskMaterial3SliderSkinlet::QskMaterial3SliderSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
}
|
||||
|
||||
QRectF QskMaterial3SliderSkinlet::subControlRect( const QskSkinnable* skinnable,
|
||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
if ( subControl == Q::Scale )
|
||||
{
|
||||
auto r = Inherited::subControlRect( skinnable, contentsRect, Q::Scale );
|
||||
|
||||
const auto handleSize = skinnable->strutSizeHint( Q::Handle );
|
||||
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
if( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
const auto m = 0.5 * handleSize.width();
|
||||
r.adjust( m, 0.0, -m, 0.0 );
|
||||
}
|
||||
{
|
||||
const auto m = 0.5 * handleSize.height();
|
||||
r.adjust( 0.0, m, 0.0, -m );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskMaterial3SliderSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
switch( nodeRole )
|
||||
{
|
||||
case GrooveRole:
|
||||
case FillRole:
|
||||
{
|
||||
auto clippedNode = QskSGNode::findChildNode( node, nodeRole );
|
||||
clippedNode = Inherited::updateSubNode( skinnable, nodeRole, clippedNode );
|
||||
|
||||
if ( clippedNode )
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
|
||||
auto clipNode = QskSGNode::ensureNode< QskClipNode >( node );
|
||||
|
||||
clipNode->setRegion( slider->subControlRect( Q::Panel ),
|
||||
slider->subControlRect( Q::Handle ) );
|
||||
|
||||
QskSGNode::setNodeRole( clippedNode, nodeRole );
|
||||
QskSGNode::setParentNode( clippedNode, clipNode );
|
||||
|
||||
return clipNode;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QVector< qreal > QskMaterial3SliderSkinlet::graduation( const QskSlider* slider ) const
|
||||
{
|
||||
QVector< qreal > graduation;
|
||||
|
||||
if ( hasGraduation( slider ) )
|
||||
{
|
||||
const auto g = Inherited::graduation( slider );
|
||||
|
||||
// adding the boundaries
|
||||
|
||||
graduation.reserve( g.count() + 2 );
|
||||
graduation += slider->minimum();
|
||||
graduation += g;
|
||||
graduation += slider->maximum();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto policy = slider->flagHint< Qsk::Policy >(
|
||||
Q::Tick | QskAspect::Option, Qsk::Maybe );
|
||||
|
||||
if ( policy != Qsk::Never )
|
||||
{
|
||||
if ( qskHasOrigin( slider ) )
|
||||
{
|
||||
graduation.reserve( 3 );
|
||||
graduation += slider->minimum();
|
||||
graduation += slider->origin();
|
||||
graduation += slider->maximum();
|
||||
}
|
||||
else
|
||||
{
|
||||
graduation.reserve( 1 );
|
||||
graduation += slider->maximum();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return graduation;
|
||||
}
|
||||
|
||||
#include "moc_QskMaterial3SliderSkinlet.cpp"
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_MATERIAL3_SLIDER_SKINLET_H
|
||||
#define QSK_MATERIAL3_SLIDER_SKINLET_H
|
||||
|
||||
#include <QskSliderSkinlet.h>
|
||||
|
||||
class QskMaterial3SliderSkinlet : QskSliderSkinlet
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
using Inherited = QskSliderSkinlet;
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QskMaterial3SliderSkinlet( QskSkin* = nullptr );
|
||||
|
||||
QRectF subControlRect( const QskSkinnable*,
|
||||
const QRectF& rect, QskAspect::Subcontrol ) const override;
|
||||
|
||||
protected:
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
QVector< qreal > graduation( const QskSlider* ) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
470
doc/Doxyfile
470
doc/Doxyfile
|
|
@ -1,4 +1,4 @@
|
|||
# Doxyfile 1.9.3
|
||||
# Doxyfile 1.9.8
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
|
|
@ -12,6 +12,16 @@
|
|||
# For lists, items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (\" \").
|
||||
#
|
||||
# Note:
|
||||
#
|
||||
# Use doxygen to compare the used configuration file with the template
|
||||
# configuration file:
|
||||
# doxygen -x [configFile]
|
||||
# Use doxygen to compare the used configuration file with the template
|
||||
# configuration file without replacing the environment variables or CMake type
|
||||
# replacement variables:
|
||||
# doxygen -x_noenv [configFile]
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
|
|
@ -38,13 +48,13 @@ PROJECT_NAME = QSkinny
|
|||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.0.1
|
||||
PROJECT_NUMBER = 0.8.0
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
# quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_BRIEF = C++/Qt UI toolkit
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||
# in the documentation. The maximum height of the logo should not exceed 55
|
||||
|
|
@ -58,18 +68,30 @@ PROJECT_LOGO =
|
|||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY =
|
||||
OUTPUT_DIRECTORY = api
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
# will distribute the generated files over these directories. Enabling this
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
|
||||
# sub-directories (in 2 levels) under the output directory of each output format
|
||||
# and will distribute the generated files over these directories. Enabling this
|
||||
# option can be useful when feeding doxygen a huge amount of source files, where
|
||||
# putting all generated files in the same directory would otherwise causes
|
||||
# performance problems for the file system.
|
||||
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
|
||||
# control the number of sub-directories.
|
||||
# The default value is: NO.
|
||||
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# Controls the number of sub-directories that will be created when
|
||||
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
|
||||
# level increment doubles the number of directories, resulting in 4096
|
||||
# directories at level 8 which is the default and also the maximum value. The
|
||||
# sub-directories are organized in 2 levels, the first level always has a fixed
|
||||
# number of 16 directories.
|
||||
# Minimum value: 0, maximum value: 8, default value: 8.
|
||||
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
||||
|
||||
CREATE_SUBDIRS_LEVEL = 8
|
||||
|
||||
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
|
||||
# characters to appear in the names of generated files. If set to NO, non-ASCII
|
||||
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
|
||||
|
|
@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO
|
|||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
|
||||
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
|
||||
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
|
||||
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
||||
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
|
||||
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
|
||||
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
|
||||
# Ukrainian and Vietnamese.
|
||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
|
||||
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
|
||||
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
|
||||
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
|
||||
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
|
||||
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
|
||||
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
|
||||
# Swedish, Turkish, Ukrainian and Vietnamese.
|
||||
# The default value is: English.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
|
@ -336,6 +358,17 @@ MARKDOWN_SUPPORT = YES
|
|||
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
|
||||
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
|
||||
# generate identifiers for the Markdown headings. Note: Every identifier is
|
||||
# unique.
|
||||
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
|
||||
# sequence number starting at 0 and GITHUB use the lower case version of title
|
||||
# with any whitespace replaced by '-' and punctuation characters removed.
|
||||
# The default value is: DOXYGEN.
|
||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||
|
||||
MARKDOWN_ID_STYLE = DOXYGEN
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
# be prevented in individual cases by putting a % sign in front of the word or
|
||||
|
|
@ -447,7 +480,7 @@ TYPEDEF_HIDES_STRUCT = NO
|
|||
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
|
||||
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
|
||||
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
|
||||
# during processing. When set to 0 doxygen will based this on the number of
|
||||
# cores available in the system. You can set it explicitly to a value larger
|
||||
# than 0 to get more control over the balance between CPU load and processing
|
||||
|
|
@ -460,6 +493,14 @@ LOOKUP_CACHE_SIZE = 0
|
|||
|
||||
NUM_PROC_THREADS = 1
|
||||
|
||||
# If the TIMESTAMP tag is set different from NO then each generated page will
|
||||
# contain the date or date and time when the page was generated. Setting this to
|
||||
# NO can help when comparing the output of multiple runs.
|
||||
# Possible values are: YES, NO, DATETIME and DATE.
|
||||
# The default value is: NO.
|
||||
|
||||
TIMESTAMP = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -541,7 +582,8 @@ HIDE_UNDOC_MEMBERS = NO
|
|||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy. If set
|
||||
# to NO, these classes will be included in the various overviews. This option
|
||||
# has no effect if EXTRACT_ALL is enabled.
|
||||
# will also hide undocumented C++ concepts if enabled. This option has no effect
|
||||
# if EXTRACT_ALL is enabled.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
|
@ -572,14 +614,15 @@ INTERNAL_DOCS = NO
|
|||
# filesystem is case sensitive (i.e. it supports files in the same directory
|
||||
# whose names only differ in casing), the option must be set to YES to properly
|
||||
# deal with such files in case they appear in the input. For filesystems that
|
||||
# are not case sensitive the option should be be set to NO to properly deal with
|
||||
# are not case sensitive the option should be set to NO to properly deal with
|
||||
# output files written for symbols that only differ in casing, such as for two
|
||||
# classes, one named CLASS and the other named Class, and to also support
|
||||
# references to files without having to specify the exact matching casing. On
|
||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||
# YES.
|
||||
# The default value is: system dependent.
|
||||
# Possible values are: SYSTEM, NO and YES.
|
||||
# The default value is: SYSTEM.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
|
||||
|
|
@ -831,11 +874,26 @@ WARN_IF_INCOMPLETE_DOC = YES
|
|||
|
||||
WARN_NO_PARAMDOC = NO
|
||||
|
||||
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
|
||||
# undocumented enumeration values. If set to NO, doxygen will accept
|
||||
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
|
||||
# will automatically be disabled.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_IF_UNDOC_ENUM_VAL = NO
|
||||
|
||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
|
||||
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
|
||||
# write the warning messages in between other messages but write them at the end
|
||||
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
|
||||
# besides being in the defined file also be shown at the end of a run, unless
|
||||
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
|
||||
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
|
||||
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = NO
|
||||
|
|
@ -846,10 +904,21 @@ WARN_AS_ERROR = NO
|
|||
# and the warning text. Optionally the format may contain $version, which will
|
||||
# be replaced by the version of the file (if it could be obtained via
|
||||
# FILE_VERSION_FILTER)
|
||||
# See also: WARN_LINE_FORMAT
|
||||
# The default value is: $file:$line: $text.
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
# In the $text part of the WARN_FORMAT command it is possible that a reference
|
||||
# to a more specific place is given. To make it easier to jump to this place
|
||||
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
|
||||
# Example:
|
||||
# WARN_LINE_FORMAT = "'vi $file +$line'"
|
||||
# See also: WARN_FORMAT
|
||||
# The default value is: at line $line of file $file.
|
||||
|
||||
WARN_LINE_FORMAT = "at line $line of file $file"
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
|
||||
# messages should be written. If left blank the output is written to standard
|
||||
# error (stderr). In case the file specified cannot be opened for writing the
|
||||
|
|
@ -878,10 +947,21 @@ INPUT = . \
|
|||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see:
|
||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||
# See also: INPUT_FILE_ENCODING
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
|
||||
# character encoding on a per file pattern basis. Doxygen will compare the file
|
||||
# name with each pattern and apply the encoding instead of the default
|
||||
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
|
||||
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
|
||||
# "INPUT_ENCODING" for further information on supported encodings.
|
||||
|
||||
INPUT_FILE_ENCODING =
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
||||
# *.h) to filter out the source-files in the directories.
|
||||
|
|
@ -893,12 +973,12 @@ INPUT_ENCODING = UTF-8
|
|||
# Note the list of default checked file patterns might differ from the list of
|
||||
# default file extension mappings.
|
||||
#
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
|
||||
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
|
||||
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
||||
# *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
|
||||
# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl,
|
||||
# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php,
|
||||
# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be
|
||||
# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
|
||||
FILE_PATTERNS =
|
||||
|
||||
|
|
@ -931,20 +1011,22 @@ EXCLUDE_SYMLINKS = NO
|
|||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories for example use the pattern */test/*
|
||||
|
||||
EXCLUDE_PATTERNS = *Private.* moc*.cpp *.moc
|
||||
EXCLUDE_PATTERNS = *Private.* \
|
||||
moc*.cpp \
|
||||
*.moc
|
||||
|
||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
|
||||
EXCLUDE_SYMBOLS = QskPainterCommand::PixmapData \
|
||||
QskPainterCommand::ImageData \
|
||||
QskPainterCommand::StateData
|
||||
QskPainterCommand::StateData \
|
||||
QHash \
|
||||
QList \
|
||||
std
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
|
||||
# that contain example code fragments that are included (see the \include
|
||||
|
|
@ -987,6 +1069,11 @@ IMAGE_PATH = images
|
|||
# code is scanned, but not when the output code is generated. If lines are added
|
||||
# or removed, the anchors will not be placed correctly.
|
||||
#
|
||||
# Note that doxygen will use the data processed and written to standard output
|
||||
# for further processing, therefore nothing else, like debug statements or used
|
||||
# commands (so in case of a Windows batch file always use @echo OFF), should be
|
||||
# written to standard output.
|
||||
#
|
||||
# Note that for custom extensions or not directly supported extensions you also
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# properly processed by doxygen.
|
||||
|
|
@ -1028,6 +1115,15 @@ FILTER_SOURCE_PATTERNS =
|
|||
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
|
||||
# The Fortran standard specifies that for fixed formatted Fortran code all
|
||||
# characters from position 72 are to be considered as comment. A common
|
||||
# extension is to allow longer lines before the automatic comment starts. The
|
||||
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
|
||||
# be processed before the automatic comment starts.
|
||||
# Minimum value: 7, maximum value: 10000, default value: 72.
|
||||
|
||||
FORTRAN_COMMENT_AFTER = 72
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -1114,6 +1210,46 @@ USE_HTAGS = NO
|
|||
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
|
||||
# clang parser (see:
|
||||
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
|
||||
# performance. This can be particularly helpful with template rich C++ code for
|
||||
# which doxygen's built-in parser lacks the necessary type information.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
# The default value is: NO.
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
|
||||
# tag is set to YES then doxygen will add the directory of each input to the
|
||||
# include path.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||
|
||||
CLANG_ADD_INC_PATHS = YES
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the compiler with command
|
||||
# line options that you would normally use when invoking the compiler. Note that
|
||||
# the include paths will already be set by doxygen for the files and directories
|
||||
# specified with INPUT and INCLUDE_PATH.
|
||||
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||
|
||||
CLANG_OPTIONS =
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the clang parser with the
|
||||
# path to the directory containing a file called compile_commands.json. This
|
||||
# file is the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
|
||||
# options used when the source files were built. This is equivalent to
|
||||
# specifying the -p option to a clang tool, such as clang-check. These options
|
||||
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
|
||||
# will be added as well.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
|
||||
CLANG_DATABASE_PATH =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -1125,10 +1261,11 @@ VERBATIM_HEADERS = YES
|
|||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
|
||||
# In case all classes in a project start with a common prefix, all classes will
|
||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||
# while generating the index headers.
|
||||
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
||||
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
||||
# tag works for classes, function and member names. The entity will be placed in
|
||||
# the alphabetical list under the first letter of the entity name that remains
|
||||
# after removing the prefix.
|
||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||
|
||||
IGNORE_PREFIX = Qsk \
|
||||
|
|
@ -1208,10 +1345,15 @@ HTML_STYLESHEET =
|
|||
# Doxygen will copy the style sheet files to the output directory.
|
||||
# Note: The order of the extra style sheet files is of importance (e.g. the last
|
||||
# style sheet in the list overrules the setting of the previous ones in the
|
||||
# list). For an example see the documentation.
|
||||
# list).
|
||||
# Note: Since the styling of scrollbars can currently not be overruled in
|
||||
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
|
||||
# one or more extra stylesheets have been specified. So if scrollbar
|
||||
# customization is desired it has to be added explicitly. For an example see the
|
||||
# documentation.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET = ./customdoxygen.css
|
||||
|
||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
||||
# other source files which should be copied to the HTML output directory. Note
|
||||
|
|
@ -1223,6 +1365,19 @@ HTML_EXTRA_STYLESHEET =
|
|||
|
||||
HTML_EXTRA_FILES =
|
||||
|
||||
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
|
||||
# should be rendered with a dark or light theme.
|
||||
# Possible values are: LIGHT always generate light mode output, DARK always
|
||||
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
|
||||
# the user preference, use light mode if no preference is set (the default),
|
||||
# AUTO_DARK automatically set the mode according to the user preference, use
|
||||
# dark mode if no preference is set and TOGGLE allow to user to switch between
|
||||
# light and dark mode via a button.
|
||||
# The default value is: AUTO_LIGHT.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_COLORSTYLE = AUTO_LIGHT
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
# this color. Hue is specified as an angle on a color-wheel, see
|
||||
|
|
@ -1232,7 +1387,7 @@ HTML_EXTRA_FILES =
|
|||
# Minimum value: 0, maximum value: 359, default value: 220.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_COLORSTYLE_HUE = 30
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
|
||||
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
|
||||
# in the HTML output. For a value of 0 the output will use gray-scales only. A
|
||||
|
|
@ -1251,16 +1406,7 @@ HTML_COLORSTYLE_SAT = 100
|
|||
# Minimum value: 40, maximum value: 240, default value: 80.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_COLORSTYLE_GAMMA = 130
|
||||
|
||||
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
|
||||
# page will contain the date and time when the page was generated. Setting this
|
||||
# to YES can help to show when doxygen was last run and thus if the
|
||||
# documentation is up to date.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
|
||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||
# documentation will contain a main index with vertical navigation menus that
|
||||
|
|
@ -1281,6 +1427,13 @@ HTML_DYNAMIC_MENUS = YES
|
|||
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
|
||||
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
|
||||
# dynamically folded and expanded in the generated HTML source code.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_CODE_FOLDING = YES
|
||||
|
||||
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
|
||||
# shown in the various tree structured indices initially; the user can expand
|
||||
# and collapse entries dynamically later on. Doxygen will expand the tree to
|
||||
|
|
@ -1411,6 +1564,16 @@ BINARY_TOC = NO
|
|||
|
||||
TOC_EXPAND = NO
|
||||
|
||||
# The SITEMAP_URL tag is used to specify the full URL of the place where the
|
||||
# generated documentation will be placed on the server by the user during the
|
||||
# deployment of the documentation. The generated sitemap is called sitemap.xml
|
||||
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
|
||||
# is specified no sitemap is generated. For information about the sitemap
|
||||
# protocol see https://www.sitemaps.org
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
SITEMAP_URL =
|
||||
|
||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
||||
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
|
||||
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
|
||||
|
|
@ -1586,17 +1749,6 @@ HTML_FORMULA_FORMAT = svg
|
|||
|
||||
FORMULA_FONTSIZE = 10
|
||||
|
||||
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
|
||||
# generated for formulas are transparent PNGs. Transparent PNGs are not
|
||||
# supported properly for IE 6.0, but are supported on all modern browsers.
|
||||
#
|
||||
# Note that when changing this option you need to delete any form_*.png files in
|
||||
# the HTML output directory before the changes have effect.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
||||
# to create new LaTeX commands to be used in formulas as building blocks. See
|
||||
# the section "Including formulas" for details.
|
||||
|
|
@ -1910,9 +2062,16 @@ PDF_HYPERLINKS = YES
|
|||
|
||||
USE_PDFLATEX = YES
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
||||
# if errors occur, instead of asking the user for help.
|
||||
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
|
||||
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
|
||||
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
|
||||
# hit at every error; missing files that TeX tries to input or request from
|
||||
# keyboard input (\read on a not open input stream) cause the job to abort,
|
||||
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
|
||||
# but there is no possibility of user interaction just like in batch mode,
|
||||
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
|
||||
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
|
||||
# each error, asking for user intervention.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
|
|
@ -1933,14 +2092,6 @@ LATEX_HIDE_INDICES = NO
|
|||
|
||||
LATEX_BIB_STYLE = plain
|
||||
|
||||
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
|
||||
# page will contain the date and time when the page was generated. Setting this
|
||||
# to NO can help when comparing the output of multiple runs.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_TIMESTAMP = NO
|
||||
|
||||
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# path from which the emoji images will be read. If a relative path is entered,
|
||||
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
||||
|
|
@ -2106,13 +2257,39 @@ DOCBOOK_OUTPUT = docbook
|
|||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
||||
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
|
||||
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
|
||||
# the structure of the code including all documentation. Note that this feature
|
||||
# is still experimental and incomplete at the moment.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to Sqlite3 output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
|
||||
# database with symbols found by doxygen stored in tables.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_SQLITE3 = NO
|
||||
|
||||
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
|
||||
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
|
||||
# in front of it.
|
||||
# The default directory is: sqlite3.
|
||||
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
|
||||
|
||||
SQLITE3_OUTPUT = sqlite3
|
||||
|
||||
# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db
|
||||
# database file will be recreated with each doxygen run. If set to NO, doxygen
|
||||
# will warn if an a database file is already found and not modify it.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
|
||||
|
||||
SQLITE3_RECREATE_DB = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -2187,7 +2364,8 @@ SEARCH_INCLUDES = YES
|
|||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by the
|
||||
# preprocessor.
|
||||
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
|
||||
# RECURSIVE has no effect here.
|
||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
||||
|
||||
INCLUDE_PATH =
|
||||
|
|
@ -2255,15 +2433,15 @@ TAGFILES =
|
|||
|
||||
GENERATE_TAGFILE =
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
|
||||
# the class index. If set to NO, only the inherited external classes will be
|
||||
# listed.
|
||||
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
|
||||
# will be listed in the class and namespace index. If set to NO, only the
|
||||
# inherited external classes will be listed.
|
||||
# The default value is: NO.
|
||||
|
||||
ALLEXTERNALS = NO
|
||||
|
||||
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
|
||||
# in the modules index. If set to NO, only the current project's groups will be
|
||||
# in the topic index. If set to NO, only the current project's groups will be
|
||||
# listed.
|
||||
# The default value is: YES.
|
||||
|
||||
|
|
@ -2277,16 +2455,9 @@ EXTERNAL_GROUPS = YES
|
|||
EXTERNAL_PAGES = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
# Configuration options related to diagram generator tools
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
# If left empty dia is assumed to be found in the default search path.
|
||||
|
||||
DIA_PATH =
|
||||
|
||||
# If set to YES the inheritance and collaboration graphs will hide inheritance
|
||||
# and usage relations if the target is undocumented or is not a class.
|
||||
# The default value is: YES.
|
||||
|
|
@ -2295,10 +2466,10 @@ HIDE_UNDOC_RELATIONS = YES
|
|||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz (see:
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: NO.
|
||||
# The default value is: YES.
|
||||
|
||||
HAVE_DOT = YES
|
||||
|
||||
|
|
@ -2312,37 +2483,51 @@ HAVE_DOT = YES
|
|||
|
||||
DOT_NUM_THREADS = 0
|
||||
|
||||
# When you want a differently looking font in the dot files that doxygen
|
||||
# generates you can specify the font name using DOT_FONTNAME. You need to make
|
||||
# sure dot is able to find the font, which can be done by putting it in a
|
||||
# standard location or by setting the DOTFONTPATH environment variable or by
|
||||
# setting DOT_FONTPATH to the directory containing the font.
|
||||
# The default value is: Helvetica.
|
||||
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
|
||||
# subgraphs. When you want a differently looking font in the dot files that
|
||||
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
|
||||
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
|
||||
# Edge and Graph Attributes specification</a> You need to make sure dot is able
|
||||
# to find the font, which can be done by putting it in a standard location or by
|
||||
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
|
||||
# directory containing the font. Default graphviz fontsize is 14.
|
||||
# The default value is: fontname=Helvetica,fontsize=10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
|
||||
|
||||
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
|
||||
# dot graphs.
|
||||
# Minimum value: 4, maximum value: 24, default value: 10.
|
||||
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
|
||||
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
|
||||
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
|
||||
# arrows shapes.</a>
|
||||
# The default value is: labelfontname=Helvetica,labelfontsize=10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
|
||||
|
||||
# By default doxygen will tell dot to use the default font as specified with
|
||||
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
|
||||
# the path where dot can find it using this tag.
|
||||
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
|
||||
# around nodes set 'shape=plain' or 'shape=plaintext' <a
|
||||
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
|
||||
# The default value is: shape=box,height=0.2,width=0.4.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
|
||||
|
||||
# You can set the path where dot can find font specified with fontname in
|
||||
# DOT_COMMON_ATTR and others dot attributes.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_FONTPATH =
|
||||
|
||||
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
||||
# graph for each documented class showing the direct and indirect inheritance
|
||||
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
||||
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
||||
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
||||
# links.
|
||||
# Possible values are: NO, YES, TEXT and GRAPH.
|
||||
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
|
||||
# generate a graph for each documented class showing the direct and indirect
|
||||
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
|
||||
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
|
||||
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
|
||||
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
|
||||
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
|
||||
# relations will be shown as texts / links.
|
||||
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
|
||||
# The default value is: YES.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
|
@ -2350,14 +2535,21 @@ CLASS_GRAPH = YES
|
|||
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
|
||||
# graph for each documented class showing the direct and indirect implementation
|
||||
# dependencies (inheritance, containment, and class references variables) of the
|
||||
# class with other documented classes.
|
||||
# class with other documented classes. Explicit enabling a collaboration graph,
|
||||
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
|
||||
# command \collaborationgraph. Disabling a collaboration graph can be
|
||||
# accomplished by means of the command \hidecollaborationgraph.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
COLLABORATION_GRAPH = NO
|
||||
|
||||
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
||||
# groups, showing the direct groups dependencies.
|
||||
# groups, showing the direct groups dependencies. Explicit enabling a group
|
||||
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
|
||||
# of the command \groupgraph. Disabling a directory graph can be accomplished by
|
||||
# means of the command \hidegroupgraph. See also the chapter Grouping in the
|
||||
# manual.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
|
|
@ -2417,7 +2609,9 @@ TEMPLATE_RELATIONS = NO
|
|||
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
|
||||
# YES then doxygen will generate a graph for each documented file showing the
|
||||
# direct and indirect include dependencies of the file with other documented
|
||||
# files.
|
||||
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
|
||||
# can be accomplished by means of the command \includegraph. Disabling an
|
||||
# include graph can be accomplished by means of the command \hideincludegraph.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
|
|
@ -2426,7 +2620,10 @@ INCLUDE_GRAPH = YES
|
|||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||
# set to YES then doxygen will generate a graph for each documented file showing
|
||||
# the direct and indirect include dependencies of the file with other documented
|
||||
# files.
|
||||
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
|
||||
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
|
||||
# an included by graph can be accomplished by means of the command
|
||||
# \hideincludedbygraph.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
|
|
@ -2466,7 +2663,10 @@ GRAPHICAL_HIERARCHY = YES
|
|||
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
|
||||
# dependencies a directory has on other directories in a graphical way. The
|
||||
# dependency relations are determined by the #include relations between the
|
||||
# files in the directories.
|
||||
# files in the directories. Explicit enabling a directory graph, when
|
||||
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
|
||||
# \directorygraph. Disabling a directory graph can be accomplished by means of
|
||||
# the command \hidedirectorygraph.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
|
|
@ -2482,12 +2682,13 @@ DIR_GRAPH_MAX_DEPTH = 1
|
|||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. For an explanation of the image formats see the section
|
||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||
# http://www.graphviz.org/)).
|
||||
# https://www.graphviz.org/)).
|
||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||
# requirement).
|
||||
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||
# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,
|
||||
# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,
|
||||
# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||
# png:gdiplus:gdiplus.
|
||||
# The default value is: png.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
|
@ -2519,11 +2720,12 @@ DOT_PATH =
|
|||
|
||||
DOTFILE_DIRS =
|
||||
|
||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain msc files that are included in the documentation (see the \mscfile
|
||||
# command).
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
# If left empty dia is assumed to be found in the default search path.
|
||||
|
||||
MSCFILE_DIRS =
|
||||
DIA_PATH =
|
||||
|
||||
# The DIAFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain dia files that are included in the documentation (see the \diafile
|
||||
|
|
@ -2573,18 +2775,6 @@ DOT_GRAPH_MAX_NODES = 20
|
|||
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
|
||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
||||
# background. This is disabled by default, because dot on Windows does not seem
|
||||
# to support this out of the box.
|
||||
#
|
||||
# Warning: Depending on the platform used, enabling this option may lead to
|
||||
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
|
||||
# read).
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_TRANSPARENT = YES
|
||||
|
||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||
|
|
@ -2612,3 +2802,19 @@ GENERATE_LEGEND = NO
|
|||
# The default value is: YES.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
# You can define message sequence charts within doxygen comments using the \msc
|
||||
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
|
||||
# use a built-in version of mscgen tool to produce the charts. Alternatively,
|
||||
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
|
||||
# specifying prog as the value, doxygen will call the tool as prog -T
|
||||
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
|
||||
# output file formats "png", "eps", "svg", and "ismap".
|
||||
|
||||
MSCGEN_TOOL =
|
||||
|
||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain msc files that are included in the documentation (see the \mscfile
|
||||
# command).
|
||||
|
||||
MSCFILE_DIRS =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,182 @@
|
|||
/* Skia overrides for doxygen CSS. */
|
||||
|
||||
html {
|
||||
--blue: rgb(0,114,178);
|
||||
--green: rgb(0,158,115);
|
||||
--red: rgb(213,94,0);
|
||||
--orange: rgb(230,159,0);
|
||||
--purple: rgb(204,121,167);
|
||||
--brown: rgb(177,89,40);
|
||||
--gray: rgb(79,79,79);
|
||||
--light-blue: rgb(128,185,217);
|
||||
--light-green: rgb(128,207,185);
|
||||
--light-red: rgb(234,175,128);
|
||||
--light-orange: rgb(243,207,128);
|
||||
--light-purple: rgb(230,188,211);
|
||||
--light-brown: rgb(216,172,148);
|
||||
--light-gray: rgb(168,168,168);
|
||||
|
||||
--dark-blue: rgb(0,65,101);
|
||||
--dark-red: rgb(156,44,8);
|
||||
|
||||
--white: rgb(254,254,254);
|
||||
--dark-white: rgb(240,240,240);
|
||||
--black: rgb(10,10,10);
|
||||
}
|
||||
|
||||
#titlearea {
|
||||
/* background matches Skia logo. */
|
||||
background: rgb(248,248,248);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
#main-nav .sm {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
h2.groupheader {
|
||||
border-bottom: var(--gray);
|
||||
color: var(--dark-blue);
|
||||
}
|
||||
|
||||
div.qindex, div.navtab{
|
||||
background-color: var(--light-gray);
|
||||
border: 1px solid var(--light-blue);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.contents a:visited {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
a.qindexHL {
|
||||
background-color: var(--light-gray);
|
||||
color: var(--white);
|
||||
border: 1px double var(--gray);
|
||||
}
|
||||
|
||||
.contents a.qindexHL:visited {
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
a.code, a.code:visited, a.line, a.line:visited {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
pre.fragment {
|
||||
border: 1px solid var(--orange);
|
||||
background-color: var(--dark-white);
|
||||
}
|
||||
|
||||
div.fragment {
|
||||
background-color: var(--dark-white);
|
||||
border: 1px solid var(--orange);
|
||||
}
|
||||
|
||||
span.lineno {
|
||||
border-right: 2px solid var(--green);
|
||||
background-color: var(-light-gray);
|
||||
}
|
||||
span.lineno a {
|
||||
background-color: var(--light-gray);
|
||||
}
|
||||
|
||||
span.lineno a:hover {
|
||||
background-color: var(--light-gray);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
div.ah, span.ah {
|
||||
background-color: var(--black);
|
||||
color: var(--white);
|
||||
border: solid thin var(--gray);
|
||||
box-shadow: 2px 2px 3px var(light-gray);
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
td.indexkey {
|
||||
background-color: var(--light-gray);
|
||||
border: 1px solid var(--orange);
|
||||
}
|
||||
|
||||
td.indexvalue {
|
||||
background-color: var(--light-gray);
|
||||
border: 1px solid var(--orange);
|
||||
}
|
||||
|
||||
tr.memlist {
|
||||
background-color: var(--light-gray);
|
||||
}
|
||||
|
||||
span.keyword {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: var(--brown);
|
||||
}
|
||||
|
||||
span.keywordflow {
|
||||
color: var(--brown);
|
||||
}
|
||||
|
||||
span.comment {
|
||||
color: var(--brown);
|
||||
}
|
||||
|
||||
span.charliteral {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
span.vhdldigit {
|
||||
color: var(--purple);
|
||||
}
|
||||
|
||||
span.vhdlchar {
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background-color: var(--light-gray);
|
||||
border-left: 2px solid var(--gray);
|
||||
}
|
||||
|
||||
.memtitle {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.memdoc, dl.reflist dd {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
color: var(--dark-red);
|
||||
}
|
||||
|
||||
.tabsearch {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.navpath ul {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.navpath li {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.navpath li.navelem a:hover {
|
||||
color: var(--blue)
|
||||
}
|
||||
|
||||
.navpath li.footer {
|
||||
background-image:none;
|
||||
}
|
||||
|
||||
|
|
@ -4,66 +4,65 @@
|
|||
|
||||
You will need:
|
||||
|
||||
1. The `documentation-xml-website` branch of the Edelhirsch QSkinny repository
|
||||
at https://github.com/edelhirsch/qskinny/tree/documentation-xml-website .
|
||||
1. A recent version of doxygen; The currently used version is 1.9.1 built from
|
||||
github sources. The `doxygen` binary needs to be in the $PATH.
|
||||
1. A recent version of doxybook2 with some custom patches. The script
|
||||
`generate-website.sh` should download and build the right version, however
|
||||
the script might need some adaptation of paths.
|
||||
For reference, the required version can be found at
|
||||
https://github.com/edelhirsch/doxybook2/tree/jekyll .
|
||||
1. A recent version of doxygen; The currently used version is 1.9.8.
|
||||
The `doxygen` binary needs to be in the $PATH.
|
||||
1. The `m4` command, which can be installed with `sudo apt install m4`.
|
||||
1. A recent version of Jekyll (see https://jekyllrb.com/), which will generate
|
||||
the static html pages. This and other required packages can be installed via
|
||||
the static html pages. The currently used jekyll version is 4.2.2.
|
||||
Also a recent version of bundler is required; this can be installed with:
|
||||
```
|
||||
gem install jekyll:3.9.0
|
||||
gem install jekyll:4.2.2
|
||||
gem install bundler:2.1.4
|
||||
```
|
||||
There might be some packages missing from the list above; in this case the
|
||||
Gemfile in the qskinny-website repository might help.
|
||||
1. Checkout the current website repository via
|
||||
1. Checkout the repo to generate the website via
|
||||
`git clone git@github.com:peter-ha/qskinny-website.git`
|
||||
1. Checkout the live website repository via
|
||||
`git clone git@github.com:qskinny/qskinny.github.io.git`
|
||||
|
||||
|
||||
## Generating the website
|
||||
|
||||
Generating the static HTML sites is done with the `generate-website.sh` script
|
||||
in the `qskinny/doc` directory. The script has some hardcoded paths and probably
|
||||
needs some adaptation to run correctly.
|
||||
### Generating the API documentation with doxygen
|
||||
```
|
||||
cd ~/dev/qskinny/doc
|
||||
export PATH=.:$PATH
|
||||
doxygen
|
||||
```
|
||||
This will generate the documentation into the `api` folder.
|
||||
|
||||
It will do the following:
|
||||
### Testing and building the website locally
|
||||
|
||||
1. Generate HTML from doxygen. This step is needed because for some reason when
|
||||
generating XML from doxygen there are no images with dependency graphs.
|
||||
*Note*: This step is only executed if the `html` folder doesn't exist,
|
||||
because otherwise it would take too long.
|
||||
1. Generate XML from doxygen. The generated XML is used with doxybook2 in the
|
||||
next step.
|
||||
*Note*: This step is only executed if the `xml` folder doesn't exist,
|
||||
because otherwise it would take too long.
|
||||
1. Generate markdown from XML with doxybook2. This markdown will be used by
|
||||
Jekyll to either server the website content locally or generate static
|
||||
HTML from it, see below.
|
||||
First copy the generated files from above to the website repo:
|
||||
|
||||
### Generating the website locally
|
||||
```
|
||||
cp -r api ~/dev/qskinny-website/docs/
|
||||
```
|
||||
|
||||
When the command line switch `-local` is used with the `generate-website.sh`
|
||||
script, it will generate the content to a local folder `doxybook-out`. This is
|
||||
meant to be able to copy selected files to the website directory at
|
||||
`~/dev/qskinny-website`.
|
||||
Otherwise, the script will copy the content to the website repository for
|
||||
uploading (again, paths are hardcoded as of now). So when generating content
|
||||
for the first time, just run the script without any switches, which should
|
||||
generate the website to `~/dev/qskinny-website`.
|
||||
Then test the website locally:
|
||||
|
||||
### Testing the website locally
|
||||
```
|
||||
cd ~/dev/qskinny-website
|
||||
bundle exec jekyll serve --livereload
|
||||
```
|
||||
|
||||
After having generated the website as described above, go to
|
||||
`~/dev/qskinny-website` and run `jekyll serve --livereload`. This should start
|
||||
a browser at http://127.0.0.1:4000/, which will display the website.
|
||||
Then direct your browser to `http://127.0.0.1:4000/`.
|
||||
|
||||
### Generating the website publicly
|
||||
If all looks good, generate the static HTML website:
|
||||
|
||||
When the command line switch `-publish` is used, the script will automatically
|
||||
generate a new version of the homepage and publish it at
|
||||
https://qskinny.github.io . This wil only work with the proper user rights of
|
||||
course.
|
||||
```
|
||||
bundle exec jekyll build
|
||||
```
|
||||
|
||||
### Publishing the website
|
||||
|
||||
Just copy over the generated HTML files to the public website repo and push a
|
||||
new version of the homepage:
|
||||
|
||||
```
|
||||
cp -r _site/* ~/dev/qskinny.github.io/
|
||||
cd ~/dev/qskinny.github.io/
|
||||
git commit -a -m "new version" # you might want to add new files
|
||||
gith push
|
||||
```
|
||||
|
||||
That's it, the new website is now published at https://qskinny.github.io/ .
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace
|
|||
public:
|
||||
enum Style
|
||||
{
|
||||
Continous,
|
||||
Continuous,
|
||||
Discrete,
|
||||
Centered
|
||||
};
|
||||
|
|
@ -33,15 +33,15 @@ namespace
|
|||
{
|
||||
case Discrete:
|
||||
{
|
||||
setSnap( true );
|
||||
setSnapping( true );
|
||||
setStepSize( 5 );
|
||||
setPageSteps( 4 );
|
||||
|
||||
break;
|
||||
}
|
||||
case Continous:
|
||||
case Continuous:
|
||||
{
|
||||
setSnap( false );
|
||||
setSnapping( false );
|
||||
setStepSize( 1 );
|
||||
setPageSteps( 10 );
|
||||
|
||||
|
|
@ -98,14 +98,20 @@ InputPage::InputPage( QQuickItem* parent )
|
|||
{
|
||||
Slider* continous;
|
||||
Slider* discrete;
|
||||
Slider* centered;
|
||||
} sliders[2];
|
||||
|
||||
for ( int i = 0; i < 2; i++ )
|
||||
{
|
||||
const auto orientation = static_cast< Qt::Orientation >( i + 1 );
|
||||
|
||||
sliders[i].continous = new Slider( orientation, Slider::Continous );
|
||||
sliders[i].continous = new Slider( orientation, Slider::Continuous );
|
||||
sliders[i].discrete = new Slider( orientation, Slider::Discrete );
|
||||
|
||||
auto slider = new Slider( orientation, Slider::Continuous );
|
||||
slider->setOrigin( slider->minimum()
|
||||
+ 0.5 * ( slider->maximum() - slider->minimum() ) );
|
||||
sliders[i].centered = slider;
|
||||
}
|
||||
|
||||
auto spinBox = new QskSpinBox( 0.0, 100.0, 1.0 );
|
||||
|
|
@ -120,6 +126,7 @@ InputPage::InputPage( QQuickItem* parent )
|
|||
|
||||
vBox->addItem( sliders[0].continous );
|
||||
vBox->addItem( sliders[0].discrete );
|
||||
vBox->addItem( sliders[0].centered );
|
||||
vBox->addItem( inputBox );
|
||||
vBox->addItem( spinBox );
|
||||
|
||||
|
|
@ -127,6 +134,7 @@ InputPage::InputPage( QQuickItem* parent )
|
|||
mainBox->setSpacing( 30 );
|
||||
mainBox->addItem( sliders[1].continous );
|
||||
mainBox->addItem( sliders[1].discrete );
|
||||
mainBox->addItem( sliders[1].centered );
|
||||
mainBox->addItem( vBox );
|
||||
|
||||
auto inputs = findChildren< QskBoundedValueInput* >();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ QSK_SUBCONTROL( LightDisplay, Tickmarks )
|
|||
QSK_SUBCONTROL( LightDisplay, ValueText )
|
||||
QSK_SUBCONTROL( LightDisplay, LeftLabel )
|
||||
QSK_SUBCONTROL( LightDisplay, RightLabel )
|
||||
QSK_SUBCONTROL( LightDisplay, Knob )
|
||||
QSK_SUBCONTROL( LightDisplay, Handle )
|
||||
|
||||
QSK_STATE( LightDisplay, Pressed, ( QskAspect::FirstUserState << 1 ) )
|
||||
|
||||
|
|
@ -44,6 +44,8 @@ LightDisplay::LightDisplay( QQuickItem* parent )
|
|||
setAlignmentHint( ValueText, Qt::AlignRight );
|
||||
|
||||
setBoundaries( 0, 100 );
|
||||
setStepSize( 1.0 );
|
||||
setPageSteps( 10 );
|
||||
}
|
||||
|
||||
bool LightDisplay::isPressed() const
|
||||
|
|
@ -53,16 +55,14 @@ bool LightDisplay::isPressed() const
|
|||
|
||||
void LightDisplay::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
QRectF handleRect = subControlRect( LightDisplay::Knob );
|
||||
|
||||
const auto handleRect = subControlRect( LightDisplay::Handle );
|
||||
if ( handleRect.contains( event->pos() ) )
|
||||
{
|
||||
setSkinStateFlag( Pressed );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
QskBoundedValueInput::mousePressEvent( event );
|
||||
}
|
||||
|
||||
Inherited::mousePressEvent( event );
|
||||
}
|
||||
|
||||
void LightDisplay::mouseMoveEvent( QMouseEvent* event )
|
||||
|
|
@ -73,19 +73,17 @@ void LightDisplay::mouseMoveEvent( QMouseEvent* event )
|
|||
const auto mousePos = qskMousePosition( event );
|
||||
const auto rect = subControlRect( ColdAndWarmArc );
|
||||
|
||||
bool arcContainsMousePos = arcContainsPoint( rect, mousePos );
|
||||
|
||||
if( !arcContainsMousePos )
|
||||
if( !arcContainsPoint( rect, mousePos ) )
|
||||
{
|
||||
setSkinStateFlag( Pressed, false );
|
||||
return;
|
||||
}
|
||||
|
||||
const auto metrics = arcMetricsHint( ColdAndWarmArc );
|
||||
qreal angle = angleFromPoint( rect, mousePos );
|
||||
|
||||
const int tolerance = 20;
|
||||
|
||||
auto angle = angleFromPoint( rect, mousePos );
|
||||
if( !angleInRange( metrics, angle ) )
|
||||
{
|
||||
// we're slightly outside the range, but don't want to give up
|
||||
|
|
@ -101,7 +99,7 @@ void LightDisplay::mouseMoveEvent( QMouseEvent* event )
|
|||
}
|
||||
}
|
||||
|
||||
qreal ratio = ( metrics.spanAngle() - angle ) / metrics.spanAngle();
|
||||
const auto ratio = ( metrics.spanAngle() - angle ) / metrics.spanAngle();
|
||||
setValueAsRatio( ratio );
|
||||
}
|
||||
|
||||
|
|
@ -110,14 +108,29 @@ void LightDisplay::mouseReleaseEvent( QMouseEvent* /*event*/ )
|
|||
setSkinStateFlag( Pressed, false );
|
||||
}
|
||||
|
||||
void LightDisplay::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
switch( event->key() )
|
||||
{
|
||||
case Qt::Key_Left:
|
||||
increment( -stepSize() );
|
||||
return;
|
||||
|
||||
case Qt::Key_Right:
|
||||
increment( stepSize() );
|
||||
return;
|
||||
}
|
||||
|
||||
Inherited::keyPressEvent( event );
|
||||
}
|
||||
|
||||
qreal LightDisplay::angleFromPoint( const QRectF& rect, const QPointF& point ) const
|
||||
{
|
||||
QPointF circlePos( point.x() - rect.center().x(),
|
||||
const QPointF circlePos( point.x() - rect.center().x(),
|
||||
rect.center().y() - point.y() );
|
||||
|
||||
const qreal atan = qAtan2( circlePos.y(), circlePos.x() );
|
||||
const qreal angle = qRadiansToDegrees( atan );
|
||||
return angle;
|
||||
const qreal angle = qAtan2( circlePos.y(), circlePos.x() );
|
||||
return qRadiansToDegrees( angle );
|
||||
}
|
||||
|
||||
bool LightDisplay::arcContainsPoint( const QRectF& rect, const QPointF& point ) const
|
||||
|
|
@ -148,9 +161,7 @@ bool LightDisplay::arcContainsPoint( const QRectF& rect, const QPointF& point )
|
|||
const bool pointOnArc = ( polarRadius + tolerance ) > radiusMin
|
||||
&& ( polarRadius - tolerance ) < radiusMax;
|
||||
|
||||
bool ret = angleWithinRange && pointOnArc;
|
||||
|
||||
return ret;
|
||||
return angleWithinRange && pointOnArc;
|
||||
}
|
||||
|
||||
#include "moc_LightDisplay.cpp"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@ class LightDisplay : public QskBoundedValueInput
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
using Inherited = QskBoundedValueInput;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, Groove, ColdAndWarmArc, Tickmarks, ValueText,
|
||||
LeftLabel, RightLabel, Knob ) // ### rename knob to handle?
|
||||
QSK_SUBCONTROLS( Panel, Groove, ColdAndWarmArc, Tickmarks,
|
||||
ValueText, LeftLabel, RightLabel, Handle )
|
||||
|
||||
QSK_STATES( Pressed )
|
||||
|
||||
LightDisplay( QQuickItem* parent = nullptr );
|
||||
|
|
@ -22,9 +25,11 @@ class LightDisplay : public QskBoundedValueInput
|
|||
bool isPressed() const;
|
||||
|
||||
protected:
|
||||
void mousePressEvent( QMouseEvent* e ) override;
|
||||
void mouseMoveEvent( QMouseEvent* e ) override;
|
||||
void mouseReleaseEvent( QMouseEvent* e ) override;
|
||||
void mousePressEvent( QMouseEvent* ) override;
|
||||
void mouseMoveEvent( QMouseEvent* ) override;
|
||||
void mouseReleaseEvent( QMouseEvent* ) override;
|
||||
|
||||
void keyPressEvent( QKeyEvent* ) override;
|
||||
|
||||
private:
|
||||
qreal angleFromPoint( const QRectF&, const QPointF& ) const;
|
||||
|
|
|
|||
|
|
@ -105,12 +105,12 @@ QRectF LightDisplaySkinlet::subControlRect( const QskSkinnable* skinnable,
|
|||
|
||||
return rect;
|
||||
}
|
||||
else if( subControl == LightDisplay::Knob )
|
||||
else if( subControl == LightDisplay::Handle )
|
||||
{
|
||||
const auto arcRect = subControlRect( skinnable,
|
||||
contentsRect, LightDisplay::ColdAndWarmArc );
|
||||
const auto arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
|
||||
const auto knobSize = display->strutSizeHint( LightDisplay::Knob );
|
||||
const auto knobSize = display->strutSizeHint( LightDisplay::Handle );
|
||||
|
||||
const qreal radius = ( arcRect.width() - arcMetrics.thickness() ) / 2;
|
||||
const qreal angle = display->valueAsRatio() * 180;
|
||||
|
|
@ -183,7 +183,7 @@ QSGNode* LightDisplaySkinlet::updateSubNode(
|
|||
}
|
||||
case KnobRole:
|
||||
{
|
||||
return updateBoxNode( skinnable, node, LightDisplay::Knob );
|
||||
return updateBoxNode( skinnable, node, LightDisplay::Handle );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -241,9 +241,9 @@ void Skin::initHints()
|
|||
ed.setFontRole( LightDisplay::ValueText, QskFontRole::Headline );
|
||||
ed.setColor( LightDisplay::ValueText, 0xff929cb2 );
|
||||
|
||||
ed.setStrutSize( LightDisplay::Knob, { 20, 20 } );
|
||||
ed.setBoxBorderMetrics( LightDisplay::Knob, 1 );
|
||||
ed.setBoxShape( LightDisplay::Knob, 100, Qt::RelativeSize );
|
||||
ed.setStrutSize( LightDisplay::Handle, { 20, 20 } );
|
||||
ed.setBoxBorderMetrics( LightDisplay::Handle, 1 );
|
||||
ed.setBoxShape( LightDisplay::Handle, 100, Qt::RelativeSize );
|
||||
|
||||
// palette dependent skin hints:
|
||||
ed.setGradient( MenuBar::Panel, palette.menuBar );
|
||||
|
|
@ -265,9 +265,9 @@ void Skin::initHints()
|
|||
ed.setShadowColor( UsageDiagramBox::Panel, palette.shadow );
|
||||
|
||||
ed.setGradient( LightDisplay::Panel, palette.box );
|
||||
ed.setGradient( LightDisplay::Knob, palette.box );
|
||||
ed.setGradient( LightDisplay::Handle, palette.box );
|
||||
ed.setGradient( LightDisplay::ColdAndWarmArc, palette.lightDisplayColdAndWarmArc );
|
||||
ed.setBoxBorderColors( LightDisplay::Knob, palette.lightDisplayKnobBorder );
|
||||
ed.setBoxBorderColors( LightDisplay::Handle, palette.lightDisplayKnobBorder );
|
||||
ed.setShadowMetrics( LightDisplay::Groove, { 0, 20 } );
|
||||
ed.setShadowColor( LightDisplay::Groove, palette.shadow );
|
||||
ed.setGradient( LightDisplay::Groove, palette.box );
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ QSK_SUBCONTROL( Dial, Needle )
|
|||
Dial::Dial( QQuickItem* parent )
|
||||
: QskBoundedValueInput( parent )
|
||||
{
|
||||
setReadOnly( true );
|
||||
}
|
||||
|
||||
QVector< QString > Dial::tickLabels() const
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#include <QskSkinlet.h>
|
||||
|
||||
#include <QskQuick.h>
|
||||
#include <QskBoxClipNode.h>
|
||||
#include <QskClipNode.h>
|
||||
#include <QskBoxBorderMetrics.h>
|
||||
|
||||
#include <qsgnode.h>
|
||||
|
|
@ -315,7 +315,7 @@ void QskPlotView::updateNode( QSGNode* node )
|
|||
if ( m_data->needsClipping() )
|
||||
{
|
||||
if ( itemsNode == nullptr || itemsNode->type() != QSGNode::ClipNodeType )
|
||||
itemsNode = new QskBoxClipNode();
|
||||
itemsNode = new QskClipNode();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ Slider::Slider( const QString& text, qreal min, qreal max,
|
|||
m_slider = new QskSlider( this );
|
||||
m_slider->setBoundaries( min, max );
|
||||
m_slider->setStepSize( step );
|
||||
m_slider->setSnap( true );
|
||||
m_slider->setSnapping( true );
|
||||
m_slider->setValue( value );
|
||||
|
||||
m_valueLabel = new QskTextLabel( this );
|
||||
|
|
|
|||
|
|
@ -105,13 +105,13 @@ list(APPEND HEADERS
|
|||
nodes/QskArcRenderNode.h
|
||||
nodes/QskBasicLinesNode.h
|
||||
nodes/QskBoxNode.h
|
||||
nodes/QskBoxClipNode.h
|
||||
nodes/QskBoxRectangleNode.h
|
||||
nodes/QskBoxRenderer.h
|
||||
nodes/QskBoxMetrics.h
|
||||
nodes/QskBoxBasicStroker.h
|
||||
nodes/QskBoxGradientStroker.h
|
||||
nodes/QskBoxShadowNode.h
|
||||
nodes/QskClipNode.h
|
||||
nodes/QskColorRamp.h
|
||||
nodes/QskFillNode.h
|
||||
nodes/QskGraduationNode.h
|
||||
|
|
@ -145,13 +145,13 @@ list(APPEND SOURCES
|
|||
nodes/QskArcRenderNode.cpp
|
||||
nodes/QskBasicLinesNode.cpp
|
||||
nodes/QskBoxNode.cpp
|
||||
nodes/QskBoxClipNode.cpp
|
||||
nodes/QskBoxRectangleNode.cpp
|
||||
nodes/QskBoxRenderer.cpp
|
||||
nodes/QskBoxMetrics.cpp
|
||||
nodes/QskBoxBasicStroker.cpp
|
||||
nodes/QskBoxGradientStroker.cpp
|
||||
nodes/QskBoxShadowNode.cpp
|
||||
nodes/QskClipNode.cpp
|
||||
nodes/QskColorRamp.cpp
|
||||
nodes/QskFillNode.cpp
|
||||
nodes/QskGraduationNode.cpp
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ namespace Qsk
|
|||
{
|
||||
Q_NAMESPACE_EXPORT( QSK_EXPORT )
|
||||
|
||||
enum Policy
|
||||
{
|
||||
Maybe,
|
||||
Always,
|
||||
Never
|
||||
};
|
||||
Q_ENUM_NS( Policy )
|
||||
|
||||
enum Direction
|
||||
{
|
||||
LeftToRight,
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@ class QSK_EXPORT QskBoundedControl : public QskControl
|
|||
|
||||
void componentComplete() override;
|
||||
|
||||
private:
|
||||
void adjustBoundaries( bool increasing );
|
||||
|
||||
private:
|
||||
qreal m_minimum;
|
||||
qreal m_maximum;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class QskBoundedInput::PrivateData
|
|||
qreal stepSize = 0.1;
|
||||
uint pageSteps = 1;
|
||||
|
||||
bool snap = false;
|
||||
bool snapping = false;
|
||||
};
|
||||
|
||||
QskBoundedInput::QskBoundedInput( QQuickItem* parent )
|
||||
|
|
@ -53,7 +53,7 @@ void QskBoundedInput::setStepSize( qreal stepSize )
|
|||
|
||||
if ( isComponentComplete() )
|
||||
{
|
||||
if ( m_data->snap && stepSize )
|
||||
if ( m_data->snapping && stepSize )
|
||||
alignInput();
|
||||
}
|
||||
}
|
||||
|
|
@ -102,21 +102,21 @@ void QskBoundedInput::pageDown()
|
|||
increment( -pageSize() );
|
||||
}
|
||||
|
||||
void QskBoundedInput::setSnap( bool snap )
|
||||
void QskBoundedInput::setSnapping( bool on )
|
||||
{
|
||||
if ( m_data->snap == snap )
|
||||
if ( m_data->snapping == on )
|
||||
return;
|
||||
|
||||
m_data->snap = snap;
|
||||
Q_EMIT snapChanged( snap );
|
||||
m_data->snapping = on;
|
||||
Q_EMIT snappingChanged( on );
|
||||
|
||||
if ( isComponentComplete() && snap )
|
||||
if ( isComponentComplete() && m_data->snapping )
|
||||
alignInput();
|
||||
}
|
||||
|
||||
bool QskBoundedInput::snap() const
|
||||
bool QskBoundedInput::isSnapping() const
|
||||
{
|
||||
return m_data->snap;
|
||||
return m_data->snapping;
|
||||
}
|
||||
|
||||
void QskBoundedInput::componentComplete()
|
||||
|
|
@ -134,38 +134,6 @@ void QskBoundedInput::alignInput()
|
|||
{
|
||||
}
|
||||
|
||||
qreal QskBoundedInput::alignedValue( qreal value ) const
|
||||
{
|
||||
value = boundedValue( value );
|
||||
|
||||
if ( value > minimum() && value < maximum() )
|
||||
{
|
||||
if ( m_data->snap && m_data->stepSize )
|
||||
{
|
||||
value = qRound( value / m_data->stepSize ) * m_data->stepSize;
|
||||
value = boundedValue( value );
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
QskIntervalF QskBoundedInput::alignedInterval( const QskIntervalF& interval ) const
|
||||
{
|
||||
if ( m_data->snap )
|
||||
{
|
||||
if ( const auto step = m_data->stepSize )
|
||||
{
|
||||
const qreal lower = std::floor( interval.lowerBound() / step ) * step;
|
||||
const qreal upper = std::ceil( interval.upperBound() / step ) * step;
|
||||
|
||||
return QskIntervalF( lower, upper );
|
||||
}
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
void QskBoundedInput::setReadOnly( bool readOnly )
|
||||
{
|
||||
if ( readOnly == isReadOnly() )
|
||||
|
|
@ -204,15 +172,6 @@ qreal QskBoundedInput::incrementForKey( const QKeyEvent* event ) const
|
|||
|
||||
case Qt::Key_PageDown:
|
||||
return -pageSize();
|
||||
|
||||
default:
|
||||
{
|
||||
if ( qskIsStandardKeyInput( event, QKeySequence::MoveToNextChar ) )
|
||||
return m_data->stepSize;
|
||||
|
||||
if ( qskIsStandardKeyInput( event, QKeySequence::MoveToPreviousChar ) )
|
||||
return -m_data->stepSize;
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class QSK_EXPORT QskBoundedInput : public QskBoundedControl
|
|||
Q_PROPERTY( qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged )
|
||||
Q_PROPERTY( uint pageSteps READ pageSteps WRITE setPageSteps NOTIFY pageStepsChanged )
|
||||
|
||||
Q_PROPERTY( bool snap READ snap WRITE setSnap NOTIFY snapChanged )
|
||||
Q_PROPERTY( bool snapping READ isSnapping WRITE setSnapping NOTIFY snappingChanged )
|
||||
Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged )
|
||||
|
||||
using Inherited = QskBoundedControl;
|
||||
|
|
@ -30,10 +30,10 @@ class QSK_EXPORT QskBoundedInput : public QskBoundedControl
|
|||
|
||||
qreal stepSize() const;
|
||||
qreal pageSize() const; // pageSteps() * stepSize()
|
||||
uint pageSteps() const;
|
||||
uint pageSteps() const;
|
||||
|
||||
void setSnap( bool );
|
||||
bool snap() const;
|
||||
void setSnapping( bool );
|
||||
bool isSnapping() const;
|
||||
|
||||
void setReadOnly( bool );
|
||||
bool isReadOnly() const;
|
||||
|
|
@ -52,7 +52,7 @@ class QSK_EXPORT QskBoundedInput : public QskBoundedControl
|
|||
Q_SIGNALS:
|
||||
void stepSizeChanged( qreal );
|
||||
void pageStepsChanged( qreal );
|
||||
void snapChanged( bool );
|
||||
void snappingChanged( bool );
|
||||
|
||||
void readOnlyChanged( bool );
|
||||
|
||||
|
|
@ -66,9 +66,6 @@ class QSK_EXPORT QskBoundedInput : public QskBoundedControl
|
|||
void componentComplete() override;
|
||||
virtual void alignInput();
|
||||
|
||||
qreal alignedValue( qreal ) const;
|
||||
QskIntervalF alignedInterval( const QskIntervalF& ) const;
|
||||
|
||||
qreal incrementForKey( const QKeyEvent* ) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -88,7 +88,9 @@ void QskBoundedRangeInput::setRange( const QskIntervalF& range )
|
|||
|
||||
if ( isComponentComplete() )
|
||||
{
|
||||
newRange = alignedInterval( newRange );
|
||||
if ( isSnapping() && stepSize() )
|
||||
newRange = newRange.fuzzyAligned( stepSize() );
|
||||
|
||||
newRange = fixupRange( newRange );
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +130,11 @@ QskIntervalF QskBoundedRangeInput::range() const
|
|||
|
||||
void QskBoundedRangeInput::alignInput()
|
||||
{
|
||||
setRangeInternal( alignedInterval( m_range ) );
|
||||
auto newRange = m_range;
|
||||
if ( isSnapping() && stepSize() )
|
||||
newRange = newRange.fuzzyAligned( stepSize() );
|
||||
|
||||
setRangeInternal( newRange );
|
||||
}
|
||||
|
||||
QskIntervalF QskBoundedRangeInput::fixupRange( const QskIntervalF& range ) const
|
||||
|
|
|
|||
|
|
@ -9,6 +9,24 @@
|
|||
#include <qlocale.h>
|
||||
#include <cfloat>
|
||||
|
||||
static qreal qskAlignedValue( const QskBoundedValueInput* input, qreal value )
|
||||
{
|
||||
value = input->boundedValue( value );
|
||||
|
||||
if ( value > input->minimum() && value < input->maximum() )
|
||||
{
|
||||
if ( input->isSnapping() && input->stepSize() )
|
||||
{
|
||||
const auto step = input->stepSize();
|
||||
|
||||
value = qRound( value / step ) * step;
|
||||
value = input->boundedValue( value );
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
class QskBoundedValueInput::PrivateData
|
||||
{
|
||||
public:
|
||||
|
|
@ -43,9 +61,25 @@ int QskBoundedValueInput::decimals() const
|
|||
return m_data->decimals;
|
||||
}
|
||||
|
||||
void QskBoundedValueInput::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
switch( event->key() )
|
||||
{
|
||||
case Qt::Key_Home:
|
||||
setValue( minimum() );
|
||||
break;
|
||||
|
||||
case Qt::Key_End:
|
||||
setValue( maximum() );
|
||||
break;
|
||||
}
|
||||
|
||||
Inherited::keyPressEvent( event );
|
||||
}
|
||||
|
||||
void QskBoundedValueInput::alignInput()
|
||||
{
|
||||
auto value = alignedValue( m_data->value );
|
||||
auto value = qskAlignedValue( this, m_data->value );
|
||||
value = fixupValue( value );
|
||||
|
||||
setValueInternal( value );
|
||||
|
|
@ -71,7 +105,7 @@ void QskBoundedValueInput::setValue( qreal value )
|
|||
{
|
||||
if ( isComponentComplete() )
|
||||
{
|
||||
value = alignedValue( value );
|
||||
value = qskAlignedValue( this, value );
|
||||
value = fixupValue( value );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ class QSK_EXPORT QskBoundedValueInput : public QskBoundedInput
|
|||
void decimalsChanged( int );
|
||||
|
||||
protected:
|
||||
void keyPressEvent( QKeyEvent* ) override;
|
||||
|
||||
virtual qreal fixupValue( qreal ) const;
|
||||
void alignInput() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class QskPageIndicator::PrivateData
|
|||
int pressedIndex = -1;
|
||||
|
||||
int count;
|
||||
Qt::Orientation orientation : 2;
|
||||
Qt::Orientation orientation;
|
||||
};
|
||||
|
||||
QskPageIndicator::QskPageIndicator( int count, QQuickItem* parent )
|
||||
|
|
|
|||
|
|
@ -13,44 +13,76 @@
|
|||
|
||||
using Q = QskProgressBar;
|
||||
|
||||
namespace
|
||||
static QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
|
||||
{
|
||||
QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
|
||||
qreal pos1, pos2;
|
||||
|
||||
if ( indicator->isIndeterminate() )
|
||||
{
|
||||
qreal pos1, pos2;
|
||||
const auto pos = indicator->positionHint( Q::Fill );
|
||||
|
||||
if ( indicator->isIndeterminate() )
|
||||
{
|
||||
const auto pos = indicator->positionHint( QskProgressIndicator::Fill );
|
||||
static const QEasingCurve curve( QEasingCurve::InOutCubic );
|
||||
|
||||
static const QEasingCurve curve( QEasingCurve::InOutCubic );
|
||||
const qreal off = 0.15;
|
||||
|
||||
const qreal off = 0.15;
|
||||
|
||||
pos1 = curve.valueForProgress( qMax( pos - off, 0.0 ) );
|
||||
pos2 = curve.valueForProgress( qMin( pos + off, 1.0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pos1 = indicator->valueAsRatio( indicator->origin() );
|
||||
pos2 = indicator->valueAsRatio( indicator->value() );
|
||||
}
|
||||
|
||||
auto bar = static_cast< const QskProgressBar* >( indicator );
|
||||
if( bar->orientation() == Qt::Horizontal )
|
||||
{
|
||||
if ( bar->layoutMirroring() )
|
||||
{
|
||||
pos1 = 1.0 - pos1;
|
||||
pos2 = 1.0 - pos2;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pos1 > pos2 )
|
||||
std::swap( pos1, pos2 );
|
||||
|
||||
return QskIntervalF( pos1, pos2 );
|
||||
pos1 = curve.valueForProgress( qMax( pos - off, 0.0 ) );
|
||||
pos2 = curve.valueForProgress( qMin( pos + off, 1.0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pos1 = indicator->valueAsRatio( indicator->origin() );
|
||||
pos2 = indicator->valueAsRatio( indicator->value() );
|
||||
}
|
||||
|
||||
auto bar = static_cast< const QskProgressBar* >( indicator );
|
||||
if( bar->orientation() == Qt::Horizontal )
|
||||
{
|
||||
if ( bar->layoutMirroring() )
|
||||
{
|
||||
pos1 = 1.0 - pos1;
|
||||
pos2 = 1.0 - pos2;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pos1 > pos2 )
|
||||
std::swap( pos1, pos2 );
|
||||
|
||||
return QskIntervalF( pos1, pos2 );
|
||||
}
|
||||
|
||||
static QskGradient qskFillGradient( const QskProgressBar* progressBar )
|
||||
{
|
||||
auto gradient = progressBar->gradientHint( Q::Fill );
|
||||
|
||||
if ( gradient.isVisible() && !gradient.isMonochrome()
|
||||
&& ( gradient.type() == QskGradient::Stops ) )
|
||||
{
|
||||
/*
|
||||
When having stops only we use a linear gradient,
|
||||
where the colors are increasing in direction of the
|
||||
progress value. We interprete the gradient as a
|
||||
definition for the 100% situation and have to adjust
|
||||
the stops for smaller bars.
|
||||
|
||||
For this situation it would be more convenient to
|
||||
adjust the start/stop positions, but the box renderer is
|
||||
not supporting this yet. TODO ...
|
||||
*/
|
||||
|
||||
const auto intv = qskFillInterval( progressBar );
|
||||
|
||||
const auto stops = qskExtractedGradientStops(
|
||||
gradient.stops(), intv.lowerBound(), intv.upperBound() );
|
||||
|
||||
gradient.setStops( stops );
|
||||
|
||||
gradient.setLinearDirection( progressBar->orientation() );
|
||||
|
||||
if ( progressBar->orientation() == Qt::Vertical || progressBar->layoutMirroring() )
|
||||
gradient.reverse();
|
||||
}
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
QskProgressBarSkinlet::QskProgressBarSkinlet( QskSkin* skin )
|
||||
|
|
@ -69,28 +101,10 @@ QRectF QskProgressBarSkinlet::subControlRect(
|
|||
const auto bar = static_cast< const Q* >( skinnable );
|
||||
|
||||
if( subControl == Q::Groove )
|
||||
{
|
||||
const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size );
|
||||
|
||||
auto rect = contentsRect;
|
||||
if ( bar->orientation() == Qt::Horizontal )
|
||||
{
|
||||
rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) );
|
||||
rect.setHeight( grooveSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) );
|
||||
rect.setWidth( grooveSize );
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
return grooveRect( bar, contentsRect );
|
||||
|
||||
if( subControl == Q::Fill )
|
||||
{
|
||||
return barRect( bar );
|
||||
}
|
||||
return fillRect( bar );
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
|
@ -104,76 +118,61 @@ QSGNode* QskProgressBarSkinlet::updateGrooveNode(
|
|||
QSGNode* QskProgressBarSkinlet::updateFillNode(
|
||||
const QskProgressIndicator* indicator, QSGNode* node ) const
|
||||
{
|
||||
const auto bar = static_cast< const Q* >( indicator );
|
||||
|
||||
const auto subControl = Q::Fill;
|
||||
|
||||
const auto rect = indicator->subControlRect( subControl );
|
||||
const auto rect = indicator->subControlRect( Q::Fill );
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
auto gradient = indicator->gradientHint( subControl );
|
||||
if ( !gradient.isVisible() )
|
||||
return nullptr;
|
||||
|
||||
if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() )
|
||||
{
|
||||
/*
|
||||
When having stops only we use a linear gradient,
|
||||
where the colors are increasing in direction of the
|
||||
progress value. We interprete the gradient as a
|
||||
definition for the 100% situation and have to adjust
|
||||
the stops for smaller bars.
|
||||
|
||||
For this situation it would be more convenient to
|
||||
adjust the start/stop positions, but the box renderer is
|
||||
not supporting this yet. TODO ...
|
||||
*/
|
||||
|
||||
const auto intv = qskFillInterval( bar );
|
||||
|
||||
const auto stops = qskExtractedGradientStops( gradient.stops(),
|
||||
intv.lowerBound(), intv.upperBound() );
|
||||
|
||||
gradient.setStops( stops );
|
||||
|
||||
gradient.setLinearDirection( static_cast< Qt::Orientation >( bar->orientation() ) );
|
||||
|
||||
if ( bar->orientation() == Qt::Vertical || bar->layoutMirroring() )
|
||||
gradient.reverse();
|
||||
}
|
||||
|
||||
return updateBoxNode( indicator, node, rect, gradient, subControl );
|
||||
const auto progressBar = static_cast< const Q* >( indicator );
|
||||
return updateBoxNode( indicator, node, rect,
|
||||
qskFillGradient( progressBar ), Q::Fill );
|
||||
}
|
||||
|
||||
QRectF QskProgressBarSkinlet::barRect( const Q* bar ) const
|
||||
QRectF QskProgressBarSkinlet::grooveRect(
|
||||
const QskProgressBar* progressBar, const QRectF& contentsRect ) const
|
||||
{
|
||||
const auto subControl = Q::Groove;
|
||||
const auto size = progressBar->metric( Q::Groove | QskAspect::Size );
|
||||
|
||||
const auto barSize = bar->metric( Q::Fill | QskAspect::Size );
|
||||
auto rect = bar->subControlRect( subControl );
|
||||
|
||||
if ( bar->orientation() == Qt::Horizontal )
|
||||
auto rect = contentsRect;
|
||||
if ( progressBar->orientation() == Qt::Horizontal )
|
||||
{
|
||||
rect.setY( rect.y() + 0.5 * ( rect.height() - barSize ) );
|
||||
rect.setHeight( barSize );
|
||||
rect.setY( rect.y() + 0.5 * ( rect.height() - size ) );
|
||||
rect.setHeight( size );
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.setX( rect.x() + 0.5 * ( rect.width() - barSize ) );
|
||||
rect.setWidth( barSize );
|
||||
rect.setX( rect.x() + 0.5 * ( rect.width() - size ) );
|
||||
rect.setWidth( size );
|
||||
}
|
||||
|
||||
const auto borderMetrics = bar->boxBorderMetricsHint( subControl );
|
||||
return rect;
|
||||
}
|
||||
|
||||
auto m = bar->paddingHint( subControl );
|
||||
QRectF QskProgressBarSkinlet::fillRect( const QskProgressBar* progressBar ) const
|
||||
{
|
||||
const auto size = progressBar->metric( Q::Fill | QskAspect::Size );
|
||||
auto rect = progressBar->subControlRect( Q::Groove );
|
||||
|
||||
if ( progressBar->orientation() == Qt::Horizontal )
|
||||
{
|
||||
rect.setY( rect.y() + 0.5 * ( rect.height() - size ) );
|
||||
rect.setHeight( size );
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.setX( rect.x() + 0.5 * ( rect.width() - size ) );
|
||||
rect.setWidth( size );
|
||||
}
|
||||
|
||||
const auto borderMetrics = progressBar->boxBorderMetricsHint( Q::Groove );
|
||||
|
||||
auto m = progressBar->paddingHint( Q::Groove );
|
||||
m += 0.5 * borderMetrics.toAbsolute( rect.size() ).widths();
|
||||
|
||||
rect = rect.marginsRemoved( m );
|
||||
|
||||
const auto intv = qskFillInterval( bar );
|
||||
const auto intv = qskFillInterval( progressBar );
|
||||
|
||||
if( bar->orientation() == Qt::Horizontal )
|
||||
if( progressBar->orientation() == Qt::Horizontal )
|
||||
{
|
||||
const auto w = rect.width();
|
||||
|
||||
|
|
@ -197,11 +196,12 @@ QSizeF QskProgressBarSkinlet::sizeHint( const QskSkinnable* skinnable,
|
|||
if ( which != Qt::PreferredSize )
|
||||
return QSizeF();
|
||||
|
||||
const auto bar = static_cast< const Q* >( skinnable );
|
||||
auto extent = skinnable->metric( Q::Groove | QskAspect::Size );
|
||||
extent = qMax( extent, skinnable->metric( Q::Fill | QskAspect::Size ) );
|
||||
|
||||
const auto extent = bar->extent();
|
||||
const auto progressBar = static_cast< const QskProgressBar* >( skinnable );
|
||||
|
||||
if ( bar->orientation() == Qt::Horizontal )
|
||||
if ( progressBar->orientation() == Qt::Horizontal )
|
||||
return QSizeF( -1, extent );
|
||||
else
|
||||
return QSizeF( extent, -1 );
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ class QSK_EXPORT QskProgressBarSkinlet : public QskProgressIndicatorSkinlet
|
|||
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
|
||||
|
||||
private:
|
||||
QRectF barRect( const QskProgressBar* ) const;
|
||||
QRectF fillRect( const QskProgressBar* ) const;
|
||||
QRectF grooveRect( const QskProgressBar*, const QRectF& ) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -148,9 +148,7 @@ void QskProgressIndicator::resetExtent()
|
|||
|
||||
qreal QskProgressIndicator::extent() const
|
||||
{
|
||||
auto grooveSize = metric( Groove | QskAspect::Size );
|
||||
auto fillSize = metric( Fill | QskAspect::Size );
|
||||
return qMax( grooveSize, fillSize );
|
||||
return metric( Groove | QskAspect::Size );
|
||||
}
|
||||
|
||||
void QskProgressIndicator::setOrigin( qreal origin )
|
||||
|
|
@ -189,6 +187,11 @@ qreal QskProgressIndicator::origin() const
|
|||
return minimum();
|
||||
}
|
||||
|
||||
bool QskProgressIndicator::hasOrigin() const
|
||||
{
|
||||
return m_data->hasOrigin;
|
||||
}
|
||||
|
||||
void QskProgressIndicator::setValue( qreal value )
|
||||
{
|
||||
if ( isComponentComplete() )
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class QSK_EXPORT QskProgressIndicator : public QskBoundedControl
|
|||
|
||||
void resetOrigin();
|
||||
qreal origin() const;
|
||||
bool hasOrigin() const;
|
||||
|
||||
qreal value() const;
|
||||
qreal valueAsRatio() const; // [0.0, 1.0]
|
||||
|
|
@ -73,7 +74,6 @@ class QSK_EXPORT QskProgressIndicator : public QskBoundedControl
|
|||
|
||||
private:
|
||||
void setValueInternal( qreal value );
|
||||
void adjustBoundaries( bool increasing );
|
||||
void adjustValue();
|
||||
|
||||
class PrivateData;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,36 @@
|
|||
|
||||
using Q = QskProgressRing;
|
||||
|
||||
static QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
|
||||
{
|
||||
qreal pos1, pos2;
|
||||
|
||||
if ( indicator->isIndeterminate() )
|
||||
{
|
||||
pos1 = indicator->positionHint( QskProgressIndicator::Fill );
|
||||
pos2 = 2 * pos1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos1 = indicator->valueAsRatio( indicator->origin() );
|
||||
pos2 = indicator->valueAsRatio( indicator->value() );
|
||||
}
|
||||
|
||||
if ( pos1 > pos2 )
|
||||
std::swap( pos1, pos2 );
|
||||
|
||||
return QskIntervalF( pos1, pos2 );
|
||||
}
|
||||
|
||||
static inline QPair< qreal, qreal > qskFillAngles(
|
||||
const QskArcMetrics& metrics, const QskIntervalF& intv )
|
||||
{
|
||||
const auto startAngle = metrics.startAngle() + intv.lowerBound() * metrics.spanAngle();
|
||||
const auto endAngle = metrics.startAngle() + intv.upperBound() * metrics.spanAngle();
|
||||
|
||||
return { startAngle, endAngle };
|
||||
}
|
||||
|
||||
QskProgressRingSkinlet::QskProgressRingSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
|
|
@ -32,6 +62,34 @@ QRectF QskProgressRingSkinlet::subControlRect(
|
|||
QSGNode* QskProgressRingSkinlet::updateGrooveNode(
|
||||
const QskProgressIndicator* indicator, QSGNode* node ) const
|
||||
{
|
||||
const auto ring = static_cast< const Q* >( indicator );
|
||||
|
||||
const auto spacing = ring->spacingHint( Q::Fill ); // degrees
|
||||
|
||||
if( spacing > 0.0 )
|
||||
{
|
||||
const auto fillMetrics = ring->arcMetricsHint( Q::Fill );
|
||||
if ( fillMetrics.isClosed() )
|
||||
{
|
||||
const auto fillAngles = qskFillAngles( fillMetrics, qskFillInterval( ring ) );
|
||||
|
||||
qreal startAngle, endAngle;
|
||||
if ( fillAngles.second > fillAngles.first )
|
||||
{
|
||||
startAngle = fillAngles.second + spacing;
|
||||
endAngle = fillAngles.first + 360.0 - spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
startAngle = fillAngles.second - spacing;
|
||||
endAngle = fillAngles.first - 360.0 + spacing;
|
||||
}
|
||||
|
||||
return updateArcNode( ring, node,
|
||||
startAngle, endAngle - startAngle, Q::Groove );
|
||||
}
|
||||
}
|
||||
|
||||
return updateArcNode( indicator, node, Q::Groove );
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +112,7 @@ QSGNode* QskProgressRingSkinlet::updateFillNode(
|
|||
if ( !gradient.isVisible() )
|
||||
return nullptr;
|
||||
|
||||
const auto intv = fillInterval( ring );
|
||||
const auto intv = qskFillInterval( ring );
|
||||
|
||||
if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() )
|
||||
{
|
||||
|
|
@ -67,10 +125,10 @@ QSGNode* QskProgressRingSkinlet::updateFillNode(
|
|||
gradient.reverse();
|
||||
}
|
||||
|
||||
const auto startAngle = metrics.startAngle() + intv.lowerBound() * metrics.spanAngle();
|
||||
const auto spanAngle = intv.upperBound() * metrics.spanAngle();
|
||||
const auto angles = qskFillAngles( metrics, intv );
|
||||
|
||||
return updateArcNode( ring, node, rect, gradient, startAngle, spanAngle, subControl );
|
||||
return updateArcNode( ring, node, rect, gradient,
|
||||
angles.first, angles.second - angles.first, subControl );
|
||||
}
|
||||
|
||||
QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||
|
|
@ -88,32 +146,11 @@ QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable,
|
|||
|
||||
if ( constraint.width() >= 0.0 )
|
||||
hint.setHeight( constraint.width() / aspectRatio );
|
||||
else
|
||||
else
|
||||
hint.setWidth( constraint.height() * aspectRatio );
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
QskIntervalF QskProgressRingSkinlet::fillInterval(
|
||||
const QskProgressIndicator* indicator ) const
|
||||
{
|
||||
qreal pos1, pos2;
|
||||
|
||||
if ( indicator->isIndeterminate() )
|
||||
{
|
||||
pos1 = pos2 = indicator->positionHint( QskProgressIndicator::Fill );
|
||||
}
|
||||
else
|
||||
{
|
||||
pos1 = indicator->valueAsRatio( indicator->origin() );
|
||||
pos2 = indicator->valueAsRatio( indicator->value() );
|
||||
}
|
||||
|
||||
if ( pos1 > pos2 )
|
||||
std::swap( pos1, pos2 );
|
||||
|
||||
return QskIntervalF( pos1, pos2 );
|
||||
}
|
||||
|
||||
#include "moc_QskProgressRingSkinlet.cpp"
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ class QSK_EXPORT QskProgressRingSkinlet : public QskProgressIndicatorSkinlet
|
|||
protected:
|
||||
QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override;
|
||||
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
|
||||
|
||||
QskIntervalF fillInterval( const QskProgressIndicator* ) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
#include "QskBoxBorderColors.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskBoxNode.h"
|
||||
#include "QskBoxClipNode.h"
|
||||
#include "QskBoxRectangleNode.h"
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
#include "QskBoxHints.h"
|
||||
#include "QskClipNode.h"
|
||||
#include "QskColorFilter.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskFunctions.h"
|
||||
|
|
@ -641,15 +641,14 @@ QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable,
|
|||
QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
auto clipNode = QskSGNode::ensureNode< QskBoxClipNode >( node );
|
||||
auto clipNode = QskSGNode::ensureNode< QskClipNode >( node );
|
||||
|
||||
const auto margins = skinnable->marginHint( subControl );
|
||||
|
||||
const auto clipRect = rect.marginsRemoved( margins );
|
||||
if ( clipRect.isEmpty() )
|
||||
{
|
||||
clipNode->setIsRectangular( true );
|
||||
clipNode->setClipRect( clipRect );
|
||||
clipNode->setRect( clipRect );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -437,6 +437,14 @@ qreal QskSkinnable::metric( const QskAspect aspect, QskSkinHintStatus* status )
|
|||
return qskMetric< qreal >( this, aspect, status );
|
||||
}
|
||||
|
||||
qreal QskSkinnable::metric( QskAspect aspect, qreal defaultValue ) const
|
||||
{
|
||||
QskSkinHintStatus status;
|
||||
|
||||
const auto value = qskMetric< qreal >( this, aspect, &status );
|
||||
return status.isValid() ? value : defaultValue;
|
||||
}
|
||||
|
||||
bool QskSkinnable::setPositionHint( QskAspect aspect, qreal position )
|
||||
{
|
||||
return qskSetMetric( this, aspect | QskAspect::Position, position );
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ class QSK_EXPORT QskSkinnable
|
|||
bool moveMetric( QskAspect, qreal );
|
||||
bool resetMetric( QskAspect );
|
||||
qreal metric( QskAspect, QskSkinHintStatus* = nullptr ) const;
|
||||
qreal metric( QskAspect, qreal defaultValue ) const;
|
||||
|
||||
bool setFlagHint( QskAspect, int flag );
|
||||
template< typename T > T flagHint( QskAspect, T = T() ) const;
|
||||
|
|
|
|||
|
|
@ -6,35 +6,96 @@
|
|||
#include "QskSlider.h"
|
||||
#include "QskAnimationHint.h"
|
||||
#include "QskAspect.h"
|
||||
#include "QskIntervalF.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskFunctions.h"
|
||||
|
||||
QSK_SUBCONTROL( QskSlider, Panel )
|
||||
QSK_SUBCONTROL( QskSlider, Groove )
|
||||
QSK_SUBCONTROL( QskSlider, Fill )
|
||||
QSK_SUBCONTROL( QskSlider, Scale )
|
||||
QSK_SUBCONTROL( QskSlider, Tick )
|
||||
QSK_SUBCONTROL( QskSlider, Handle )
|
||||
QSK_SUBCONTROL( QskSlider, GrooveStopIndicators )
|
||||
QSK_SUBCONTROL( QskSlider, FillStopIndicators )
|
||||
QSK_SUBCONTROL( QskSlider, LabelContainer )
|
||||
QSK_SUBCONTROL( QskSlider, LabelText )
|
||||
|
||||
QSK_SYSTEM_STATE( QskSlider, Pressed, QskAspect::FirstSystemState << 2 )
|
||||
|
||||
static QRectF qskHandleSelectionRect( const QskSlider* slider )
|
||||
{
|
||||
return slider->subControlRect( QskSlider::Handle );
|
||||
}
|
||||
|
||||
static QRectF qskSliderSelectionRect( const QskSlider* slider )
|
||||
{
|
||||
const qreal margin = 10.0;
|
||||
|
||||
const auto scaleRect = slider->subControlRect( QskSlider::Scale );
|
||||
const auto handleRect = qskHandleSelectionRect( slider );
|
||||
|
||||
auto r = slider->subControlRect( QskSlider::Panel );
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
r.setTop( qMin( r.top(), handleRect.top() ) );
|
||||
r.setBottom( qMax( r.bottom(), handleRect.bottom() ) );
|
||||
r.setLeft( scaleRect.left() - margin );
|
||||
r.setRight( scaleRect.right() + margin );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setLeft( qMin( r.left(), handleRect.left() ) );
|
||||
r.setRight( qMax( r.right(), handleRect.right() ) );
|
||||
r.setTop( scaleRect.top() - margin );
|
||||
r.setBottom( scaleRect.bottom() + margin );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int qskKeyOffset( Qt::Orientation orientation, int key )
|
||||
{
|
||||
if ( orientation == Qt::Horizontal )
|
||||
{
|
||||
if ( key == Qt::Key_Left )
|
||||
return -1;
|
||||
|
||||
if ( key == Qt::Key_Right )
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( key == Qt::Key_Down )
|
||||
return -1;
|
||||
|
||||
if ( key == Qt::Key_Up )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
class QskSlider::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData( Qt::Orientation orientation )
|
||||
: pressedValue( 0 )
|
||||
, hasOrigin( false )
|
||||
, inverted( false )
|
||||
, tracking( true )
|
||||
, dragging( false )
|
||||
, orientation( orientation )
|
||||
{
|
||||
}
|
||||
|
||||
QPointF pressedPos;
|
||||
qreal pressedValue;
|
||||
|
||||
qreal origin = 0.0;
|
||||
|
||||
bool hasOrigin : 1;
|
||||
bool inverted : 1;
|
||||
bool tracking : 1;
|
||||
Qt::Orientation orientation : 2;
|
||||
bool dragging : 1;
|
||||
uint orientation : 2;
|
||||
};
|
||||
|
||||
QskSlider::QskSlider( QQuickItem* parent )
|
||||
|
|
@ -62,11 +123,6 @@ QskSlider::~QskSlider()
|
|||
{
|
||||
}
|
||||
|
||||
bool QskSlider::isPressed() const
|
||||
{
|
||||
return hasSkinState( Pressed );
|
||||
}
|
||||
|
||||
void QskSlider::setOrientation( Qt::Orientation orientation )
|
||||
{
|
||||
if ( orientation != m_data->orientation )
|
||||
|
|
@ -79,13 +135,68 @@ void QskSlider::setOrientation( Qt::Orientation orientation )
|
|||
resetImplicitSize();
|
||||
update();
|
||||
|
||||
Q_EMIT orientationChanged( m_data->orientation );
|
||||
Q_EMIT orientationChanged( this->orientation() );
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Orientation QskSlider::orientation() const
|
||||
{
|
||||
return m_data->orientation;
|
||||
return static_cast< Qt::Orientation >( m_data->orientation );
|
||||
}
|
||||
|
||||
void QskSlider::setInverted( bool on )
|
||||
{
|
||||
if ( on != m_data->inverted )
|
||||
{
|
||||
m_data->inverted = on;
|
||||
update();
|
||||
|
||||
Q_EMIT invertedChanged( on );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskSlider::isInverted() const
|
||||
{
|
||||
return m_data->inverted;
|
||||
}
|
||||
|
||||
void QskSlider::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 QskSlider::resetOrigin()
|
||||
{
|
||||
if ( m_data->hasOrigin )
|
||||
{
|
||||
m_data->hasOrigin = false;
|
||||
|
||||
update();
|
||||
Q_EMIT originChanged( origin() );
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskSlider::origin() const
|
||||
{
|
||||
if ( m_data->hasOrigin )
|
||||
return boundedValue( m_data->origin );
|
||||
|
||||
return minimum();
|
||||
}
|
||||
|
||||
bool QskSlider::hasOrigin() const
|
||||
{
|
||||
return m_data->hasOrigin;
|
||||
}
|
||||
|
||||
QskAspect::Variation QskSlider::effectiveVariation() const
|
||||
|
|
@ -107,137 +218,139 @@ bool QskSlider::isTracking() const
|
|||
return m_data->tracking;
|
||||
}
|
||||
|
||||
void QskSlider::componentComplete()
|
||||
{
|
||||
Inherited::componentComplete();
|
||||
if ( m_data->hasOrigin )
|
||||
m_data->origin = boundedValue( m_data->origin );
|
||||
}
|
||||
|
||||
void QskSlider::aboutToShow()
|
||||
{
|
||||
setPositionHint( Handle, valueAsRatio() );
|
||||
Inherited::aboutToShow();
|
||||
}
|
||||
|
||||
QSizeF QskSlider::handleSize() const
|
||||
{
|
||||
return handleRect().size();
|
||||
}
|
||||
|
||||
QRectF QskSlider::handleRect() const
|
||||
{
|
||||
auto rect = subControlRect( Handle );
|
||||
|
||||
#if 1 // minimum handle strut size hardcoded here for now
|
||||
const QSizeF strutSize( 60, 60 );
|
||||
const auto w = qMax( ( strutSize.width() - rect.width() ) / 2, 0.0 );
|
||||
const auto h = qMax( ( strutSize.height() - rect.height() ) / 2, 0.0 );
|
||||
#endif
|
||||
|
||||
return rect.marginsAdded( { w, h, w, h } );
|
||||
}
|
||||
|
||||
void QskSlider::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
if ( handleRect().contains( event->pos() ) )
|
||||
const auto pos = qskMousePosition( event );
|
||||
if ( !qskHandleSelectionRect( this ).contains( pos ) )
|
||||
{
|
||||
// Case 1: press started in the handle, start sliding
|
||||
const auto r = qskSliderSelectionRect( this );
|
||||
if ( !r.contains( pos ) )
|
||||
{
|
||||
Inherited::mousePressEvent( event );
|
||||
return;
|
||||
}
|
||||
|
||||
m_data->pressedPos = event->pos();
|
||||
m_data->pressedValue = value();
|
||||
setSkinStateFlag( Pressed );
|
||||
Q_EMIT pressedChanged( true );
|
||||
}
|
||||
else if ( pageSteps() == 0 )
|
||||
{
|
||||
// Case 2: pageSize is not used, we're done here
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 3: pressed outside of the handle, page the scroller in
|
||||
// the direction of the press requires an auto-repeat behavior
|
||||
// until the slider reaches the destination, or it simply jumps
|
||||
// there (configurable)
|
||||
qreal ratio;
|
||||
|
||||
const auto scaleRect = subControlRect( Scale );
|
||||
if ( m_data->orientation == Qt::Horizontal )
|
||||
ratio = ( pos.x() - scaleRect.left() ) / scaleRect.width();
|
||||
else
|
||||
ratio = ( scaleRect.bottom() - pos.y() ) / scaleRect.height();
|
||||
|
||||
if ( m_data->inverted )
|
||||
ratio = 1.0 - ratio;
|
||||
|
||||
setValue( valueFromRatio( ratio ) );
|
||||
}
|
||||
|
||||
setSkinStateFlag( Pressed );
|
||||
|
||||
m_data->pressedPos = pos;
|
||||
m_data->pressedValue = value();
|
||||
}
|
||||
|
||||
void QskSlider::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
if ( !isPressed() )
|
||||
if ( !hasSkinState( Pressed ) )
|
||||
return;
|
||||
|
||||
const auto mousePos = qskMousePosition( event );
|
||||
const auto r = subControlRect( Scale );
|
||||
|
||||
auto length = boundaryLength();
|
||||
if ( m_data->inverted )
|
||||
length = -length;
|
||||
|
||||
qreal newValue;
|
||||
|
||||
if ( m_data->orientation == Qt::Horizontal )
|
||||
{
|
||||
const auto distance = mousePos.x() - m_data->pressedPos.x();
|
||||
newValue = m_data->pressedValue + distance / r.width() * boundaryLength();
|
||||
newValue = m_data->pressedValue + distance / r.width() * length;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto distance = mousePos.y() - m_data->pressedPos.y();
|
||||
newValue = m_data->pressedValue - distance / r.height() * boundaryLength();
|
||||
newValue = m_data->pressedValue - distance / r.height() * length;
|
||||
}
|
||||
|
||||
if ( m_data->tracking )
|
||||
{
|
||||
m_data->dragging = true;
|
||||
setValue( newValue );
|
||||
m_data->dragging = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// moving the handle without changing the value
|
||||
moveHandleTo( newValue, QskAnimationHint() );
|
||||
}
|
||||
}
|
||||
|
||||
void QskSlider::mouseReleaseEvent( QMouseEvent* event )
|
||||
void QskSlider::mouseReleaseEvent( QMouseEvent* )
|
||||
{
|
||||
if ( !isPressed() ) // Page event
|
||||
{
|
||||
const auto mousePos = qskMousePosition( event );
|
||||
|
||||
const auto szHandle = handleSize();
|
||||
const auto rect = contentsRect();
|
||||
|
||||
bool up;
|
||||
if ( m_data->orientation == Qt::Horizontal )
|
||||
{
|
||||
const qreal w = szHandle.width();
|
||||
|
||||
const qreal x = ( mousePos.x() - rect.x() - w * 0.5 ) / ( rect.width() - w );
|
||||
up = x > valueAsRatio();
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal h = szHandle.height();
|
||||
|
||||
const qreal y = ( mousePos.y() - rect.y() - h * 0.5 ) / ( rect.height() - h );
|
||||
up = y < 1.0 - valueAsRatio();
|
||||
}
|
||||
|
||||
if ( up )
|
||||
pageUp();
|
||||
else
|
||||
pageDown();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !m_data->tracking )
|
||||
{
|
||||
const auto pos = handlePosition();
|
||||
setValue( valueFromRatio( pos ) );
|
||||
}
|
||||
}
|
||||
if ( !m_data->tracking && ( m_data->pressedValue != value() ) )
|
||||
Q_EMIT valueChanged( value() );
|
||||
|
||||
setSkinStateFlag( Pressed, false );
|
||||
Q_EMIT pressedChanged( false );
|
||||
}
|
||||
|
||||
qreal QskSlider::handlePosition() const
|
||||
void QskSlider::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
return positionHint( Handle );
|
||||
if ( auto offset = qskKeyOffset( orientation(), event->key() ) )
|
||||
{
|
||||
if ( m_data->inverted )
|
||||
offset = -offset;
|
||||
|
||||
increment( offset * stepSize() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_data->hasOrigin )
|
||||
{
|
||||
switch( event->key() )
|
||||
{
|
||||
case Qt::Key_Home:
|
||||
{
|
||||
setValue( origin() );
|
||||
return;
|
||||
}
|
||||
|
||||
case Qt::Key_End:
|
||||
{
|
||||
// we have 2 endpoints - better do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::keyPressEvent( event );
|
||||
}
|
||||
|
||||
void QskSlider::moveHandle()
|
||||
{
|
||||
const auto aspect = Handle | QskAspect::Metric | QskAspect::Position;
|
||||
moveHandleTo( value(), animationHint( aspect | skinStates() ) );
|
||||
QskAnimationHint hint;
|
||||
if ( !m_data->dragging )
|
||||
{
|
||||
const auto aspect = Handle | QskAspect::Metric | QskAspect::Position;
|
||||
hint = animationHint( aspect | skinStates() );
|
||||
}
|
||||
|
||||
moveHandleTo( value(), hint );
|
||||
}
|
||||
|
||||
void QskSlider::moveHandleTo( qreal value, const QskAnimationHint& hint )
|
||||
|
|
|
|||
|
|
@ -7,26 +7,29 @@
|
|||
#define QSK_SLIDER_H
|
||||
|
||||
#include "QskBoundedValueInput.h"
|
||||
#include "QskNamespace.h"
|
||||
|
||||
class QSK_EXPORT QskSlider : public QskBoundedValueInput
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( bool isPressed READ isPressed NOTIFY pressedChanged )
|
||||
|
||||
Q_PROPERTY( Qt::Orientation orientation READ orientation
|
||||
WRITE setOrientation NOTIFY orientationChanged )
|
||||
|
||||
Q_PROPERTY( bool inverted READ isInverted
|
||||
WRITE setInverted NOTIFY invertedChanged )
|
||||
|
||||
Q_PROPERTY( bool tracking READ isTracking
|
||||
WRITE setTracking NOTIFY trackingChanged )
|
||||
|
||||
Q_PROPERTY( qreal handlePosition READ handlePosition )
|
||||
Q_PROPERTY( qreal origin READ origin
|
||||
WRITE setOrigin RESET resetOrigin NOTIFY originChanged )
|
||||
|
||||
using Inherited = QskBoundedValueInput;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Handle,
|
||||
GrooveStopIndicators, FillStopIndicators, LabelContainer, LabelText )
|
||||
QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Tick, Handle,
|
||||
LabelContainer, LabelText )
|
||||
QSK_STATES( Pressed )
|
||||
|
||||
explicit QskSlider( QQuickItem* parent = nullptr );
|
||||
|
|
@ -34,11 +37,16 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput
|
|||
|
||||
~QskSlider() override;
|
||||
|
||||
bool isPressed() const;
|
||||
|
||||
void setOrientation( Qt::Orientation );
|
||||
Qt::Orientation orientation() const;
|
||||
|
||||
void setInverted( bool );
|
||||
bool isInverted() const;
|
||||
|
||||
void resetOrigin();
|
||||
qreal origin() const;
|
||||
bool hasOrigin() const;
|
||||
|
||||
void setTracking( bool );
|
||||
bool isTracking() const;
|
||||
|
||||
|
|
@ -46,20 +54,24 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput
|
|||
|
||||
QskAspect::Variation effectiveVariation() const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setOrigin( qreal );
|
||||
|
||||
Q_SIGNALS:
|
||||
void pressedChanged( bool );
|
||||
void orientationChanged( Qt::Orientation );
|
||||
void invertedChanged( bool );
|
||||
void trackingChanged( bool );
|
||||
void originChanged( qreal );
|
||||
|
||||
protected:
|
||||
void mousePressEvent( QMouseEvent* ) override;
|
||||
void mouseMoveEvent( QMouseEvent* ) override;
|
||||
void mouseReleaseEvent( QMouseEvent* ) override;
|
||||
|
||||
QSizeF handleSize() const;
|
||||
QRectF handleRect() const;
|
||||
void keyPressEvent( QKeyEvent* ) override;
|
||||
|
||||
void aboutToShow() override;
|
||||
void componentComplete() override;
|
||||
|
||||
private:
|
||||
void moveHandle();
|
||||
|
|
|
|||
|
|
@ -5,58 +5,91 @@
|
|||
|
||||
#include "QskSliderSkinlet.h"
|
||||
#include "QskSlider.h"
|
||||
|
||||
#include "QskAspect.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskIntervalF.h"
|
||||
|
||||
#include <QFontMetricsF>
|
||||
#include <QtMath>
|
||||
#include <qvector.h>
|
||||
#include <qpair.h>
|
||||
#include <qmath.h>
|
||||
#include <qfontmetrics.h>
|
||||
|
||||
// the color of graduation ticks might different, when being on top of the filling
|
||||
QSK_SYSTEM_STATE( QskSliderSkinlet, Filled, QskAspect::FirstUserState >> 1 )
|
||||
|
||||
using Q = QskSlider;
|
||||
|
||||
namespace
|
||||
static inline qreal qskSubcontrolExtent(
|
||||
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
inline QRectF qskInnerPanelRect(
|
||||
const QskSlider* slider, const QRectF& contentsRect )
|
||||
return skinnable->metric( subControl | QskAspect::Size, -1.0 );
|
||||
}
|
||||
|
||||
static inline bool qskHasFilling( const QskSlider* slider )
|
||||
{
|
||||
const auto policy = slider->flagHint< Qsk::Policy >(
|
||||
Q::Fill | QskAspect::Option, Qsk::Always );
|
||||
|
||||
switch( policy )
|
||||
{
|
||||
#if 1
|
||||
auto padding = slider->paddingHint( Q::Panel );
|
||||
padding += slider->boxBorderMetricsHint( Q::Panel ).widths();
|
||||
case Qsk::Never:
|
||||
return false;
|
||||
|
||||
auto r = slider->subControlRect( contentsRect, Q::Panel );
|
||||
r = r.marginsRemoved( padding );
|
||||
#else
|
||||
r = slider->subControlContentsRect( contentsRect, Q::Panel );
|
||||
#endif
|
||||
case Qsk::Maybe:
|
||||
return qskFuzzyCompare( slider->origin(), slider->minimum() );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
QRectF qskInnerValueRect( const QskSlider* slider, const QRectF& contentsRect )
|
||||
{
|
||||
// For M3 the stop indicators have some padding related to the groove (and fill),
|
||||
// so we use the rect between first and last stop indicator as authoritative for
|
||||
// indicators, handle etc.
|
||||
const auto grooveIndicatorMargins = slider->paddingHint( Q::GrooveStopIndicators );
|
||||
const auto r = qskInnerPanelRect( slider, contentsRect ).marginsRemoved( grooveIndicatorMargins );
|
||||
return r;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static QRectF qskInnerRect( const QskSlider* slider,
|
||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
auto r = slider->subControlContentsRect( contentsRect, Q::Panel );
|
||||
|
||||
const qreal extent = qskSubcontrolExtent( slider, subControl );
|
||||
|
||||
if ( extent >= 0.0 )
|
||||
{
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
if ( extent < r.height() )
|
||||
{
|
||||
r.setTop( r.center().y() - 0.5 * extent );
|
||||
r.setHeight( extent );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( extent < r.width() )
|
||||
{
|
||||
r.setLeft( r.center().x() - 0.5 * extent );
|
||||
r.setWidth( extent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline QPair< qreal, qreal > qskTickSpan( qreal min, qreal max, qreal length )
|
||||
{
|
||||
if ( length >= 0.0 )
|
||||
{
|
||||
// using the center of [min,max]
|
||||
min += 0.5 * ( max - min - length );
|
||||
max = min + length;
|
||||
}
|
||||
|
||||
return { min, max };
|
||||
}
|
||||
|
||||
|
||||
QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
setNodeRoles( {
|
||||
PanelRole,
|
||||
GrooveRole,
|
||||
FillRole,
|
||||
FillStopIndicatorsRole,
|
||||
GrooveStopIndicatorsRole,
|
||||
HandleRole,
|
||||
LabelContainerRole,
|
||||
LabelTextRole,
|
||||
} );
|
||||
setNodeRoles( { PanelRole, GrooveRole, FillRole, TicksRole, HandleRole,
|
||||
LabelContainerRole, LabelTextRole } );
|
||||
}
|
||||
|
||||
QskSliderSkinlet::~QskSliderSkinlet()
|
||||
|
|
@ -69,107 +102,29 @@ QRectF QskSliderSkinlet::subControlRect( const QskSkinnable* skinnable,
|
|||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
|
||||
if ( subControl == Q::Panel )
|
||||
{
|
||||
return panelRect( slider, contentsRect );
|
||||
}
|
||||
|
||||
if ( subControl == Q::Groove )
|
||||
{
|
||||
return grooveRect( slider, contentsRect );
|
||||
}
|
||||
return qskInnerRect( slider, contentsRect, Q::Groove );
|
||||
|
||||
if ( subControl == Q::Fill )
|
||||
{
|
||||
return fillRect( slider, contentsRect );
|
||||
}
|
||||
|
||||
if ( subControl == Q::Handle )
|
||||
{
|
||||
return handleRect( slider, contentsRect );
|
||||
}
|
||||
|
||||
if ( subControl == Q::Scale )
|
||||
{
|
||||
return scaleRect( slider, contentsRect );
|
||||
}
|
||||
return subControlRect( skinnable, contentsRect, Q::Groove );
|
||||
|
||||
if ( subControl == Q::Handle )
|
||||
return handleRect( slider, contentsRect );
|
||||
|
||||
if ( subControl == Q::LabelContainer )
|
||||
{
|
||||
return labelContainerRect( slider, contentsRect );
|
||||
}
|
||||
|
||||
if ( subControl == Q::LabelText )
|
||||
{
|
||||
return labelContainerRect( slider, contentsRect );
|
||||
}
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
int QskSliderSkinlet::sampleCount( const QskSkinnable* skinnable,
|
||||
QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
|
||||
if( slider->snap() )
|
||||
{
|
||||
const auto num = qCeil( slider->boundaryLength() / slider->stepSize() ) + 1;
|
||||
return num;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( subControl == Q::GrooveStopIndicators ) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::sampleRect(
|
||||
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||
QskAspect::Subcontrol subControl, int index ) const
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
|
||||
auto r = qskInnerValueRect( slider, contentsRect );
|
||||
|
||||
const auto size = slider->strutSizeHint( subControl );
|
||||
|
||||
const auto filledPoints = qFloor( ( slider->value() - slider->minimum() ) / slider->stepSize() );
|
||||
|
||||
if( slider->snap())
|
||||
{
|
||||
if( slider->snap()
|
||||
&& ( ( index >= filledPoints && subControl == Q::FillStopIndicators )
|
||||
|| ( index < filledPoints && subControl == Q::GrooveStopIndicators ) ) )
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const auto pos = slider->snap() ? slider->minimum() + index * slider->stepSize() : slider->maximum();
|
||||
|
||||
if( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
r.setTop( r.center().y() - size.height() / 2 );
|
||||
const auto x = r.left() + slider->valueAsRatio( pos ) * r.width() - size.width() / 2;
|
||||
r.setLeft( x );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setLeft( r.center().x() - size.width() / 2 );
|
||||
const auto y = r.bottom() - slider->valueAsRatio( pos ) * r.height() - size.height() / 2;
|
||||
r.setTop( y );
|
||||
}
|
||||
|
||||
r.setHeight( size.height() );
|
||||
r.setWidth( size.width() );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
QskAspect::States QskSliderSkinlet::sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int ) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QSGNode* QskSliderSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
|
|
@ -178,56 +133,102 @@ QSGNode* QskSliderSkinlet::updateSubNode(
|
|||
switch ( nodeRole )
|
||||
{
|
||||
case PanelRole:
|
||||
{
|
||||
return updateBoxNode( slider, node, Q::Panel );
|
||||
}
|
||||
|
||||
case GrooveRole:
|
||||
{
|
||||
return updateBoxNode( slider, node, Q::Groove );
|
||||
}
|
||||
|
||||
case FillRole:
|
||||
{
|
||||
return updateBoxNode( slider, node, Q::Fill );
|
||||
}
|
||||
|
||||
case GrooveStopIndicatorsRole:
|
||||
{
|
||||
return updateSeriesNode( slider, Q::GrooveStopIndicators, node );
|
||||
}
|
||||
|
||||
case FillStopIndicatorsRole:
|
||||
{
|
||||
return updateSeriesNode( slider, Q::FillStopIndicators, node );
|
||||
}
|
||||
|
||||
case HandleRole:
|
||||
{
|
||||
return updateBoxNode( slider, node, Q::Handle );
|
||||
}
|
||||
|
||||
case TicksRole:
|
||||
return updateSeriesNode( slider, Q::Tick, node );
|
||||
|
||||
case LabelContainerRole:
|
||||
{
|
||||
return updateBoxNode( slider, node, Q::LabelContainer );
|
||||
}
|
||||
|
||||
case LabelTextRole:
|
||||
{
|
||||
return updateTextNode( slider, node, slider->valueText(), Q::LabelText );
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
int QskSliderSkinlet::sampleCount( const QskSkinnable* skinnable,
|
||||
QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
if ( subControl == Q::Tick )
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
return graduation( slider ).count();
|
||||
}
|
||||
|
||||
return Inherited::sampleCount( skinnable, subControl );
|
||||
}
|
||||
|
||||
QVariant QskSliderSkinlet::sampleAt( const QskSkinnable* skinnable,
|
||||
QskAspect::Subcontrol subControl, int index ) const
|
||||
{
|
||||
if ( subControl == Q::Tick )
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
return graduation( slider ).value( index );
|
||||
}
|
||||
|
||||
return Inherited::sampleAt( skinnable, subControl, index );
|
||||
}
|
||||
|
||||
QskAspect::States QskSliderSkinlet::sampleStates(
|
||||
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
|
||||
{
|
||||
auto states = Inherited::sampleStates( skinnable, subControl, index );
|
||||
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
|
||||
if ( subControl == Q::Tick && qskHasFilling( slider ) )
|
||||
{
|
||||
const auto tickValue = sampleAt( skinnable, subControl, index );
|
||||
if ( tickValue.canConvert< qreal >() )
|
||||
{
|
||||
const auto intv = QskIntervalF::normalized(
|
||||
slider->origin(), slider->value() );
|
||||
|
||||
if ( intv.contains( tickValue.value< qreal >() ) )
|
||||
states |= Filled;
|
||||
}
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::sampleRect(
|
||||
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||
QskAspect::Subcontrol subControl, int index ) const
|
||||
{
|
||||
if ( subControl == Q::Tick )
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
return tickRect( slider, contentsRect, index );
|
||||
}
|
||||
|
||||
return Inherited::sampleRect( skinnable, contentsRect, subControl, index );
|
||||
}
|
||||
|
||||
QSGNode* QskSliderSkinlet::updateSampleNode( const QskSkinnable* skinnable,
|
||||
QskAspect::Subcontrol subControl, int index, QSGNode* node ) const
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
const auto rect = sampleRect( slider, slider->contentsRect(), subControl, index );
|
||||
if ( subControl == Q::Tick )
|
||||
{
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
const auto rect = sampleRect( slider, slider->contentsRect(), subControl, index );
|
||||
|
||||
return updateBoxNode( skinnable, node, rect, subControl );
|
||||
return updateBoxNode( skinnable, node, rect, subControl );
|
||||
}
|
||||
|
||||
return Inherited::updateSampleNode( skinnable, subControl, index, node );
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::panelRect(
|
||||
|
|
@ -235,104 +236,73 @@ QRectF QskSliderSkinlet::panelRect(
|
|||
{
|
||||
auto r = contentsRect;
|
||||
|
||||
const qreal size = slider->metric( Q::Panel | QskAspect::Size ); // 0: no hint
|
||||
if ( size > 0 && size < r.height() )
|
||||
const qreal extent = qskSubcontrolExtent( slider, Q::Panel );
|
||||
if ( extent >= 0 && extent < r.height() )
|
||||
{
|
||||
const auto alignment = slider->alignmentHint( Q::Panel );
|
||||
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
r = qskAlignedRectF( r, r.width(), size, alignment & Qt::AlignVertical_Mask );
|
||||
{
|
||||
r = qskAlignedRectF( r, r.width(),
|
||||
extent, alignment & Qt::AlignVertical_Mask );
|
||||
}
|
||||
else
|
||||
r = qskAlignedRectF( r, size, r.height(), alignment & Qt::AlignHorizontal_Mask );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::innerRect( const QskSlider* slider,
|
||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
auto r = qskInnerPanelRect( slider, contentsRect );
|
||||
|
||||
QskSkinHintStatus status;
|
||||
|
||||
const qreal extent = slider->metric( subControl | QskAspect::Size, &status );
|
||||
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
if ( status.isValid() && ( extent < r.height() ) )
|
||||
{
|
||||
r.setTop( r.center().y() - 0.5 * extent );
|
||||
r.setHeight( extent );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( status.isValid() && ( extent < r.width() ) )
|
||||
{
|
||||
r.setLeft( r.center().x() - 0.5 * extent );
|
||||
r.setWidth( extent );
|
||||
r = qskAlignedRectF( r, extent, r.height(),
|
||||
alignment & Qt::AlignHorizontal_Mask );
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::grooveRect(
|
||||
const QskSlider* slider, const QRectF& contentsRect ) const
|
||||
{
|
||||
const auto r = qskInnerPanelRect( slider, contentsRect );
|
||||
auto grooveRect = innerRect( slider, contentsRect, Q::Groove );
|
||||
const auto handleRect = slider->subControlRect( Q::Handle );
|
||||
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
grooveRect.setLeft( handleRect.right() );
|
||||
grooveRect.setRight( r.right() );
|
||||
}
|
||||
else
|
||||
{
|
||||
grooveRect.setBottom( handleRect.top() );
|
||||
grooveRect.setTop( r.top() );
|
||||
}
|
||||
|
||||
return grooveRect;
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::scaleRect(
|
||||
const QskSlider* slider, const QRectF& rect ) const
|
||||
{
|
||||
return innerRect( slider, rect, Q::Groove );
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::fillRect(
|
||||
const QskSlider* slider, const QRectF& contentsRect ) const
|
||||
{
|
||||
const auto r = qskInnerPanelRect( slider, contentsRect );
|
||||
const auto handleRect = slider->subControlRect( Q::Handle );
|
||||
if ( !qskHasFilling( slider ) )
|
||||
return QRectF();
|
||||
|
||||
auto pos1 = slider->valueAsRatio( slider->origin() );
|
||||
auto pos2 = qBound( 0.0, slider->positionHint( Q::Handle ), 1.0 );
|
||||
|
||||
if ( slider->isInverted() )
|
||||
{
|
||||
pos1 = 1.0 - pos1;
|
||||
pos2 = 1.0 - pos2;
|
||||
}
|
||||
|
||||
if ( pos1 > pos2 )
|
||||
qSwap( pos1, pos2 );
|
||||
|
||||
auto r = qskInnerRect( slider, contentsRect, Q::Fill );
|
||||
|
||||
auto scaleRect = subControlRect( slider, contentsRect, Q::Scale );
|
||||
|
||||
auto fillRect = innerRect( slider, contentsRect, Q::Fill );
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
fillRect.setLeft( r.left() );
|
||||
fillRect.setRight( handleRect.left() );
|
||||
if ( !qFuzzyIsNull( pos1 ) )
|
||||
r.setLeft( scaleRect.left() + pos1 * scaleRect.width() );
|
||||
|
||||
r.setRight( scaleRect.left() + pos2 * scaleRect.width() );
|
||||
}
|
||||
else
|
||||
{
|
||||
fillRect.setBottom( r.bottom() );
|
||||
fillRect.setTop( handleRect.bottom() );
|
||||
if ( !qFuzzyIsNull( pos1 ) )
|
||||
r.setBottom( scaleRect.bottom() - pos1 * scaleRect.height() );
|
||||
|
||||
r.setTop( scaleRect.bottom() - pos2 * scaleRect.height() );
|
||||
}
|
||||
|
||||
return fillRect;
|
||||
return r;
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::handleRect(
|
||||
const QskSlider* slider, const QRectF& contentsRect ) const
|
||||
{
|
||||
auto handleSize = slider->strutSizeHint( Q::Handle );
|
||||
const auto pos = qBound( 0.0, slider->handlePosition(), 1.0 );
|
||||
const auto pos = qBound( 0.0, slider->positionHint( Q::Handle ), 1.0 );
|
||||
|
||||
const auto r = qskInnerValueRect( slider, contentsRect );
|
||||
const auto r = subControlRect( slider, contentsRect, Q::Scale );
|
||||
auto center = r.center();
|
||||
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
|
|
@ -343,7 +313,10 @@ QRectF QskSliderSkinlet::handleRect(
|
|||
if ( handleSize.width() < 0.0 )
|
||||
handleSize.setWidth( handleSize.height() );
|
||||
|
||||
center.setX( r.left() + pos * r.width() );
|
||||
if ( slider->isInverted() )
|
||||
center.setX( r.right() - pos * r.width() );
|
||||
else
|
||||
center.setX( r.left() + pos * r.width() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -353,17 +326,56 @@ QRectF QskSliderSkinlet::handleRect(
|
|||
if ( handleSize.height() < 0.0 )
|
||||
handleSize.setHeight( handleSize.width() );
|
||||
|
||||
center.setY( r.bottom() - pos * r.height() );
|
||||
if ( slider->isInverted() )
|
||||
center.setY( r.top() + pos * r.height() );
|
||||
else
|
||||
center.setY( r.bottom() - pos * r.height() );
|
||||
}
|
||||
|
||||
QRectF handleRect( 0, 0, handleSize.width(), handleSize.height() );
|
||||
handleRect.moveCenter( center );
|
||||
|
||||
handleRect = handleRect.marginsRemoved( slider->marginHint( Q::Handle ) );
|
||||
|
||||
return handleRect;
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::tickRect( const QskSlider* slider,
|
||||
const QRectF& contentsRect, int index ) const
|
||||
{
|
||||
const auto tickValue = sampleAt( slider, Q::Tick, index );
|
||||
if ( !tickValue.canConvert< qreal >() )
|
||||
return QRectF();
|
||||
|
||||
auto tickPos = slider->valueAsRatio( tickValue.value< qreal >() );
|
||||
if ( slider->isInverted() )
|
||||
tickPos = 1.0 - tickPos;
|
||||
|
||||
const auto r = subControlRect( slider, contentsRect, Q::Scale );
|
||||
|
||||
const auto padding = slider->paddingHint( Q::Scale );
|
||||
const auto size = slider->strutSizeHint( Q::Tick );
|
||||
|
||||
if( slider->orientation() == Qt::Horizontal )
|
||||
{
|
||||
const auto x = tickPos * r.width() - 0.5 * size.width();
|
||||
|
||||
const auto span = qskTickSpan(
|
||||
padding.top(), r.height() - padding.bottom(), size.height() );
|
||||
|
||||
return QRectF( r.x() + x, r.y() + span.first,
|
||||
size.width(), span.second - span.first );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto y = tickPos * r.height() + 0.5 * size.height();
|
||||
|
||||
const auto span = qskTickSpan(
|
||||
padding.left(), r.width() - padding.right(), size.width() );
|
||||
|
||||
return QRectF( r.x() + span.first, r.bottom() - y,
|
||||
span.second - span.first, size.height() );
|
||||
}
|
||||
}
|
||||
|
||||
QRectF QskSliderSkinlet::labelContainerRect(
|
||||
const QskSlider* slider, const QRectF& rect ) const
|
||||
{
|
||||
|
|
@ -398,24 +410,73 @@ QRectF QskSliderSkinlet::labelContainerRect(
|
|||
|
||||
return QRectF( x, y, size.width(), size.height() );
|
||||
}
|
||||
|
||||
QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||
Qt::SizeHint which, const QSizeF& ) const
|
||||
{
|
||||
if ( which != Qt::PreferredSize )
|
||||
return QSizeF();
|
||||
|
||||
const auto panelHint = skinnable->strutSizeHint( Q::Panel );
|
||||
const auto grooveHint = skinnable->strutSizeHint( Q::Groove );
|
||||
const auto fillHint = skinnable->strutSizeHint( Q::Fill );
|
||||
const auto handleHint = skinnable->strutSizeHint( Q::Handle );
|
||||
auto extent = qskSubcontrolExtent( skinnable, Q::Panel );
|
||||
extent = qMax( extent, qskSubcontrolExtent( skinnable, Q::Groove ) );
|
||||
extent = qMax( extent, qskSubcontrolExtent( skinnable, Q::Fill ) );
|
||||
|
||||
auto hint = panelHint;
|
||||
hint = hint.expandedTo( grooveHint );
|
||||
hint = hint.expandedTo( fillHint );
|
||||
hint = hint.expandedTo( handleHint );
|
||||
const auto slider = static_cast< const QskSlider* >( skinnable );
|
||||
|
||||
auto hint = skinnable->strutSizeHint( Q::Handle );
|
||||
|
||||
if ( slider->orientation() == Qt::Horizontal )
|
||||
hint.setHeight( qMax( hint.height(), extent ) );
|
||||
else
|
||||
hint.setWidth( qMax( hint.width(), extent ) );
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
bool QskSliderSkinlet::hasGraduation( const QskSlider* slider ) const
|
||||
{
|
||||
if ( slider->stepSize() )
|
||||
{
|
||||
const auto policy = slider->flagHint< Qsk::Policy >(
|
||||
Q::Tick | QskAspect::Option, Qsk::Never );
|
||||
|
||||
switch( policy )
|
||||
{
|
||||
case Qsk::Always:
|
||||
return true;
|
||||
|
||||
case Qsk::Maybe:
|
||||
return slider->isSnapping();
|
||||
|
||||
case Qsk::Never:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector< qreal > QskSliderSkinlet::graduation( const QskSlider* slider ) const
|
||||
{
|
||||
QVector< qreal > graduation;
|
||||
|
||||
if ( hasGraduation( slider ) )
|
||||
{
|
||||
const auto from = slider->minimum();
|
||||
const auto to = slider->maximum();
|
||||
|
||||
auto step = slider->stepSize();
|
||||
if ( from > to )
|
||||
step = -step;
|
||||
|
||||
const auto n = qCeil( ( to - from ) / step ) - 1;
|
||||
|
||||
graduation.reserve( n );
|
||||
|
||||
for ( int i = 1; i <= n; i++ )
|
||||
graduation += from + i * step;
|
||||
}
|
||||
|
||||
return graduation;
|
||||
}
|
||||
|
||||
#include "moc_QskSliderSkinlet.cpp"
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet
|
|||
using Inherited = QskSkinlet;
|
||||
|
||||
public:
|
||||
QSK_STATES( Filled )
|
||||
|
||||
enum NodeRole
|
||||
{
|
||||
PanelRole,
|
||||
GrooveRole,
|
||||
FillRole,
|
||||
GrooveStopIndicatorsRole,
|
||||
FillStopIndicatorsRole,
|
||||
TicksRole,
|
||||
HandleRole,
|
||||
LabelContainerRole,
|
||||
LabelTextRole,
|
||||
|
|
@ -45,6 +46,9 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet
|
|||
QRectF sampleRect( const QskSkinnable*,
|
||||
const QRectF&, QskAspect::Subcontrol, int index ) const override;
|
||||
|
||||
QVariant sampleAt( const QskSkinnable*,
|
||||
QskAspect::Subcontrol, int index ) const override;
|
||||
|
||||
QskAspect::States sampleStates( const QskSkinnable*,
|
||||
QskAspect::Subcontrol, int ) const override;
|
||||
|
||||
|
|
@ -55,15 +59,16 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet
|
|||
QSGNode* updateSampleNode( const QskSkinnable*,
|
||||
QskAspect::Subcontrol, int index, QSGNode* ) const override;
|
||||
|
||||
virtual QVector< qreal > graduation( const QskSlider* ) const;
|
||||
bool hasGraduation( const QskSlider* ) const;
|
||||
|
||||
private:
|
||||
QRectF panelRect( const QskSlider*, const QRectF& ) const;
|
||||
QRectF grooveRect( const QskSlider*, const QRectF& ) const;
|
||||
QRectF fillRect( const QskSlider*, const QRectF& ) const;
|
||||
QRectF handleRect( const QskSlider*, const QRectF& ) const;
|
||||
QRectF scaleRect( const QskSlider*, const QRectF& ) const;
|
||||
QRectF labelContainerRect( const QskSlider*, const QRectF& ) const;
|
||||
QRectF tickRect( const QskSlider*, const QRectF&, int index ) const;
|
||||
|
||||
QRectF innerRect( const QskSlider*, const QRectF&, QskAspect::Subcontrol ) const;
|
||||
QRectF labelContainerRect( const QskSlider*, const QRectF& ) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -248,8 +248,7 @@ static inline void qskCreateFill(
|
|||
using namespace QskVertex;
|
||||
using namespace Qt;
|
||||
|
||||
const auto cn = m_metrics.corners;
|
||||
const bool isHorizontal = m_metrics.preferredOrientation == Qt::Horizontal;
|
||||
const bool isHorizontal = ( m_metrics.preferredOrientation == Qt::Horizontal );
|
||||
|
||||
if ( !m_metrics.isInsideRounded )
|
||||
{
|
||||
|
|
@ -258,7 +257,7 @@ static inline void qskCreateFill(
|
|||
}
|
||||
else if ( m_metrics.isOutsideSymmetric )
|
||||
{
|
||||
const int stepCount = cn[ 0 ].stepCount;
|
||||
const int stepCount = m_metrics.corners[ 0 ].innerStepCount();
|
||||
|
||||
if ( isHorizontal )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskBoxClipNode.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskBoxRenderer.h"
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
#include "QskFunctions.h"
|
||||
|
||||
#include <qquickitem.h>
|
||||
|
||||
static inline QskHashValue qskMetricsHash(
|
||||
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
|
||||
{
|
||||
QskHashValue hash = 13000;
|
||||
|
||||
hash = shape.hash( hash );
|
||||
return border.hash( hash );
|
||||
}
|
||||
|
||||
QskBoxClipNode::QskBoxClipNode()
|
||||
: m_hash( 0 )
|
||||
, m_geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
|
||||
{
|
||||
setGeometry( &m_geometry );
|
||||
}
|
||||
|
||||
QskBoxClipNode::~QskBoxClipNode()
|
||||
{
|
||||
}
|
||||
|
||||
void QskBoxClipNode::setBox( const QQuickWindow* window, const QRectF& rect,
|
||||
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
|
||||
{
|
||||
const auto hash = qskMetricsHash( shape, border );
|
||||
if ( hash == m_hash && rect == m_rect )
|
||||
return;
|
||||
|
||||
m_rect = rect;
|
||||
m_hash = hash;
|
||||
|
||||
bool isRectangular = false;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Depending on isRectangular the "renderer can use scissoring instead of stencil,
|
||||
which is significantly faster."
|
||||
|
||||
However the batch renderer ( qsgbatchrenderer.cpp ) is rounding the clip rectangle
|
||||
to integers and the clip might become too small/large.
|
||||
|
||||
So we always have to use stencil clipping - even if it might have a negative
|
||||
impact on the performance. TODO ...
|
||||
*/
|
||||
|
||||
if ( shape.isRectangle() )
|
||||
isRectangular = true;
|
||||
#endif
|
||||
|
||||
if ( isRectangular )
|
||||
{
|
||||
if ( m_geometry.vertexCount() > 0 )
|
||||
m_geometry.allocate( 0 );
|
||||
|
||||
setIsRectangular( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
setIsRectangular( false );
|
||||
|
||||
QskBoxRenderer renderer( window );
|
||||
renderer.setFillLines( rect, shape, border, m_geometry );
|
||||
}
|
||||
|
||||
/*
|
||||
Even in situations, where the clipping is not rectangular, it is
|
||||
useful to know its bounding rectangle
|
||||
*/
|
||||
setClipRect( qskValidOrEmptyInnerRect( rect, border.widths() ) );
|
||||
|
||||
m_geometry.markVertexDataDirty();
|
||||
markDirty( QSGNode::DirtyGeometry );
|
||||
}
|
||||
|
|
@ -168,7 +168,8 @@ void QskBoxRenderer::setColoredBorderLines( const QRectF& rect,
|
|||
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
|
||||
geometry.markVertexDataDirty();
|
||||
|
||||
const QskBoxBasicStroker stroker( QskBoxMetrics( rect, shape, border ), borderColors );
|
||||
const QskBoxMetrics metrics( rect, shape, border );
|
||||
const QskBoxBasicStroker stroker( metrics, borderColors );
|
||||
|
||||
if ( auto lines = qskAllocateColoredLines( geometry, stroker.borderCount() ) )
|
||||
stroker.setBoxLines( lines, nullptr );
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskClipNode.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskBoxRenderer.h"
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskVertex.h"
|
||||
|
||||
#include <qquickwindow.h>
|
||||
|
||||
static inline QskHashValue qskMetricsHash(
|
||||
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
|
||||
{
|
||||
QskHashValue hash = 13000;
|
||||
|
||||
hash = shape.hash( hash );
|
||||
return border.hash( hash );
|
||||
}
|
||||
|
||||
static inline void qskSetBoundingRect( QSGClipNode* node, const QRectF& rect )
|
||||
{
|
||||
/*
|
||||
Depending on isRectangular: the "scene graph renderer can use
|
||||
scissoring instead of stencil, which is significantly faster."
|
||||
|
||||
However the batch renderer ( qsgbatchrenderer.cpp ) is rounding
|
||||
the clip rectangle to integers and the clip might become too small/large.
|
||||
So we always have to use stencil clipping - even if it might have a negative
|
||||
impact on the performance.
|
||||
|
||||
When isRectangular is set to false the clipRect is not used from the
|
||||
renderer and we use the memory for the storing the bounding rectangle.
|
||||
*/
|
||||
|
||||
node->setIsRectangular( false );
|
||||
node->setClipRect( rect );
|
||||
}
|
||||
|
||||
static inline QskVertex::Line* qskAllocateLines(
|
||||
QSGGeometry& geometry, int lineCount )
|
||||
{
|
||||
geometry.allocate( 2 * lineCount ); // 2 points per line
|
||||
return reinterpret_cast< QskVertex::Line* >( geometry.vertexData() );
|
||||
}
|
||||
|
||||
QskClipNode::QskClipNode()
|
||||
: m_hash( 0 )
|
||||
, m_geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
|
||||
{
|
||||
setGeometry( &m_geometry );
|
||||
}
|
||||
|
||||
QskClipNode::~QskClipNode()
|
||||
{
|
||||
}
|
||||
|
||||
void QskClipNode::setRect( const QRectF& rect )
|
||||
{
|
||||
setRegion( rect, QRectF() );
|
||||
}
|
||||
|
||||
void QskClipNode::setRegion( const QRectF& rect, const QRectF& excludedRect )
|
||||
{
|
||||
if ( rect.isEmpty() )
|
||||
{
|
||||
/*
|
||||
what about rectangles having a width/height
|
||||
of 0 ( f.e lines ) TODO ...
|
||||
*/
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto innerRect = excludedRect.isEmpty()
|
||||
? QRectF() : excludedRect.intersected( rect );
|
||||
|
||||
const auto hash = qHashBits( &innerRect, sizeof( innerRect ), 1450 );
|
||||
if ( ( hash == m_hash ) && ( rect == Inherited::clipRect() ) )
|
||||
return;
|
||||
|
||||
qskSetBoundingRect( this, rect );
|
||||
m_hash = hash;
|
||||
|
||||
m_geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
|
||||
|
||||
if ( innerRect.isEmpty() )
|
||||
{
|
||||
const auto l = qskAllocateLines( m_geometry, 2 );
|
||||
|
||||
l[0].setLine( rect.topLeft(), rect.topRight() );
|
||||
l[1].setLine( rect.bottomLeft(), rect.bottomRight() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto l = qskAllocateLines( m_geometry, 5 );
|
||||
|
||||
l[0].setLine( rect.topLeft(), innerRect.topLeft() );
|
||||
l[1].setLine( rect.topRight(), innerRect.topRight() );
|
||||
l[2].setLine( rect.bottomRight(), innerRect.bottomRight() );
|
||||
l[3].setLine( rect.bottomLeft(), innerRect.bottomLeft() );
|
||||
l[4] = l[0];
|
||||
}
|
||||
|
||||
m_geometry.markVertexDataDirty();
|
||||
markDirty( QSGNode::DirtyGeometry );
|
||||
}
|
||||
|
||||
void QskClipNode::setBox( const QQuickWindow* window, const QRectF& rect,
|
||||
const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
|
||||
{
|
||||
if ( rect.isEmpty() )
|
||||
{
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto hash = qskMetricsHash( shape, border );
|
||||
if ( hash == m_hash && rect == boundingRectangle() )
|
||||
return;
|
||||
|
||||
qskSetBoundingRect( this, rect );
|
||||
m_hash = hash;
|
||||
|
||||
QskBoxRenderer renderer( window );
|
||||
renderer.setFillLines( rect, shape, border, m_geometry );
|
||||
|
||||
m_geometry.markVertexDataDirty();
|
||||
markDirty( QSGNode::DirtyGeometry );
|
||||
}
|
||||
|
||||
void QskClipNode::reset()
|
||||
{
|
||||
Inherited::setIsRectangular( true );
|
||||
Inherited::setClipRect( QRectF() );
|
||||
|
||||
if ( m_geometry.vertexData() )
|
||||
{
|
||||
m_geometry.allocate( 0 );
|
||||
m_geometry.markVertexDataDirty();
|
||||
}
|
||||
|
||||
if ( m_hash != 0 )
|
||||
{
|
||||
m_hash = 0;
|
||||
markDirty( QSGNode::DirtyGeometry );
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_BOX_CLIP_NODE_H
|
||||
#define QSK_BOX_CLIP_NODE_H
|
||||
#ifndef QSK_CLIP_NODE_H
|
||||
#define QSK_CLIP_NODE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include <qsgnode.h>
|
||||
|
|
@ -14,20 +14,36 @@ class QskBoxBorderMetrics;
|
|||
|
||||
class QQuickWindow;
|
||||
|
||||
class QSK_EXPORT QskBoxClipNode : public QSGClipNode
|
||||
class QSK_EXPORT QskClipNode : public QSGClipNode
|
||||
{
|
||||
using Inherited = QSGClipNode;
|
||||
|
||||
public:
|
||||
QskBoxClipNode();
|
||||
~QskBoxClipNode() override;
|
||||
QskClipNode();
|
||||
~QskClipNode() override;
|
||||
|
||||
void setRect( const QRectF& );
|
||||
void setRegion( const QRectF&, const QRectF& excludedRect );
|
||||
|
||||
void setBox( const QQuickWindow*, const QRectF&,
|
||||
const QskBoxShapeMetrics&, const QskBoxBorderMetrics& );
|
||||
|
||||
private:
|
||||
QskHashValue m_hash;
|
||||
QRectF m_rect;
|
||||
QRectF boundingRectangle() const;
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
void setIsRectangular( bool ) = delete;
|
||||
void setClipRect( const QRectF& ) = delete;
|
||||
QRectF clipRect() const = delete;
|
||||
|
||||
QskHashValue m_hash;
|
||||
QSGGeometry m_geometry;
|
||||
};
|
||||
|
||||
inline QRectF QskClipNode::boundingRectangle() const
|
||||
{
|
||||
return Inherited::clipRect();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -88,13 +88,16 @@ void QskSGNode::setParentNode( QSGNode* node, QSGNode* parent )
|
|||
|
||||
QSGNode* QskSGNode::findChildNode( QSGNode* parent, quint8 role )
|
||||
{
|
||||
auto node = parent->firstChild();
|
||||
while ( node )
|
||||
if ( parent )
|
||||
{
|
||||
if ( nodeRole( node ) == role )
|
||||
return node;
|
||||
auto node = parent->firstChild();
|
||||
while ( node )
|
||||
{
|
||||
if ( nodeRole( node ) == role )
|
||||
return node;
|
||||
|
||||
node = node->nextSibling();
|
||||
node = node->nextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
|
|||
Loading…
Reference in New Issue