Merge 74c5178ce4 into 7acd0f9c63
This commit is contained in:
commit
00c7f6a6f5
|
|
@ -9,6 +9,8 @@
|
||||||
#include <QskLinearBox.h>
|
#include <QskLinearBox.h>
|
||||||
#include <QskPushButton.h>
|
#include <QskPushButton.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#if QT_CONFIG(thread)
|
#if QT_CONFIG(thread)
|
||||||
/*
|
/*
|
||||||
WebAssembly without asyncify support does not allow recursive
|
WebAssembly without asyncify support does not allow recursive
|
||||||
|
|
@ -96,6 +98,18 @@ namespace
|
||||||
auto selectButton = new Button( "Selection", this );
|
auto selectButton = new Button( "Selection", this );
|
||||||
connect( selectButton, &Button::clicked, this, &ButtonBox::execSelection );
|
connect( selectButton, &Button::clicked, this, &ButtonBox::execSelection );
|
||||||
|
|
||||||
|
auto fileSelectionButton = new Button( "File selection", this );
|
||||||
|
connect( fileSelectionButton, &Button::clicked, this, &ButtonBox::execFileSelection );
|
||||||
|
|
||||||
|
auto directorySelectionButton = new Button( "Directory selection", this );
|
||||||
|
connect( directorySelectionButton, &Button::clicked, this, &ButtonBox::execDirectorySelection );
|
||||||
|
|
||||||
|
auto colorSelectionButton = new Button( "Color selection", this );
|
||||||
|
connect( colorSelectionButton, &Button::clicked, this, &ButtonBox::execColorSelection );
|
||||||
|
|
||||||
|
auto fontSelectionButton = new Button( "Font selection", this );
|
||||||
|
connect( fontSelectionButton, &Button::clicked, this, &ButtonBox::execFontSelection );
|
||||||
|
|
||||||
setExtraSpacingAt( Qt::BottomEdge );
|
setExtraSpacingAt( Qt::BottomEdge );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +169,42 @@ namespace
|
||||||
QskDialog::Ok | QskDialog::Cancel, QskDialog::Ok, entries, 7 );
|
QskDialog::Ok | QskDialog::Cancel, QskDialog::Ok, entries, 7 );
|
||||||
#else
|
#else
|
||||||
(void )qskDialog->select( title, entries, 7 );
|
(void )qskDialog->select( title, entries, 7 );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void execFileSelection()
|
||||||
|
{
|
||||||
|
#ifndef QSK_USE_EXEC
|
||||||
|
// not implemented for now (class is not public)
|
||||||
|
#else
|
||||||
|
( void ) qskDialog->selectFile( "select file", QDir::currentPath() );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void execDirectorySelection()
|
||||||
|
{
|
||||||
|
#ifndef QSK_USE_EXEC
|
||||||
|
// not implemented for now (class is not public)
|
||||||
|
#else
|
||||||
|
( void ) qskDialog->selectDirectory( "select directory", QDir::currentPath() );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void execColorSelection()
|
||||||
|
{
|
||||||
|
#ifndef QSK_USE_EXEC
|
||||||
|
// not implemented for now (class is not public)
|
||||||
|
#else
|
||||||
|
( void ) qskDialog->selectColor( "select color" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void execFontSelection()
|
||||||
|
{
|
||||||
|
#ifndef QSK_USE_EXEC
|
||||||
|
// not implemented for now (class is not public)
|
||||||
|
#else
|
||||||
|
( void ) qskDialog->selectFont( "select font" );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QskCheckBox.h>
|
#include <QskCheckBox.h>
|
||||||
#include <QskLinearBox.h>
|
#include <QskLinearBox.h>
|
||||||
#include <QskMainView.h>
|
#include <QskMainView.h>
|
||||||
|
#include <QskDialog.h>
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
|
@ -20,34 +21,6 @@
|
||||||
#include <private/qquickfontdialog_p.h>
|
#include <private/qquickfontdialog_p.h>
|
||||||
#include <private/qquickmessagedialog_p.h>
|
#include <private/qquickmessagedialog_p.h>
|
||||||
|
|
||||||
#include <QtQml>
|
|
||||||
|
|
||||||
static QQuickAbstractDialog* createQml( const char* className )
|
|
||||||
{
|
|
||||||
static QQmlEngine engine( nullptr );
|
|
||||||
|
|
||||||
QByteArray qmlCode = "import QtQuick.Dialogs\n";
|
|
||||||
qmlCode += className;
|
|
||||||
qmlCode += " {}";
|
|
||||||
|
|
||||||
auto component = new QQmlComponent( &engine );
|
|
||||||
component->setData( qmlCode.constData(), QUrl() );
|
|
||||||
|
|
||||||
if ( component->status() != QQmlComponent::Ready )
|
|
||||||
{
|
|
||||||
qWarning() << component->errorString();
|
|
||||||
delete component;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dialog = qobject_cast< QQuickAbstractDialog* >( component->create() );
|
|
||||||
QObject::connect( dialog, &QObject::destroyed,
|
|
||||||
component, &QObject::deleteLater );
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class ButtonBox : public QskLinearBox
|
class ButtonBox : public QskLinearBox
|
||||||
|
|
@ -108,10 +81,38 @@ namespace
|
||||||
|
|
||||||
if ( qGuiApp->testAttribute( Qt::AA_DontUseNativeDialogs ) )
|
if ( qGuiApp->testAttribute( Qt::AA_DontUseNativeDialogs ) )
|
||||||
{
|
{
|
||||||
const auto metaEnum = QMetaEnum::fromType<DialogType>();
|
switch( dialogType )
|
||||||
m_dialog = createQml( metaEnum.key( dialogType ) );
|
{
|
||||||
if ( m_dialog )
|
case ColorDialog:
|
||||||
m_dialog->setParentWindow( window() );
|
{
|
||||||
|
qskDialog->selectColor( "select color" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FileDialog:
|
||||||
|
{
|
||||||
|
qskDialog->selectFile( "select file", QDir::currentPath() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FolderDialog:
|
||||||
|
{
|
||||||
|
qskDialog->selectDirectory( "select directory", QDir::currentPath() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FontDialog:
|
||||||
|
{
|
||||||
|
qskDialog->selectFont( "select font" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageDialog:
|
||||||
|
{
|
||||||
|
qskDialog->message( "message", "The quick brown fox jumps over the lazy dog" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
qWarning() << "unknown dialog type detected";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -458,16 +458,31 @@ list(APPEND HEADERS
|
||||||
dialogs/QskSelectionWindow.h
|
dialogs/QskSelectionWindow.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
list(APPEND PRIVATE_HEADERS
|
||||||
|
dialogs/QskColorPicker.h
|
||||||
|
dialogs/QskColorPickerSkinlet.h
|
||||||
|
dialogs/QskColorSelectionWindow.h
|
||||||
|
dialogs/QskFileSelectionWindow.h
|
||||||
|
dialogs/QskFontSelectionWindow.h
|
||||||
|
dialogs/QskWindowOrSubWindow.h
|
||||||
|
)
|
||||||
|
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
|
dialogs/QskColorPicker.cpp
|
||||||
|
dialogs/QskColorPickerSkinlet.cpp
|
||||||
|
dialogs/QskColorSelectionWindow.cpp
|
||||||
dialogs/QskDialogButton.cpp
|
dialogs/QskDialogButton.cpp
|
||||||
dialogs/QskDialogButtonBox.cpp
|
dialogs/QskDialogButtonBox.cpp
|
||||||
dialogs/QskDialog.cpp
|
dialogs/QskDialog.cpp
|
||||||
dialogs/QskDialogSubWindow.cpp
|
dialogs/QskDialogSubWindow.cpp
|
||||||
dialogs/QskDialogWindow.cpp
|
dialogs/QskDialogWindow.cpp
|
||||||
|
dialogs/QskFileSelectionWindow.cpp
|
||||||
|
dialogs/QskFontSelectionWindow.cpp
|
||||||
dialogs/QskMessageSubWindow.cpp
|
dialogs/QskMessageSubWindow.cpp
|
||||||
dialogs/QskMessageWindow.cpp
|
dialogs/QskMessageWindow.cpp
|
||||||
dialogs/QskSelectionSubWindow.cpp
|
dialogs/QskSelectionSubWindow.cpp
|
||||||
dialogs/QskSelectionWindow.cpp
|
dialogs/QskSelectionWindow.cpp
|
||||||
|
dialogs/QskWindowOrSubWindow.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND HEADERS
|
list(APPEND HEADERS
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,9 @@
|
||||||
#include "QskStatusIndicator.h"
|
#include "QskStatusIndicator.h"
|
||||||
#include "QskStatusIndicatorSkinlet.h"
|
#include "QskStatusIndicatorSkinlet.h"
|
||||||
|
|
||||||
|
#include "QskColorPicker.h"
|
||||||
|
#include "QskColorPickerSkinlet.h"
|
||||||
|
|
||||||
#include "QskInternalMacros.h"
|
#include "QskInternalMacros.h"
|
||||||
|
|
||||||
#include <qhash.h>
|
#include <qhash.h>
|
||||||
|
|
@ -219,6 +222,7 @@ QskSkin::QskSkin( QObject* parent )
|
||||||
declareSkinlet< QskProgressBar, QskProgressBarSkinlet >();
|
declareSkinlet< QskProgressBar, QskProgressBarSkinlet >();
|
||||||
declareSkinlet< QskProgressRing, QskProgressRingSkinlet >();
|
declareSkinlet< QskProgressRing, QskProgressRingSkinlet >();
|
||||||
declareSkinlet< QskRadioBox, QskRadioBoxSkinlet >();
|
declareSkinlet< QskRadioBox, QskRadioBoxSkinlet >();
|
||||||
|
declareSkinlet< QskColorPicker, QskColorPickerSkinlet >();
|
||||||
|
|
||||||
const QFont font = QGuiApplication::font();
|
const QFont font = QGuiApplication::font();
|
||||||
setupFontTable( font.family(), font.italic() );
|
setupFontTable( font.family(), font.italic() );
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskColorPicker.h"
|
||||||
|
#include "QskColorPickerSkinlet.h"
|
||||||
|
#include "QskEvent.h"
|
||||||
|
#include "QskFunctions.h"
|
||||||
|
|
||||||
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
QSK_SUBCONTROL( QskColorPicker, Panel )
|
||||||
|
QSK_SUBCONTROL( QskColorPicker, ColorPane )
|
||||||
|
QSK_SUBCONTROL( QskColorPicker, Selector )
|
||||||
|
|
||||||
|
using A = QskAspect;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const auto HPos = QskColorPicker::Selector | A::Horizontal;
|
||||||
|
const auto VPos = QskColorPicker::Selector | A::Vertical;
|
||||||
|
|
||||||
|
void createImage( QImage* image, const QSizeF& size, qreal v )
|
||||||
|
{
|
||||||
|
if( image->size() != size )
|
||||||
|
{
|
||||||
|
*image = QImage( size.width(), size.height(), QImage::Format_RGB32 );
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor color;
|
||||||
|
float h, s;
|
||||||
|
|
||||||
|
for ( int y = 0; y < image->height(); y++ )
|
||||||
|
{
|
||||||
|
s = 1.0 - static_cast< float >( y ) / image->height();
|
||||||
|
auto line = reinterpret_cast< QRgb* >( image->scanLine( y ) );
|
||||||
|
|
||||||
|
for ( int x = 0; x < image->width(); x++ )
|
||||||
|
{
|
||||||
|
h = static_cast< float >( x ) / image->width();
|
||||||
|
color.setHsvF( h, s, v );
|
||||||
|
*line++ = color.rgb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class QskColorPicker::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
qreal value = 255;
|
||||||
|
bool isPressed = false;
|
||||||
|
QImage image;
|
||||||
|
};
|
||||||
|
|
||||||
|
QskColorPicker::QskColorPicker( QQuickItem* parent )
|
||||||
|
: Inherited( parent )
|
||||||
|
, m_data( new PrivateData )
|
||||||
|
{
|
||||||
|
setAcceptedMouseButtons( Qt::LeftButton );
|
||||||
|
setBoundaries( 0, 255 );
|
||||||
|
setPolishOnResize( true );
|
||||||
|
createImage();
|
||||||
|
setPositionHint( HPos, -1 );
|
||||||
|
setPositionHint( VPos, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskColorPicker::~QskColorPicker() = default;
|
||||||
|
|
||||||
|
QColor QskColorPicker::selectedColor() const
|
||||||
|
{
|
||||||
|
if( image().isNull() )
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_data->image.pixelColor( position().toPoint() );
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal QskColorPicker::value() const
|
||||||
|
{
|
||||||
|
return m_data->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal QskColorPicker::valueAsRatio() const
|
||||||
|
{
|
||||||
|
return valueAsRatio( m_data->value );
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage QskColorPicker::image() const
|
||||||
|
{
|
||||||
|
return m_data->image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::setValue( qreal v )
|
||||||
|
{
|
||||||
|
if( !qskFuzzyCompare( m_data->value, v ) )
|
||||||
|
{
|
||||||
|
m_data->value = v;
|
||||||
|
createImage();
|
||||||
|
update();
|
||||||
|
Q_EMIT valueChanged( m_data->value );
|
||||||
|
Q_EMIT selectedColorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::setValueAsRatio( qreal ratio )
|
||||||
|
{
|
||||||
|
ratio = qBound( 0.0, ratio, 1.0 );
|
||||||
|
setValue( minimum() + ratio * boundaryLength() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::updateLayout()
|
||||||
|
{
|
||||||
|
createImage();
|
||||||
|
updatePosition( position() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::mousePressEvent( QMouseEvent* event )
|
||||||
|
{
|
||||||
|
m_data->isPressed = true;
|
||||||
|
updatePosition( qskMousePosition( event ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::mouseMoveEvent( QMouseEvent* event )
|
||||||
|
{
|
||||||
|
if( !m_data->isPressed )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition( qskMousePosition( event ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::mouseReleaseEvent( QMouseEvent* )
|
||||||
|
{
|
||||||
|
m_data->isPressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::updatePosition( const QPointF& point )
|
||||||
|
{
|
||||||
|
const auto rect = subControlRect( ColorPane );
|
||||||
|
|
||||||
|
if( rect.isEmpty() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p = point;
|
||||||
|
p.rx() = qBound( rect.x(), p.x(), rect.right() - 1.0 );
|
||||||
|
p.ry() = qBound( rect.y(), p.y(), rect.bottom() - 1.0 );
|
||||||
|
|
||||||
|
const auto oldX = positionHint( HPos );
|
||||||
|
const auto oldY = positionHint( VPos );
|
||||||
|
|
||||||
|
if( !qskFuzzyCompare( p.x(), oldX ) || !qskFuzzyCompare( p.y(), oldY ) )
|
||||||
|
{
|
||||||
|
setPositionHint( HPos, p.x() );
|
||||||
|
setPositionHint( VPos, p.y() );
|
||||||
|
|
||||||
|
update();
|
||||||
|
Q_EMIT positionChanged();
|
||||||
|
Q_EMIT selectedColorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF QskColorPicker::position() const
|
||||||
|
{
|
||||||
|
const auto r = subControlRect( ColorPane );
|
||||||
|
|
||||||
|
if( !r.size().isValid() )
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto x = positionHint( HPos );
|
||||||
|
const auto y = positionHint( VPos );
|
||||||
|
return { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskColorPicker::createImage()
|
||||||
|
{
|
||||||
|
const auto r = subControlRect( ColorPane );
|
||||||
|
const auto ratio = window() ? window()->effectiveDevicePixelRatio() : 1.0;
|
||||||
|
const auto size = r.size() * ratio;
|
||||||
|
|
||||||
|
::createImage( &m_data->image, size, valueAsRatio() );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_QskColorPicker.cpp"
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_COLOR_PICKER_H
|
||||||
|
#define QSK_COLOR_PICKER_H
|
||||||
|
|
||||||
|
#include "QskBoundedControl.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class QskColorPicker : public QskBoundedControl
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
using Inherited = QskBoundedControl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QSK_SUBCONTROLS( Panel, ColorPane, Selector )
|
||||||
|
|
||||||
|
QskColorPicker( QQuickItem* parentItem = nullptr );
|
||||||
|
~QskColorPicker() override;
|
||||||
|
|
||||||
|
QColor selectedColor() const;
|
||||||
|
|
||||||
|
qreal value() const; // value as in hue / saturation / value
|
||||||
|
qreal valueAsRatio() const; // [0.0, 1.0]
|
||||||
|
using QskBoundedControl::valueAsRatio;
|
||||||
|
|
||||||
|
QImage image() const;
|
||||||
|
QPointF position() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setValue( qreal );
|
||||||
|
void setValueAsRatio( qreal );
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void valueChanged( qreal );
|
||||||
|
void selectedColorChanged();
|
||||||
|
void positionChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateLayout() override;
|
||||||
|
void mousePressEvent( QMouseEvent* ) override;
|
||||||
|
void mouseMoveEvent( QMouseEvent* ) override;
|
||||||
|
void mouseReleaseEvent( QMouseEvent* ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updatePosition( const QPointF& );
|
||||||
|
void createImage();
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskColorPickerSkinlet.h"
|
||||||
|
#include "QskColorPicker.h"
|
||||||
|
|
||||||
|
#include "QskSGNode.h"
|
||||||
|
#include "QskPaintedNode.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
using Q = QskColorPicker;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class ColorPaneNode : public QskPaintedNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void paint( QPainter* p, const QSize& size, const void* nodeData ) override
|
||||||
|
{
|
||||||
|
const Q* q = static_cast< const Q* >( nodeData );
|
||||||
|
const auto image = q->image().scaled( size );
|
||||||
|
p->drawImage( QPointF( 0, 0 ), image );
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateNode( QQuickWindow* window, const QRectF& rect, const Q* q )
|
||||||
|
{
|
||||||
|
update( window, rect, QSizeF(), q );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QskHashValue hash( const void* nodeData ) const override
|
||||||
|
{
|
||||||
|
const Q* q = static_cast< const Q* >( nodeData );
|
||||||
|
const auto r = q->subControlRect( Q::ColorPane );
|
||||||
|
|
||||||
|
QskHashValue h = qHash( r.width() );
|
||||||
|
h = qHash( r.height() );
|
||||||
|
h = qHash( q->value() );
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QskColorPickerSkinlet::QskColorPickerSkinlet( QskSkin* skin )
|
||||||
|
: Inherited( skin )
|
||||||
|
{
|
||||||
|
setNodeRoles( { PanelRole, ColorPaneRole, SelectorRole } );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskColorPickerSkinlet::~QskColorPickerSkinlet() = default;
|
||||||
|
|
||||||
|
QSGNode* QskColorPickerSkinlet::updateSubNode(
|
||||||
|
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||||
|
{
|
||||||
|
const auto q = static_cast< const Q* >( skinnable );
|
||||||
|
|
||||||
|
switch ( nodeRole )
|
||||||
|
{
|
||||||
|
case PanelRole:
|
||||||
|
{
|
||||||
|
return updateBoxNode( skinnable, node, Q::Panel );
|
||||||
|
}
|
||||||
|
case ColorPaneRole:
|
||||||
|
{
|
||||||
|
return updateColorPaneNode( q, node );
|
||||||
|
}
|
||||||
|
case SelectorRole:
|
||||||
|
{
|
||||||
|
return updateBoxNode( skinnable, node, Q::Selector );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF QskColorPickerSkinlet::subControlRect(
|
||||||
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
||||||
|
QskAspect::Subcontrol subControl ) const
|
||||||
|
{
|
||||||
|
const auto q = static_cast< const Q* >( skinnable );
|
||||||
|
|
||||||
|
if( subControl == Q::Panel || subControl == Q::ColorPane )
|
||||||
|
{
|
||||||
|
return contentsRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( subControl == Q::Selector )
|
||||||
|
{
|
||||||
|
const auto s = q->strutSizeHint( Q::Selector );
|
||||||
|
const auto p = q->position();
|
||||||
|
|
||||||
|
const QRectF r( { p.x() - s.width() / 2.0, p.y() - s.height() / 2.0 }, s );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* QskColorPickerSkinlet::updateColorPaneNode(
|
||||||
|
const QskColorPicker* q, QSGNode* node ) const
|
||||||
|
{
|
||||||
|
auto* colorPaneNode = QskSGNode::ensureNode< ColorPaneNode >( node );
|
||||||
|
|
||||||
|
const auto rect = q->subControlRect( Q::ColorPane );
|
||||||
|
|
||||||
|
colorPaneNode->updateNode( q->window(), rect, q );
|
||||||
|
|
||||||
|
return colorPaneNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_QskColorPickerSkinlet.cpp"
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_COLOR_PICKER_SKINLET_H
|
||||||
|
#define QSK_COLOR_PICKER_SKINLET_H
|
||||||
|
|
||||||
|
#include "QskSkinlet.h"
|
||||||
|
|
||||||
|
class QskColorPicker;
|
||||||
|
|
||||||
|
class QskColorPickerSkinlet : public QskSkinlet
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
using Inherited = QskSkinlet;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum NodeRole : quint8
|
||||||
|
{
|
||||||
|
PanelRole,
|
||||||
|
ColorPaneRole,
|
||||||
|
SelectorRole,
|
||||||
|
|
||||||
|
RoleCount
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_INVOKABLE QskColorPickerSkinlet( QskSkin* = nullptr );
|
||||||
|
~QskColorPickerSkinlet() override;
|
||||||
|
|
||||||
|
QRectF subControlRect( const QskSkinnable*,
|
||||||
|
const QRectF&, QskAspect::Subcontrol ) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QSGNode* updateSubNode( const QskSkinnable*,
|
||||||
|
quint8 nodeRole, QSGNode* ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSGNode* updateColorPaneNode( const QskColorPicker*, QSGNode* ) const;
|
||||||
|
|
||||||
|
QRectF cursorRect( const QskSkinnable*, const QRectF&, int index ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskColorSelectionWindow.h"
|
||||||
|
|
||||||
|
#include "QskBoxBorderColors.h"
|
||||||
|
#include "QskBoxBorderMetrics.h"
|
||||||
|
#include "QskBoxShapeMetrics.h"
|
||||||
|
#include "QskColorPicker.h"
|
||||||
|
#include "QskComboBox.h"
|
||||||
|
#include "QskGridBox.h"
|
||||||
|
#include "QskLinearBox.h"
|
||||||
|
#include "QskSlider.h"
|
||||||
|
#include "QskTextField.h"
|
||||||
|
#include "QskTextLabel.h"
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskColorSelectionWindow< W >::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskColorPicker* colorPicker;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskColorSelectionWindow< W >::QskColorSelectionWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction )
|
||||||
|
: Inherited( parent, title, actions, defaultAction )
|
||||||
|
, m_data( new PrivateData )
|
||||||
|
{
|
||||||
|
auto* outerBox = new QskLinearBox( Qt::Vertical );
|
||||||
|
outerBox->setMargins( 20 );
|
||||||
|
outerBox->setSpacing( 20 );
|
||||||
|
#if 1
|
||||||
|
outerBox->setFixedSize( 350, 500 );
|
||||||
|
#endif
|
||||||
|
auto* upperBox = new QskLinearBox( Qt::Horizontal, outerBox );
|
||||||
|
upperBox->setSizePolicy( Qt::Vertical, QskSizePolicy::Expanding );
|
||||||
|
upperBox->setSpacing( 12 );
|
||||||
|
|
||||||
|
m_data->colorPicker = new QskColorPicker( upperBox );
|
||||||
|
m_data->colorPicker->setStrutSizeHint( QskColorPicker::Selector, { 18, 18 } );
|
||||||
|
m_data->colorPicker->setBoxShapeHint( QskColorPicker::Selector, { 100, Qt::RelativeSize } );
|
||||||
|
m_data->colorPicker->setBoxBorderMetricsHint( QskColorPicker::Selector, 2 );
|
||||||
|
m_data->colorPicker->setBoxBorderColorsHint( QskColorPicker::Selector, Qt::black );
|
||||||
|
m_data->colorPicker->setGradientHint( QskColorPicker::Selector, Qt::transparent );
|
||||||
|
|
||||||
|
auto* outputBox = new QskBox( upperBox );
|
||||||
|
outputBox->setPanel( true );
|
||||||
|
|
||||||
|
QObject::connect( m_data->colorPicker, &QskColorPicker::selectedColorChanged,
|
||||||
|
this, [this, outputBox]()
|
||||||
|
{
|
||||||
|
const auto c = m_data->colorPicker->selectedColor();
|
||||||
|
outputBox->setGradientHint( QskBox::Panel, c );
|
||||||
|
} );
|
||||||
|
|
||||||
|
upperBox->setStretchFactor( m_data->colorPicker, 9 );
|
||||||
|
upperBox->setStretchFactor( outputBox, 1 );
|
||||||
|
|
||||||
|
|
||||||
|
auto* valueSlider = new QskSlider( outerBox );
|
||||||
|
valueSlider->setBoundaries( 0, 1 );
|
||||||
|
valueSlider->setValue( m_data->colorPicker->value() );
|
||||||
|
|
||||||
|
QskGradient g( Qt::black, Qt::white );
|
||||||
|
g.setLinearDirection( Qt::Horizontal );
|
||||||
|
valueSlider->setGradientHint( QskSlider::Groove, g );
|
||||||
|
valueSlider->setGradientHint( QskSlider::Fill, Qt::transparent );
|
||||||
|
valueSlider->setGradientHint( QskSlider::Handle, Qt::black );
|
||||||
|
|
||||||
|
QObject::connect( valueSlider, &QskSlider::valueChanged,
|
||||||
|
m_data->colorPicker, &QskColorPicker::setValueAsRatio );
|
||||||
|
|
||||||
|
|
||||||
|
auto* gridBox = new QskGridBox( outerBox );
|
||||||
|
gridBox->setSizePolicy( Qt::Vertical, QskSizePolicy::Preferred );
|
||||||
|
|
||||||
|
auto* menu = new QskComboBox( gridBox );
|
||||||
|
menu->addOption( QUrl(), "RGB" );
|
||||||
|
menu->setCurrentIndex( 0 );
|
||||||
|
gridBox->addItem( menu, 0, 0 );
|
||||||
|
|
||||||
|
auto* rgbValue = new QskTextField( gridBox );
|
||||||
|
rgbValue->setReadOnly( true );
|
||||||
|
gridBox->addItem( rgbValue, 0, 2 );
|
||||||
|
|
||||||
|
auto* redValue = new QskTextField( gridBox );
|
||||||
|
redValue->setReadOnly( true );
|
||||||
|
gridBox->addItem( redValue, 1, 0 );
|
||||||
|
gridBox->addItem( new QskTextLabel( "Red", gridBox ), 1, 1 );
|
||||||
|
|
||||||
|
auto* greenValue = new QskTextField( gridBox );
|
||||||
|
greenValue->setReadOnly( true );
|
||||||
|
gridBox->addItem( greenValue, 2, 0 );
|
||||||
|
gridBox->addItem( new QskTextLabel( "Green", gridBox ), 2, 1 );
|
||||||
|
|
||||||
|
auto* blueValue = new QskTextField( gridBox );
|
||||||
|
blueValue->setReadOnly( true );
|
||||||
|
gridBox->addItem( blueValue, 3, 0 );
|
||||||
|
gridBox->addItem( new QskTextLabel( "Blue", gridBox ), 3, 1 );
|
||||||
|
|
||||||
|
QObject::connect( m_data->colorPicker, &QskColorPicker::selectedColorChanged,
|
||||||
|
this, [this, rgbValue, redValue, greenValue, blueValue]()
|
||||||
|
{
|
||||||
|
const auto c = m_data->colorPicker->selectedColor();
|
||||||
|
rgbValue->setText( c.name() );
|
||||||
|
|
||||||
|
redValue->setText( QString::number( c.red() ) );
|
||||||
|
greenValue->setText( QString::number( c.green() ) );
|
||||||
|
blueValue->setText( QString::number( c.blue() ) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
Inherited::setContentItem( outerBox );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskColorSelectionWindow< W >::~QskColorSelectionWindow() = default;
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QColor QskColorSelectionWindow< W >::selectedColor() const
|
||||||
|
{
|
||||||
|
return m_data->colorPicker->selectedColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
template class QskColorSelectionWindow< QskDialogWindow >;
|
||||||
|
template class QskColorSelectionWindow< QskDialogSubWindow >;
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_COLOR_SELECTION_WINDODW_H
|
||||||
|
#define QSK_COLOR_SELECTION_WINDODW_H
|
||||||
|
|
||||||
|
#include "QskWindowOrSubWindow.h"
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskColorSelectionWindow : public QskWindowOrSubWindow< W >
|
||||||
|
{
|
||||||
|
using Inherited = QskWindowOrSubWindow< W >;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
QskColorSelectionWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction );
|
||||||
|
~QskColorSelectionWindow();
|
||||||
|
|
||||||
|
QColor selectedColor() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
#include "QskSelectionSubWindow.h"
|
#include "QskSelectionSubWindow.h"
|
||||||
#include "QskSelectionWindow.h"
|
#include "QskSelectionWindow.h"
|
||||||
|
|
||||||
|
#include "QskColorSelectionWindow.h"
|
||||||
|
#include "QskFileSelectionWindow.h"
|
||||||
|
#include "QskFontSelectionWindow.h"
|
||||||
|
|
||||||
#include "QskFocusIndicator.h"
|
#include "QskFocusIndicator.h"
|
||||||
|
|
||||||
#include <qguiapplication.h>
|
#include <qguiapplication.h>
|
||||||
|
|
@ -207,6 +211,39 @@ static QString qskSelectWindow(
|
||||||
return selectedEntry;
|
return selectedEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
static QString qskSelectPath( QskFileSelectionWindow< W >& window )
|
||||||
|
{
|
||||||
|
QString selectedFile = window.selectedPath();
|
||||||
|
|
||||||
|
if( window.exec() == QskDialog::Accepted )
|
||||||
|
selectedFile = window.selectedPath();
|
||||||
|
|
||||||
|
return selectedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
static QColor qskSelectColor( QskColorSelectionWindow< W >& window )
|
||||||
|
{
|
||||||
|
QColor selectedColor = window.selectedColor();
|
||||||
|
|
||||||
|
if( window.exec() == QskDialog::Accepted )
|
||||||
|
selectedColor = window.selectedColor();
|
||||||
|
|
||||||
|
return selectedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
static QFont qskSelectFont( QskFontSelectionWindow< W >& window )
|
||||||
|
{
|
||||||
|
QFont selectedFont = window.selectedFont();
|
||||||
|
|
||||||
|
if( window.exec() == QskDialog::Accepted )
|
||||||
|
selectedFont = window.selectedFont();
|
||||||
|
|
||||||
|
return selectedFont;
|
||||||
|
}
|
||||||
|
|
||||||
class QskDialog::PrivateData
|
class QskDialog::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -321,6 +358,124 @@ QString QskDialog::select( const QString& title,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QskDialog::selectFile(
|
||||||
|
const QString& title, const QString& directory ) const
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// should be parameters
|
||||||
|
const auto actions = QskDialog::Ok | QskDialog::Cancel;
|
||||||
|
const auto defaultAction = QskDialog::Ok;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto filters = QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs;
|
||||||
|
|
||||||
|
if ( m_data->policy == EmbeddedBox )
|
||||||
|
{
|
||||||
|
auto quickWindow = qobject_cast< QQuickWindow* >( m_data->transientParent );
|
||||||
|
|
||||||
|
if ( quickWindow == nullptr )
|
||||||
|
quickWindow = qskSomeQuickWindow();
|
||||||
|
|
||||||
|
if ( quickWindow )
|
||||||
|
{
|
||||||
|
QskFileSelectionWindow< QskDialogSubWindow > window( quickWindow, title,
|
||||||
|
actions, defaultAction, directory, filters );
|
||||||
|
return qskSelectPath< QskDialogSubWindow >( window );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskFileSelectionWindow< QskDialogWindow > window( m_data->transientParent, title,
|
||||||
|
actions, defaultAction, directory, filters );
|
||||||
|
return qskSelectPath< QskDialogWindow >( window );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QskDialog::selectDirectory(
|
||||||
|
const QString& title, const QString& directory ) const
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// should be parameters
|
||||||
|
const auto actions = QskDialog::Ok | QskDialog::Cancel;
|
||||||
|
const auto defaultAction = QskDialog::Ok;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto filters = QDir::NoDotAndDotDot | QDir::AllDirs;
|
||||||
|
|
||||||
|
if ( m_data->policy == EmbeddedBox )
|
||||||
|
{
|
||||||
|
auto quickWindow = qobject_cast< QQuickWindow* >( m_data->transientParent );
|
||||||
|
|
||||||
|
if ( quickWindow == nullptr )
|
||||||
|
quickWindow = qskSomeQuickWindow();
|
||||||
|
|
||||||
|
if ( quickWindow )
|
||||||
|
{
|
||||||
|
QskFileSelectionWindow< QskDialogSubWindow > window( quickWindow, title,
|
||||||
|
actions, defaultAction, directory, filters );
|
||||||
|
return qskSelectPath< QskDialogSubWindow >( window );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskFileSelectionWindow< QskDialogWindow > window( m_data->transientParent, title,
|
||||||
|
actions, defaultAction, directory, filters );
|
||||||
|
return qskSelectPath< QskDialogWindow >( window );
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor QskDialog::selectColor( const QString& title ) const
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// should be parameters
|
||||||
|
const auto actions = QskDialog::Ok | QskDialog::Cancel;
|
||||||
|
const auto defaultAction = QskDialog::Ok;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( m_data->policy == EmbeddedBox )
|
||||||
|
{
|
||||||
|
auto quickWindow = qobject_cast< QQuickWindow* >( m_data->transientParent );
|
||||||
|
|
||||||
|
if ( quickWindow == nullptr )
|
||||||
|
quickWindow = qskSomeQuickWindow();
|
||||||
|
|
||||||
|
if ( quickWindow )
|
||||||
|
{
|
||||||
|
QskColorSelectionWindow< QskDialogSubWindow > window( quickWindow, title,
|
||||||
|
actions, defaultAction );
|
||||||
|
return qskSelectColor< QskDialogSubWindow >( window );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskColorSelectionWindow< QskDialogWindow > window( m_data->transientParent, title,
|
||||||
|
actions, defaultAction );
|
||||||
|
return qskSelectColor< QskDialogWindow >( window );
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont QskDialog::selectFont( const QString& title ) const
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// should be parameters
|
||||||
|
const auto actions = QskDialog::Ok | QskDialog::Cancel;
|
||||||
|
const auto defaultAction = QskDialog::Ok;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( m_data->policy == EmbeddedBox )
|
||||||
|
{
|
||||||
|
auto quickWindow = qobject_cast< QQuickWindow* >( m_data->transientParent );
|
||||||
|
|
||||||
|
if ( quickWindow == nullptr )
|
||||||
|
quickWindow = qskSomeQuickWindow();
|
||||||
|
|
||||||
|
if ( quickWindow )
|
||||||
|
{
|
||||||
|
QskFontSelectionWindow< QskDialogSubWindow > window( quickWindow, title,
|
||||||
|
actions, defaultAction );
|
||||||
|
return qskSelectFont< QskDialogSubWindow >( window );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QskFontSelectionWindow< QskDialogWindow > window( m_data->transientParent, title,
|
||||||
|
actions, defaultAction );
|
||||||
|
return qskSelectFont< QskDialogWindow >( window );
|
||||||
|
}
|
||||||
|
|
||||||
QskDialog::ActionRole QskDialog::actionRole( Action action )
|
QskDialog::ActionRole QskDialog::actionRole( Action action )
|
||||||
{
|
{
|
||||||
using Q = QPlatformDialogHelper;
|
using Q = QPlatformDialogHelper;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
#include "QskGlobal.h"
|
||||||
|
|
||||||
|
#include <qcolor.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -130,6 +131,16 @@ class QSK_EXPORT QskDialog : public QObject
|
||||||
Q_INVOKABLE QString select( const QString& title,
|
Q_INVOKABLE QString select( const QString& title,
|
||||||
const QStringList& entries, int selectedRow = 0 ) const;
|
const QStringList& entries, int selectedRow = 0 ) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QString selectFile( const QString& title,
|
||||||
|
const QString& directory ) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QString selectDirectory( const QString& title,
|
||||||
|
const QString& directory ) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QColor selectColor( const QString& title ) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QFont selectFont( const QString& title ) const;
|
||||||
|
|
||||||
static ActionRole actionRole( Action action );
|
static ActionRole actionRole( Action action );
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,455 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskFileSelectionWindow.h"
|
||||||
|
|
||||||
|
#include "QskEvent.h"
|
||||||
|
#include "QskFunctions.h"
|
||||||
|
#include "QskInternalMacros.h"
|
||||||
|
#include "QskLinearBox.h"
|
||||||
|
#include "QskListView.h"
|
||||||
|
#include "QskScrollArea.h"
|
||||||
|
#include "QskPushButton.h"
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
#include <QDateTime>
|
||||||
|
#else
|
||||||
|
#include <QFileSystemModel>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qquickwindow_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
// copied from QskListView.cpp:
|
||||||
|
static inline int qskRowAt( const QskListView* listView, const QPointF& pos )
|
||||||
|
{
|
||||||
|
const auto rect = listView->viewContentsRect();
|
||||||
|
if ( rect.contains( pos ) )
|
||||||
|
{
|
||||||
|
const auto y = pos.y() - rect.top() + listView->scrollPos().y();
|
||||||
|
|
||||||
|
const int row = y / listView->rowHeight();
|
||||||
|
if ( row >= 0 && row < listView->rowCount() )
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from QskGestureRecognizer.cpp:
|
||||||
|
static QMouseEvent* qskClonedMouseEvent( const QMouseEvent* event )
|
||||||
|
{
|
||||||
|
QMouseEvent* clonedEvent;
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
clonedEvent = QQuickWindowPrivate::cloneMouseEvent(
|
||||||
|
const_cast< QMouseEvent* >( event ), nullptr );
|
||||||
|
#else
|
||||||
|
clonedEvent = event->clone();
|
||||||
|
#endif
|
||||||
|
clonedEvent->setAccepted( false );
|
||||||
|
|
||||||
|
return clonedEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
class Model : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Model( QObject* parent )
|
||||||
|
: QObject( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString rootPath() const
|
||||||
|
{
|
||||||
|
return m_dir.absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRootPath( const QString& path )
|
||||||
|
{
|
||||||
|
m_dir.setPath( path );
|
||||||
|
m_list = m_dir.entryInfoList();
|
||||||
|
Q_EMIT directoryLoaded( m_dir.path() );
|
||||||
|
Q_EMIT rootPathChanged( m_dir.path() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir::Filters filter() const
|
||||||
|
{
|
||||||
|
return m_dir.filter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFilter( QDir::Filters filter )
|
||||||
|
{
|
||||||
|
m_dir.setFilter( filter );
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows() const
|
||||||
|
{
|
||||||
|
return m_dir.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
int columns() const
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant entry( int row, int col )
|
||||||
|
{
|
||||||
|
Q_ASSERT( row < m_list.count() );
|
||||||
|
|
||||||
|
const auto fi = m_list.at( row );
|
||||||
|
|
||||||
|
switch( col )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return fi.fileName();
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if( fi.isDir() )
|
||||||
|
return "Directory";
|
||||||
|
else if( fi.isExecutable() )
|
||||||
|
return "Executable";
|
||||||
|
else
|
||||||
|
return "File";
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fi.fileTime( QFileDevice::FileAccessTime ).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void directoryLoaded( const QString& path );
|
||||||
|
void rootPathChanged( const QString& path );
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDir m_dir;
|
||||||
|
QFileInfoList m_list;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
class Model : public QFileSystemModel
|
||||||
|
{
|
||||||
|
using Inherited = QFileSystemModel;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Model( QObject* parent )
|
||||||
|
: QFileSystemModel( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows() const
|
||||||
|
{
|
||||||
|
const auto i = index( rootPath() );
|
||||||
|
return Inherited::rowCount( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
int columns() const
|
||||||
|
{
|
||||||
|
const auto i = index( rootPath() );
|
||||||
|
return Inherited::columnCount( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant entry( int row, int col ) const
|
||||||
|
{
|
||||||
|
const auto rootIndex = index( rootPath() );
|
||||||
|
|
||||||
|
const auto i = index( row, col, rootIndex );
|
||||||
|
const auto v = data( i );
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class FileSystemView : public QskListView
|
||||||
|
{
|
||||||
|
using Inherited = QskListView;
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileSystemView( const QString& directory, QDir::Filters filters, QQuickItem* parent = nullptr )
|
||||||
|
: QskListView( parent )
|
||||||
|
, m_model( new Model( this ) )
|
||||||
|
{
|
||||||
|
const auto defaultWidth = 50;
|
||||||
|
|
||||||
|
connect( m_model, &Model::directoryLoaded, this, [this, defaultWidth]()
|
||||||
|
{
|
||||||
|
m_columnWidths.fill( defaultWidth );
|
||||||
|
updateScrollableSize();
|
||||||
|
setScrollPos( { 0, 0 } );
|
||||||
|
setSelectedRow( -1 );
|
||||||
|
});
|
||||||
|
|
||||||
|
connect( m_model, &Model::rootPathChanged,
|
||||||
|
this, &FileSystemView::rootPathChanged );
|
||||||
|
|
||||||
|
m_columnWidths.fill( defaultWidth, m_model->columns() );
|
||||||
|
|
||||||
|
m_model->setFilter( filters );
|
||||||
|
m_model->setRootPath( {} ); // invalidate to make sure to get an update
|
||||||
|
m_model->setRootPath( directory );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int rowCount() const override
|
||||||
|
{
|
||||||
|
return m_model->rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int columnCount() const override
|
||||||
|
{
|
||||||
|
return m_model->columns();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual qreal columnWidth( int col ) const override
|
||||||
|
{
|
||||||
|
auto w = m_columnWidths.at( col );
|
||||||
|
|
||||||
|
if( col == 0 )
|
||||||
|
{
|
||||||
|
w = qMax( 250, w ); // min width for the name
|
||||||
|
}
|
||||||
|
|
||||||
|
return w + 15; // spacing
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual qreal rowHeight() const override
|
||||||
|
{
|
||||||
|
const auto hint = strutSizeHint( Cell );
|
||||||
|
const auto padding = paddingHint( Cell );
|
||||||
|
|
||||||
|
qreal h = effectiveFontHeight( Text );
|
||||||
|
h += padding.top() + padding.bottom();
|
||||||
|
|
||||||
|
return qMax( h, hint.height() );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual QVariant valueAt( int row, int col ) const override
|
||||||
|
{
|
||||||
|
const auto v = m_model->entry( row, col );
|
||||||
|
|
||||||
|
const auto w = qskHorizontalAdvance( effectiveFont( Text ), v.toString() );
|
||||||
|
|
||||||
|
if( w > m_columnWidths.at( col ) )
|
||||||
|
{
|
||||||
|
m_columnWidths[ col ] = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString rootPath() const
|
||||||
|
{
|
||||||
|
return m_model->rootPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRootPath( const QString& rootPath )
|
||||||
|
{
|
||||||
|
m_model->setRootPath( rootPath );
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir::Filters filter() const
|
||||||
|
{
|
||||||
|
return m_model->filter();
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void rootPathChanged( const QString& rootPath );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent( QMouseEvent* event ) override
|
||||||
|
{
|
||||||
|
if( m_doubleClickEvent && m_doubleClickEvent->timestamp() == event->timestamp() )
|
||||||
|
{
|
||||||
|
// do not select rows from double click mouse events
|
||||||
|
m_doubleClickEvent = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Inherited::mousePressEvent( event );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseDoubleClickEvent( QMouseEvent* event ) override
|
||||||
|
{
|
||||||
|
m_doubleClickEvent = qskClonedMouseEvent( event );
|
||||||
|
|
||||||
|
const int row = qskRowAt( this, qskMousePosition( event ) );
|
||||||
|
const auto path = valueAt( row, 0 ).toString();
|
||||||
|
|
||||||
|
QFileInfo fi( m_model->rootPath(), path );
|
||||||
|
|
||||||
|
if( fi.isDir() )
|
||||||
|
{
|
||||||
|
m_model->setRootPath( fi.absoluteFilePath() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Inherited::mouseDoubleClickEvent( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model* const m_model;
|
||||||
|
mutable QVector< int > m_columnWidths;
|
||||||
|
QMouseEvent* m_doubleClickEvent = nullptr;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskFileSelectionWindow< W >::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskScrollArea* headerScrollArea;
|
||||||
|
QskLinearBox* headerBox;
|
||||||
|
QVector< QskPushButton* > breadcrumbsButtons;
|
||||||
|
|
||||||
|
FileSystemView* fileView;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskFileSelectionWindow< W >::QskFileSelectionWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction,
|
||||||
|
const QString& directory, QDir::Filters filters )
|
||||||
|
: QskWindowOrSubWindow< W >( parent, title, actions, defaultAction )
|
||||||
|
, m_data( new PrivateData )
|
||||||
|
{
|
||||||
|
auto* outerBox = new QskLinearBox( Qt::Vertical );
|
||||||
|
outerBox->setMargins( 20 );
|
||||||
|
outerBox->setSpacing( 20 );
|
||||||
|
#if 1
|
||||||
|
outerBox->setFixedSize( 700, 500 );
|
||||||
|
#endif
|
||||||
|
setupHeader( outerBox );
|
||||||
|
setupFileSystemView( directory, filters, outerBox );
|
||||||
|
|
||||||
|
updateHeader( directory );
|
||||||
|
|
||||||
|
Inherited::setContentItem( outerBox );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskFileSelectionWindow< W >::~QskFileSelectionWindow() = default;
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QString QskFileSelectionWindow< W >::selectedPath() const
|
||||||
|
{
|
||||||
|
if( m_data->fileView->selectedRow() != -1 )
|
||||||
|
{
|
||||||
|
const auto path = m_data->fileView->valueAt( m_data->fileView->selectedRow(), 0 ).toString();
|
||||||
|
QFileInfo fi( m_data->fileView->rootPath(), path );
|
||||||
|
return fi.absoluteFilePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
void QskFileSelectionWindow< W >::setupHeader( QQuickItem* parentItem )
|
||||||
|
{
|
||||||
|
m_data->headerScrollArea = new QskScrollArea( parentItem );
|
||||||
|
m_data->headerScrollArea->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
|
||||||
|
m_data->headerScrollArea->setFlickableOrientations( Qt::Horizontal );
|
||||||
|
|
||||||
|
m_data->headerBox = new QskLinearBox( Qt::Horizontal, m_data->headerScrollArea );
|
||||||
|
m_data->headerScrollArea->setScrolledItem( m_data->headerBox );
|
||||||
|
}
|
||||||
|
|
||||||
|
static QStringList splitPath( const QString& path )
|
||||||
|
{
|
||||||
|
const auto cleanPath = QDir::cleanPath( path );
|
||||||
|
|
||||||
|
QDir dir( cleanPath );
|
||||||
|
|
||||||
|
QStringList result;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if( dir != QDir::root() )
|
||||||
|
{
|
||||||
|
result.prepend( dir.absolutePath() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while( dir.cdUp() );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
void QskFileSelectionWindow< W >::updateHeader( const QString& path )
|
||||||
|
{
|
||||||
|
const auto dirPaths = ::splitPath( path );
|
||||||
|
|
||||||
|
for( int i = 0; i < dirPaths.count(); ++i )
|
||||||
|
{
|
||||||
|
QskPushButton* b;
|
||||||
|
|
||||||
|
if( m_data->breadcrumbsButtons.count() <= i )
|
||||||
|
{
|
||||||
|
b = new QskPushButton( m_data->headerBox );
|
||||||
|
b->setStrutSizeHint( QskPushButton::Panel, { -1, -1 } );
|
||||||
|
m_data->breadcrumbsButtons.append( b );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b = m_data->breadcrumbsButtons.at( i );
|
||||||
|
b->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo fi( dirPaths.at( i ) );
|
||||||
|
b->setText( fi.baseName() );
|
||||||
|
|
||||||
|
QObject::connect( b, &QskPushButton::clicked, this, [this, fi]()
|
||||||
|
{
|
||||||
|
m_data->fileView->setRootPath( fi.filePath() );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = dirPaths.count(); i < m_data->breadcrumbsButtons.count(); i++ )
|
||||||
|
{
|
||||||
|
m_data->breadcrumbsButtons.at( i )->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data->breadcrumbsButtons.remove( dirPaths.count(), m_data->breadcrumbsButtons.count() - dirPaths.count() );
|
||||||
|
|
||||||
|
if( !m_data->breadcrumbsButtons.isEmpty() )
|
||||||
|
{
|
||||||
|
auto* b = m_data->breadcrumbsButtons.last();
|
||||||
|
|
||||||
|
// button might just have been created and not be layed out yet:
|
||||||
|
QObject::connect( b, &QskPushButton::widthChanged, this, [this, b]()
|
||||||
|
{
|
||||||
|
m_data->headerScrollArea->ensureItemVisible( b );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
void QskFileSelectionWindow< W >::setupFileSystemView( const QString& directory, QDir::Filters filters, QQuickItem* parentItem )
|
||||||
|
{
|
||||||
|
m_data->fileView = new FileSystemView( directory, filters, parentItem );
|
||||||
|
|
||||||
|
QObject::connect( m_data->fileView, &FileSystemView::rootPathChanged,
|
||||||
|
this, &QskFileSelectionWindow< W >::updateHeader );
|
||||||
|
|
||||||
|
QObject::connect( m_data->fileView, &QskListView::selectedRowChanged, this, [this]()
|
||||||
|
{
|
||||||
|
if( m_data->fileView->filter() & QDir::Files )
|
||||||
|
{
|
||||||
|
QFileInfo fi( selectedPath() );
|
||||||
|
W::defaultButton()->setEnabled( !fi.isDir() );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
template class QskFileSelectionWindow< QskDialogWindow >;
|
||||||
|
template class QskFileSelectionWindow< QskDialogSubWindow >;
|
||||||
|
|
||||||
|
#include "QskFileSelectionWindow.moc"
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_FILE_SELECTION_WINDODW_H
|
||||||
|
#define QSK_FILE_SELECTION_WINDODW_H
|
||||||
|
|
||||||
|
#include "QskWindowOrSubWindow.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskFileSelectionWindow : public QskWindowOrSubWindow< W >
|
||||||
|
{
|
||||||
|
using Inherited = QskWindowOrSubWindow< W >;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
QskFileSelectionWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction,
|
||||||
|
const QString& directory, QDir::Filters filters );
|
||||||
|
~QskFileSelectionWindow();
|
||||||
|
|
||||||
|
QString selectedPath() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupHeader( QQuickItem* parentItem );
|
||||||
|
|
||||||
|
static QStringList splitPath( const QString& path );
|
||||||
|
|
||||||
|
void updateHeader( const QString& path );
|
||||||
|
|
||||||
|
void setupFileSystemView( const QString& directory, QDir::Filters filters, QQuickItem* parentItem );
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData >m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskFontSelectionWindow.h"
|
||||||
|
|
||||||
|
#include "QskFontRole.h"
|
||||||
|
#include "QskGridBox.h"
|
||||||
|
#include "QskLinearBox.h"
|
||||||
|
#include "QskSimpleListBox.h"
|
||||||
|
#include "QskTextLabel.h"
|
||||||
|
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
QStringList families()
|
||||||
|
{
|
||||||
|
QFontDatabase db;
|
||||||
|
return db.families();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList styles( const QString& family )
|
||||||
|
{
|
||||||
|
QFontDatabase db;
|
||||||
|
return db.styles( family );
|
||||||
|
}
|
||||||
|
|
||||||
|
QList< int > pointSizes( const QString& family )
|
||||||
|
{
|
||||||
|
QFontDatabase db;
|
||||||
|
return db.pointSizes( family );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QStringList families()
|
||||||
|
{
|
||||||
|
return QFontDatabase::families();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList styles( const QString& family )
|
||||||
|
{
|
||||||
|
return QFontDatabase::styles( family );
|
||||||
|
}
|
||||||
|
|
||||||
|
QList< int > pointSizes( const QString& family )
|
||||||
|
{
|
||||||
|
return QFontDatabase::pointSizes( family );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskFontSelectionWindow< W >::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QFont selectedFont;
|
||||||
|
|
||||||
|
QskSimpleListBox* familyView;
|
||||||
|
QskSimpleListBox* styleView;
|
||||||
|
QskSimpleListBox* sizeView;
|
||||||
|
|
||||||
|
QskTextLabel* outputLabel;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskFontSelectionWindow< W >::QskFontSelectionWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction )
|
||||||
|
: Inherited( parent, title, actions, defaultAction )
|
||||||
|
, m_data( new PrivateData )
|
||||||
|
{
|
||||||
|
auto* outerBox = new QskLinearBox( Qt::Vertical );
|
||||||
|
outerBox->setMargins( 20 );
|
||||||
|
outerBox->setSpacing( 20 );
|
||||||
|
#if 1
|
||||||
|
outerBox->setFixedSize( 700, 500 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setupControls( outerBox );
|
||||||
|
connectSignals();
|
||||||
|
|
||||||
|
Inherited::setContentItem( outerBox );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskFontSelectionWindow< W >::~QskFontSelectionWindow() = default;
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QFont QskFontSelectionWindow< W >::selectedFont() const
|
||||||
|
{
|
||||||
|
return m_data->selectedFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
void QskFontSelectionWindow< W >::setupControls( QQuickItem* parentItem )
|
||||||
|
{
|
||||||
|
auto* gridBox = new QskGridBox( parentItem );
|
||||||
|
gridBox->setSpacing( 10 );
|
||||||
|
|
||||||
|
const QskFontRole role( QskFontRole::Subtitle, QskFontRole::Normal );
|
||||||
|
|
||||||
|
auto* familyLabel = new QskTextLabel( "Family", gridBox );
|
||||||
|
familyLabel->setFontRole( role );
|
||||||
|
gridBox->addItem( familyLabel, 0, 0 );
|
||||||
|
|
||||||
|
auto* styleLabel = new QskTextLabel( "Style", gridBox );
|
||||||
|
styleLabel->setFontRole( role );
|
||||||
|
gridBox->addItem( styleLabel, 0, 1 );
|
||||||
|
|
||||||
|
auto* sizeLabel = new QskTextLabel( "Size", gridBox );
|
||||||
|
sizeLabel->setFontRole( role );
|
||||||
|
gridBox->addItem( sizeLabel, 0, 2 );
|
||||||
|
|
||||||
|
m_data->familyView = new QskSimpleListBox( gridBox );
|
||||||
|
m_data->familyView->setSizePolicy( Qt::Vertical, QskSizePolicy::Expanding );
|
||||||
|
gridBox->addItem( m_data->familyView, 1, 0 );
|
||||||
|
|
||||||
|
m_data->styleView = new QskSimpleListBox( gridBox );
|
||||||
|
m_data->styleView->setSizePolicy( Qt::Vertical, QskSizePolicy::Expanding );
|
||||||
|
gridBox->addItem( m_data->styleView, 1, 1 );
|
||||||
|
|
||||||
|
m_data->sizeView = new QskSimpleListBox( gridBox );
|
||||||
|
m_data->sizeView->setSizePolicy( Qt::Vertical, QskSizePolicy::Expanding );
|
||||||
|
gridBox->addItem( m_data->sizeView, 1, 2 );
|
||||||
|
|
||||||
|
auto* sampleLabel = new QskTextLabel( "Sample", gridBox );
|
||||||
|
sampleLabel->setFontRole( role );
|
||||||
|
gridBox->addItem( sampleLabel, 2, 0 );
|
||||||
|
|
||||||
|
m_data->outputLabel = new QskTextLabel( gridBox );
|
||||||
|
m_data->outputLabel->setSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Minimum );
|
||||||
|
m_data->outputLabel->setElideMode( Qt::ElideRight );
|
||||||
|
gridBox->addItem( m_data->outputLabel, 3, 0, 1, 3 );
|
||||||
|
|
||||||
|
gridBox->setColumnStretchFactor( 0, 5 );
|
||||||
|
gridBox->setColumnStretchFactor( 1, 3 );
|
||||||
|
gridBox->setColumnStretchFactor( 2, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
void QskFontSelectionWindow< W >::connectSignals()
|
||||||
|
{
|
||||||
|
m_data->familyView->setEntries( families() );
|
||||||
|
|
||||||
|
QObject::connect( m_data->familyView, &QskSimpleListBox::selectedEntryChanged,
|
||||||
|
this, [this]( const QString& family )
|
||||||
|
{
|
||||||
|
m_data->styleView->setEntries( styles( family ) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
QObject::connect( m_data->familyView, &QskSimpleListBox::selectedEntryChanged,
|
||||||
|
this, [this]( const QString& family )
|
||||||
|
{
|
||||||
|
const auto sizes = pointSizes( family );
|
||||||
|
QStringList sizesString;
|
||||||
|
sizesString.reserve( sizes.count() );
|
||||||
|
|
||||||
|
for( const auto size : sizes )
|
||||||
|
{
|
||||||
|
sizesString.append( QString::number( size ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data->sizeView->setEntries( sizesString );
|
||||||
|
} );
|
||||||
|
|
||||||
|
auto displaySample = [this]()
|
||||||
|
{
|
||||||
|
const auto family = m_data->familyView->selectedEntry();
|
||||||
|
const auto style = m_data->styleView->selectedEntry();
|
||||||
|
const auto size = m_data->sizeView->selectedEntry();
|
||||||
|
|
||||||
|
if( !family.isNull() && !style.isNull() && !size.isNull() )
|
||||||
|
{
|
||||||
|
auto& f = m_data->selectedFont;
|
||||||
|
|
||||||
|
f = QFont( family, size.toInt() );
|
||||||
|
f.setStyleName( style );
|
||||||
|
|
||||||
|
m_data->outputLabel->setSkinHint( QskTextLabel::Text | QskAspect::FontRole, f );
|
||||||
|
m_data->outputLabel->resetImplicitSize();
|
||||||
|
m_data->outputLabel->setText( "The quick brown fox jumps over the lazy dog" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data->outputLabel->setText( {} );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect( m_data->familyView, &QskSimpleListBox::selectedEntryChanged, this, displaySample );
|
||||||
|
QObject::connect( m_data->styleView, &QskSimpleListBox::selectedEntryChanged, this, displaySample );
|
||||||
|
QObject::connect( m_data->sizeView, &QskSimpleListBox::selectedEntryChanged, this, displaySample );
|
||||||
|
}
|
||||||
|
|
||||||
|
template class QskFontSelectionWindow< QskDialogWindow >;
|
||||||
|
template class QskFontSelectionWindow< QskDialogSubWindow >;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_FONT_SELECTION_WINDODW_H
|
||||||
|
#define QSK_FONT_SELECTION_WINDODW_H
|
||||||
|
|
||||||
|
#include "QskWindowOrSubWindow.h"
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskFontSelectionWindow : public QskWindowOrSubWindow< W >
|
||||||
|
{
|
||||||
|
using Inherited = QskWindowOrSubWindow< W >;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
QskFontSelectionWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction );
|
||||||
|
~QskFontSelectionWindow();
|
||||||
|
|
||||||
|
QFont selectedFont() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupControls( QQuickItem* );
|
||||||
|
void connectSignals();
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskWindowOrSubWindow.h"
|
||||||
|
|
||||||
|
#include "QskDialogButtonBox.h"
|
||||||
|
#include "QskFocusIndicator.h"
|
||||||
|
|
||||||
|
// copied from QskDialog.cpp:
|
||||||
|
static QskDialog::Action qskActionCandidate( const QskDialogButtonBox* buttonBox )
|
||||||
|
{
|
||||||
|
// not the fastest code ever, but usually we always
|
||||||
|
// have a AcceptRole or YesRole button
|
||||||
|
|
||||||
|
const QskDialog::ActionRole candidates[] =
|
||||||
|
{
|
||||||
|
QskDialog::AcceptRole, QskDialog::YesRole,
|
||||||
|
QskDialog::RejectRole, QskDialog::NoRole, QskDialog::DestructiveRole,
|
||||||
|
QskDialog::UserRole, QskDialog::ResetRole,
|
||||||
|
QskDialog::ApplyRole, QskDialog::HelpRole
|
||||||
|
};
|
||||||
|
|
||||||
|
for ( auto role : candidates )
|
||||||
|
{
|
||||||
|
const auto& buttons = buttonBox->buttons( role );
|
||||||
|
if ( !buttons.isEmpty() )
|
||||||
|
return buttonBox->action( buttons.first() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return QskDialog::NoAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QskDialog::DialogCode qskExec( QskDialogWindow* dialogWindow )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
auto focusIndicator = new QskFocusIndicator();
|
||||||
|
focusIndicator->setObjectName( QStringLiteral( "DialogFocusIndicator" ) );
|
||||||
|
dialogWindow->addItem( focusIndicator );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return dialogWindow->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
QskWindowOrSubWindow< W >::QskWindowOrSubWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction )
|
||||||
|
: W( parent, title, actions, defaultAction )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QskWindowOrSubWindow< QskDialogWindow >::QskWindowOrSubWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction )
|
||||||
|
: QskDialogWindow( static_cast< QWindow* >( parent ) )
|
||||||
|
{
|
||||||
|
auto* transientParent = static_cast< QWindow* >( parent );
|
||||||
|
setTransientParent( transientParent );
|
||||||
|
|
||||||
|
setTitle( title );
|
||||||
|
setDialogActions( actions );
|
||||||
|
|
||||||
|
if ( actions != QskDialog::NoAction && defaultAction == QskDialog::NoAction )
|
||||||
|
defaultAction = qskActionCandidate( buttonBox() );
|
||||||
|
|
||||||
|
setDefaultDialogAction( defaultAction );
|
||||||
|
|
||||||
|
setModality( transientParent ? Qt::WindowModal : Qt::ApplicationModal );
|
||||||
|
|
||||||
|
const QSize size = sizeConstraint();
|
||||||
|
|
||||||
|
if ( this->parent() )
|
||||||
|
{
|
||||||
|
QRect r( QPoint(), size );
|
||||||
|
r.moveCenter( QRect( QPoint(), this->parent()->size() ).center() );
|
||||||
|
|
||||||
|
setGeometry( r );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto adjustSize = [this]()
|
||||||
|
{
|
||||||
|
const QSize size = sizeConstraint();
|
||||||
|
|
||||||
|
if ( size.isValid() )
|
||||||
|
{
|
||||||
|
setFlags( flags() | Qt::MSWindowsFixedSizeDialogHint );
|
||||||
|
setFixedSize( size );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
connect( contentItem(), &QQuickItem::widthChanged, this, adjustSize );
|
||||||
|
connect( contentItem(), &QQuickItem::heightChanged, this, adjustSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskDialog::DialogCode QskWindowOrSubWindow< QskDialogWindow >::exec()
|
||||||
|
{
|
||||||
|
return qskExec( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskWindowOrSubWindow< QskDialogWindow >::setContentItem( QQuickItem* item )
|
||||||
|
{
|
||||||
|
QskDialogWindow::setDialogContentItem( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskWindowOrSubWindow< QskDialogSubWindow >::QskWindowOrSubWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction )
|
||||||
|
: QskDialogSubWindow( static_cast< QQuickWindow* >( parent )->contentItem() )
|
||||||
|
{
|
||||||
|
setPopupFlag( QskPopup::DeleteOnClose );
|
||||||
|
setModal( true );
|
||||||
|
setTitle( title );
|
||||||
|
setDialogActions( actions );
|
||||||
|
|
||||||
|
if ( actions != QskDialog::NoAction && defaultAction == QskDialog::NoAction )
|
||||||
|
defaultAction = qskActionCandidate( buttonBox() );
|
||||||
|
|
||||||
|
setDefaultDialogAction( defaultAction );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskDialog::DialogCode QskWindowOrSubWindow< QskDialogSubWindow >::exec()
|
||||||
|
{
|
||||||
|
return QskDialogSubWindow::exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskWindowOrSubWindow< QskDialogSubWindow >::setContentItem( QQuickItem* item )
|
||||||
|
{
|
||||||
|
QskDialogSubWindow::setContentItem( item );
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_WINDOW_OR_SUBWINDOW_H
|
||||||
|
#define QSK_WINDOW_OR_SUBWINDOW_H
|
||||||
|
|
||||||
|
#include "QskDialogSubWindow.h"
|
||||||
|
#include "QskDialogWindow.h"
|
||||||
|
|
||||||
|
template< typename W >
|
||||||
|
class QskWindowOrSubWindow : public W
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskWindowOrSubWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction );
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class QskWindowOrSubWindow< QskDialogWindow > : public QskDialogWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskWindowOrSubWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction );
|
||||||
|
|
||||||
|
QskDialog::DialogCode exec();
|
||||||
|
|
||||||
|
void setContentItem( QQuickItem* item );
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class QskWindowOrSubWindow< QskDialogSubWindow > : public QskDialogSubWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskWindowOrSubWindow( QObject* parent, const QString& title,
|
||||||
|
QskDialog::Actions actions, QskDialog::Action defaultAction );
|
||||||
|
|
||||||
|
QskDialog::DialogCode exec();
|
||||||
|
|
||||||
|
void setContentItem( QQuickItem* item );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue