This commit is contained in:
zhuzichu 2023-12-13 16:20:09 +08:00
parent 863c88411b
commit ec2378a07a
30 changed files with 215 additions and 264 deletions

1
3rdparty/framelesshelper vendored Submodule

@ -0,0 +1 @@
Subproject commit 27fcd913b4b21b51d5cca307e47e93d1ae75e1bb

View File

@ -13,8 +13,8 @@ FluWindow {
id:window id:window
title: "FluentUI" title: "FluentUI"
width: 1000 width: 960
height: 640 height: 600
minimumWidth: 520 minimumWidth: 520
minimumHeight: 200 minimumHeight: 200
launchMode: FluWindowType.SingleTask launchMode: FluWindowType.SingleTask

View File

@ -16,8 +16,8 @@ FluWindow {
id:window id:window
title: "FluentUI" title: "FluentUI"
width: 1000 width: 960
height: 640 height: 600
minimumWidth: 520 minimumWidth: 520
minimumHeight: 200 minimumHeight: 200
launchMode: FluWindowType.SingleTask launchMode: FluWindowType.SingleTask

View File

@ -1,137 +1,6 @@
#include "FluFrameless.h" #include "FluFrameless.h"
#include "FluFrameless.h"
#include <QGuiApplication> #include <QGuiApplication>
#include <QScreen>
#ifdef Q_OS_WIN
#pragma comment(lib, "dwmapi.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "shcore.lib")
#pragma comment(lib, "Gdi32.lib")
#include <Windows.h>
#include <windowsx.h>
#include <winuser.h>
#include <dwmapi.h>
#include <codecvt>
#include <cmath>
static inline QByteArray qtNativeEventType()
{
static const auto result = "windows_generic_MSG";
return result;
}
#endif
FramelessEventFilter::FramelessEventFilter(QQuickWindow* window){
_window = window;
_current = window->winId();
}
bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result){
#ifdef Q_OS_WIN
if ((eventType != qtNativeEventType()) || !message || !result || !_window) {
return false;
}
const auto msg = static_cast<const MSG *>(message);
const HWND hWnd = msg->hwnd;
if (!hWnd) {
return false;
}
const qint64 wid = reinterpret_cast<qint64>(hWnd);
if(wid != _current){
return false;
}
const UINT uMsg = msg->message;
if (!msg || !msg->hwnd)
{
return false;
}
const LPARAM lParam = msg->lParam;
const int borderPadding = 8;
if (uMsg == WM_NCCALCSIZE) {
if (_window->visibility() == QWindow::FullScreen) {
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
sz->rgrc[0].left += borderPadding;
sz->rgrc[0].top += borderPadding;
sz->rgrc[0].right -= borderPadding;
sz->rgrc[0].bottom -= borderPadding;
*result = WVR_REDRAW;
return true;
}
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
if ( _window->visibility() == QWindow::Maximized) {
sz->rgrc[0].top += borderPadding;
} else {
sz->rgrc[0].top += 0;
}
sz->rgrc[0].right -= borderPadding;
sz->rgrc[0].bottom -= borderPadding;
sz->rgrc[0].left -= -borderPadding;
*result = WVR_REDRAW;
return true;
}else if (uMsg == WM_NCHITTEST){
const bool isResizable = !(_window->height()==_window->maximumHeight()&&_window->height()==_window->minimumHeight()&&_window->width()==_window->maximumWidth()&&_window->width()==_window->minimumWidth());
RECT winrect;
GetWindowRect(msg->hwnd, &winrect);
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(msg->lParam);
if (x >= winrect.left && x < winrect.left + borderPadding &&
y < winrect.bottom && y >= winrect.bottom - borderPadding && isResizable) {
*result = HTBOTTOMLEFT;
return true;
}
if (x < winrect.right && x >= winrect.right - borderPadding &&
y < winrect.bottom && y >= winrect.bottom - borderPadding && isResizable) {
*result = HTBOTTOMRIGHT;
return true;
}
if (x >= winrect.left && x < winrect.left + borderPadding &&
y >= winrect.top && y < winrect.top + borderPadding && isResizable) {
*result = HTTOPLEFT;
return true;
}
if (x < winrect.right && x >= winrect.right - borderPadding &&
y >= winrect.top && y < winrect.top + borderPadding && isResizable) {
*result = HTTOPRIGHT;
return true;
}
if (x >= winrect.left && x < winrect.left + borderPadding && isResizable) {
*result = HTLEFT;
return true;
}
if (x < winrect.right && x >= winrect.right - borderPadding && isResizable) {
*result = HTRIGHT;
return true;
}
if (y < winrect.bottom && y >= winrect.bottom - borderPadding && isResizable) {
*result = HTBOTTOM;
return true;
}
if (y >= winrect.top && y < winrect.top + borderPadding && isResizable) {
*result = HTTOP;
return true;
}
return false;
}else if(uMsg == WM_COMMAND){
SendMessage(msg->hwnd, WM_SYSCOMMAND, msg->wParam, msg->lParam);
*result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
return true;
}else if(uMsg == WM_WINDOWPOSCHANGING){
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(msg->lParam);
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0)
{
wp->flags |= SWP_NOCOPYBITS;
*result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
return true;
}
return false;
}
return false;
#endif
return false;
}
FluFrameless::FluFrameless(QObject *parent) FluFrameless::FluFrameless(QObject *parent)
: QObject{parent} : QObject{parent}
@ -141,18 +10,7 @@ FluFrameless::FluFrameless(QObject *parent)
void FluFrameless::classBegin(){ void FluFrameless::classBegin(){
} }
void FluFrameless::refresLayout(){ void FluFrameless::updateCursor(int edges){
#ifdef Q_OS_WIN
if(!_window.isNull()){
HWND hWnd = reinterpret_cast<HWND>(_window->winId());
RECT rect;
GetWindowRect(hWnd, &rect);
SetWindowPos(hWnd, nullptr, rect.left, rect.top, rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |SWP_FRAMECHANGED);
}
#endif
}
void FluFrameless::updateCursor(Qt::Edges edges){
switch (edges) { switch (edges) {
case 0: case 0:
_window->setCursor(Qt::ArrowCursor); _window->setCursor(Qt::ArrowCursor);
@ -177,20 +35,27 @@ void FluFrameless::updateCursor(Qt::Edges edges){
} }
bool FluFrameless::eventFilter(QObject *obj, QEvent *ev){ bool FluFrameless::eventFilter(QObject *obj, QEvent *ev){
if (_window->flags()& Qt::FramelessWindowHint) { if (!_window.isNull() && _window->flags()& Qt::FramelessWindowHint) {
static Qt::Edges edges = Qt::Edges(); static int edges = 0;
const int margin = 8; const int margin = 8;
switch (ev->type()) { switch (ev->type()) {
case QEvent::MouseButtonPress: case QEvent::MouseButtonPress:
updateCursor(edges); if(edges!=0){
_window->startSystemResize(edges); updateCursor(edges);
_window->startSystemResize(Qt::Edges(edges));
}
break; break;
case QEvent::MouseButtonRelease: case QEvent::MouseButtonRelease:
qDebug() << Q_FUNC_INFO << ev;
edges = Qt::Edges(); edges = Qt::Edges();
updateCursor(edges); updateCursor(edges);
break; break;
case QEvent::MouseMove: { case QEvent::MouseMove: {
if(_window->visibility() == QWindow::Maximized || _window->visibility() == QWindow::FullScreen){
break;
}
if(_window->width() == _window->maximumWidth() && _window->width() == _window->minimumWidth() && _window->height() == _window->maximumHeight() && _window->height() == _window->minimumHeight()){
break;
}
edges = Qt::Edges(); edges = Qt::Edges();
QMouseEvent *event = static_cast<QMouseEvent*>(ev); QMouseEvent *event = static_cast<QMouseEvent*>(ev);
QPoint p = QPoint p =
@ -227,37 +92,20 @@ void FluFrameless::componentComplete(){
_window = (QQuickWindow*)o; _window = (QQuickWindow*)o;
o = o->parent(); o = o->parent();
} }
#ifdef Q_OS_WIN
if(!_window.isNull()){
_nativeEvent =new FramelessEventFilter(_window);
qApp->installNativeEventFilter(_nativeEvent);
// MARGINS margins[2]{{0, 0, 0, 0}, {0, 0, 1, 0}};
// HWND hWnd = reinterpret_cast<HWND>(_window->winId());
// DwmExtendFrameIntoClientArea(hWnd, &margins[false]);
refresLayout();
connect(_window,&QWindow::visibilityChanged,this,[=](QWindow::Visibility visibility){ refresLayout(); });
}
#endif
#ifdef Q_OS_LINUX
if(!_window.isNull()){ if(!_window.isNull()){
_window->setFlag(Qt::FramelessWindowHint,true); _window->setFlag(Qt::FramelessWindowHint,true);
_window->update();
QGuiApplication::processEvents();
_window->installEventFilter(this); _window->installEventFilter(this);
} }
#endif
} }
FluFrameless::~FluFrameless(){ FluFrameless::~FluFrameless(){
#ifdef Q_OS_WIN
if (_nativeEvent) {
delete _nativeEvent;
_nativeEvent = nullptr;
refresLayout();
}
#endif
#ifdef Q_OS_LINUX
if (!_window.isNull()) { if (!_window.isNull()) {
_window->removeEventFilter(this);
_window->setFlag(Qt::FramelessWindowHint,false); _window->setFlag(Qt::FramelessWindowHint,false);
_window->update();
QGuiApplication::processEvents();
_window->removeEventFilter(this);
} }
#endif
} }

View File

@ -7,24 +7,6 @@
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#include "stdafx.h" #include "stdafx.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
using QT_NATIVE_EVENT_RESULT_TYPE = qintptr;
using QT_ENTER_EVENT_TYPE = QEnterEvent;
#else
using QT_NATIVE_EVENT_RESULT_TYPE = long;
using QT_ENTER_EVENT_TYPE = QEvent;
#endif
class FramelessEventFilter : public QAbstractNativeEventFilter
{
public:
FramelessEventFilter(QQuickWindow* window);
bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
public:
QQuickWindow* _window = nullptr;
qint64 _current = 0;
};
class FluFrameless : public QObject, public QQmlParserStatus class FluFrameless : public QObject, public QQmlParserStatus
{ {
Q_OBJECT Q_OBJECT
@ -34,14 +16,12 @@ public:
~FluFrameless(); ~FluFrameless();
void classBegin() override; void classBegin() override;
void componentComplete() override; void componentComplete() override;
Q_INVOKABLE void refresLayout();
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
private: private:
void updateCursor(Qt::Edges edges); void updateCursor(int edges);
private: private:
QPointer<QQuickWindow> _window = nullptr; QPointer<QQuickWindow> _window = nullptr;
FramelessEventFilter* _nativeEvent = nullptr;
}; };
#endif // FLUFRAMELESS_H #endif // FLUFRAMELESS_H

View File

@ -74,14 +74,16 @@ Rectangle{
property bool isRestore: win && Window.Maximized === win.visibility property bool isRestore: win && Window.Maximized === win.visibility
property bool resizable: win && !(win.height === win.maximumHeight && win.height === win.minimumHeight && win.width === win.maximumWidth && win.width === win.minimumWidth) property bool resizable: win && !(win.height === win.maximumHeight && win.height === win.minimumHeight && win.width === win.maximumWidth && win.width === win.minimumWidth)
} }
TapHandler { MouseArea{
onTapped: if (tapCount === 2 && d.resizable) btn_maximize.clicked() anchors.fill: parent
gesturePolicy: TapHandler.DragThreshold onPositionChanged: {
} d.win.startSystemMove()
DragHandler { }
target: null onDoubleClicked: {
grabPermissions: TapHandler.CanTakeOverFromAnything if(d.resizable){
onActiveChanged: if (active) { d.win.startSystemMove(); } btn_maximize.clicked()
}
}
} }
Row{ Row{
anchors{ anchors{
@ -105,6 +107,49 @@ Rectangle{
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Component{
id:com_mac_buttons
RowLayout{
FluImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_close_normal.png"
hoveredImage: "../Image/btn_close_hovered.png"
pushedImage: "../Image/btn_close_pushed.png"
visible: showClose
onClicked: closeClickListener()
}
FluImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_min_normal.png"
hoveredImage: "../Image/btn_min_hovered.png"
pushedImage: "../Image/btn_min_pushed.png"
onClicked: minClickListener()
visible: showMinimize
}
FluImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_max_normal.png"
hoveredImage: "../Image/btn_max_hovered.png"
pushedImage: "../Image/btn_max_pushed.png"
onClicked: maxClickListener()
visible: d.resizable && showMaximize
}
}
}
FluLoader{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 10
}
sourceComponent: isMac ? com_mac_buttons : undefined
}
RowLayout{ RowLayout{
anchors.right: parent.right anchors.right: parent.right
height: control.height height: control.height

View File

@ -0,0 +1,18 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Button{
id:control
property string normalImage: ""
property string hoveredImage: ""
property string pushedImage: ""
background: Item{
implicitHeight: 12
implicitWidth: 12
BorderImage {
anchors.fill: parent
source: control.hovered ? (control.pressed ? control.pushedImage : control.hoveredImage ) : control.normalImage
}
}
}

View File

@ -37,8 +37,9 @@ Window {
property bool showMinimize: true property bool showMinimize: true
property bool showMaximize: true property bool showMaximize: true
property bool showStayTop: true property bool showStayTop: true
flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
property bool autoMaximize: false property bool autoMaximize: false
property color resizeBorderColor: FluTheme.dark ? Qt.rgba(80/255,80/255,80/255,1) : Qt.rgba(210/255,210/255,210/255,1)
property int resizeBorderWidth: 1
property var closeListener: function(event){ property var closeListener: function(event){
if(closeDestory){ if(closeDestory){
destoryOnClose() destoryOnClose()
@ -126,18 +127,18 @@ Window {
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
height: {
if(FluApp.useSystemAppBar){
return 0
}
return window.fitsAppBarWindows ? 0 : window.appBar.height
}
sourceComponent: FluApp.useSystemAppBar ? undefined : com_app_bar sourceComponent: FluApp.useSystemAppBar ? undefined : com_app_bar
} }
Component{ Component{
id:com_app_bar id:com_app_bar
Item{ Item{
data: window.appBar data: window.appBar
height: {
if(FluApp.useSystemAppBar){
return 0
}
return window.fitsAppBarWindows ? 0 : childrenRect.height
}
} }
} }
Item{ Item{
@ -225,27 +226,19 @@ Window {
WindowLifecycle{ WindowLifecycle{
id:lifecycle id:lifecycle
} }
FluLoader{ Rectangle{
id:loader_window_border
anchors.fill: parent anchors.fill: parent
z:999 color:"transparent"
sourceComponent: FluApp.useSystemAppBar ? undefined : com_window_border border.width: window.resizeBorderWidth
} border.color: window.resizeBorderColor
Component{ visible: {
id:com_window_border if(FluApp.useSystemAppBar){
Item{ return false
Rectangle{
anchors.fill: parent
color: Qt.rgba(0,0,0,0)
border.width: 1
visible: FluTools.isLinux()
border.color: {
if(window.active){
return Qt.rgba(51/255,51/255,51/255,1)
}
return Qt.rgba(153/255,153/255,153/255,1)
}
} }
if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){
return false
}
return true
} }
} }
function destoryOnClose(){ function destoryOnClose(){

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -97,5 +97,15 @@
<file>FluentUI/Controls/FluClip.qml</file> <file>FluentUI/Controls/FluClip.qml</file>
<file>FluentUI/Controls/FluLoader.qml</file> <file>FluentUI/Controls/FluLoader.qml</file>
<file>FluentUI/Controls/FluShortcutPicker.qml</file> <file>FluentUI/Controls/FluShortcutPicker.qml</file>
<file>FluentUI/Image/btn_close_hovered.png</file>
<file>FluentUI/Image/btn_close_normal.png</file>
<file>FluentUI/Image/btn_close_pushed.png</file>
<file>FluentUI/Image/btn_max_hovered.png</file>
<file>FluentUI/Image/btn_max_normal.png</file>
<file>FluentUI/Image/btn_max_pushed.png</file>
<file>FluentUI/Image/btn_min_hovered.png</file>
<file>FluentUI/Image/btn_min_normal.png</file>
<file>FluentUI/Image/btn_min_pushed.png</file>
<file>FluentUI/Controls/FluImageButton.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -74,14 +74,16 @@ Rectangle{
property bool isRestore: win && Window.Maximized === win.visibility property bool isRestore: win && Window.Maximized === win.visibility
property bool resizable: win && !(win.height === win.maximumHeight && win.height === win.minimumHeight && win.width === win.maximumWidth && win.width === win.minimumWidth) property bool resizable: win && !(win.height === win.maximumHeight && win.height === win.minimumHeight && win.width === win.maximumWidth && win.width === win.minimumWidth)
} }
TapHandler { MouseArea{
onTapped: if (tapCount === 2 && d.resizable) btn_maximize.clicked() anchors.fill: parent
gesturePolicy: TapHandler.DragThreshold onPositionChanged: {
} d.win.startSystemMove()
DragHandler { }
target: null onDoubleClicked: {
grabPermissions: TapHandler.CanTakeOverFromAnything if(d.resizable){
onActiveChanged: if (active) { d.win.startSystemMove(); } btn_maximize.clicked()
}
}
} }
Row{ Row{
anchors{ anchors{
@ -105,6 +107,49 @@ Rectangle{
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Component{
id:com_mac_buttons
RowLayout{
FluImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_close_normal.png"
hoveredImage: "../Image/btn_close_hovered.png"
pushedImage: "../Image/btn_close_pushed.png"
visible: showClose
onClicked: closeClickListener()
}
FluImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_min_normal.png"
hoveredImage: "../Image/btn_min_hovered.png"
pushedImage: "../Image/btn_min_pushed.png"
onClicked: minClickListener()
visible: showMinimize
}
FluImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_max_normal.png"
hoveredImage: "../Image/btn_max_hovered.png"
pushedImage: "../Image/btn_max_pushed.png"
onClicked: maxClickListener()
visible: d.resizable && showMaximize
}
}
}
FluLoader{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 10
}
sourceComponent: isMac ? com_mac_buttons : undefined
}
RowLayout{ RowLayout{
anchors.right: parent.right anchors.right: parent.right
height: control.height height: control.height

View File

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Controls
import FluentUI
Button{
id:control
property string normalImage: ""
property string hoveredImage: ""
property string pushedImage: ""
background: Item{
implicitHeight: 12
implicitWidth: 12
BorderImage {
anchors.fill: parent
source: control.hovered ? (control.pressed ? control.pushedImage : control.hoveredImage ) : control.normalImage
}
}
}

View File

@ -36,8 +36,9 @@ Window {
property bool showMinimize: true property bool showMinimize: true
property bool showMaximize: true property bool showMaximize: true
property bool showStayTop: true property bool showStayTop: true
flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
property bool autoMaximize: false property bool autoMaximize: false
property color resizeBorderColor: FluTheme.dark ? Qt.rgba(80/255,80/255,80/255,1) : Qt.rgba(210/255,210/255,210/255,1)
property int resizeBorderWidth: 1
property var closeListener: function(event){ property var closeListener: function(event){
if(closeDestory){ if(closeDestory){
destoryOnClose() destoryOnClose()
@ -125,18 +126,18 @@ Window {
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
height: {
if(FluApp.useSystemAppBar){
return 0
}
return window.fitsAppBarWindows ? 0 : window.appBar.height
}
sourceComponent: FluApp.useSystemAppBar ? undefined : com_app_bar sourceComponent: FluApp.useSystemAppBar ? undefined : com_app_bar
} }
Component{ Component{
id:com_app_bar id:com_app_bar
Item{ Item{
data: window.appBar data: window.appBar
height: {
if(FluApp.useSystemAppBar){
return 0
}
return window.fitsAppBarWindows ? 0 : childrenRect.height
}
} }
} }
Item{ Item{
@ -224,27 +225,19 @@ Window {
WindowLifecycle{ WindowLifecycle{
id:lifecycle id:lifecycle
} }
FluLoader{ Rectangle{
id:loader_window_border
anchors.fill: parent anchors.fill: parent
z:999 color:"transparent"
sourceComponent: FluApp.useSystemAppBar ? undefined : com_window_border border.width: window.resizeBorderWidth
} border.color: window.resizeBorderColor
Component{ visible: {
id:com_window_border if(FluApp.useSystemAppBar){
Item{ return false
Rectangle{
anchors.fill: parent
color: Qt.rgba(0,0,0,0)
border.width: 1
visible: FluTools.isLinux()
border.color: {
if(window.active){
return Qt.rgba(51/255,51/255,51/255,1)
}
return Qt.rgba(153/255,153/255,153/255,1)
}
} }
if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){
return false
}
return true
} }
} }
function destoryOnClose(){ function destoryOnClose(){

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB