Add minimal Qt desktop pet window
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
|||||||
|
build/
|
||||||
|
cmake-build-*/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
*.autosave
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
*.obj
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Runtime/config files generated during development
|
||||||
|
config/
|
||||||
|
logs/
|
||||||
|
*.broken.json
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(QtDesktopPet VERSION 0.1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC OFF)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Widgets)
|
||||||
|
|
||||||
|
qt_add_executable(QtDesktopPet
|
||||||
|
main.cpp
|
||||||
|
src/ui/PetWindow.h
|
||||||
|
src/ui/PetWindow.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(QtDesktopPet
|
||||||
|
PRIVATE
|
||||||
|
PET_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(QtDesktopPet
|
||||||
|
PRIVATE
|
||||||
|
Qt6::Widgets
|
||||||
|
)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
target_compile_definitions(QtDesktopPet PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "src/ui/PetWindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
QApplication::setApplicationName("QtDesktopPet");
|
||||||
|
QApplication::setOrganizationName("QtDesktopPet");
|
||||||
|
|
||||||
|
PetWindow window;
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
#include "PetWindow.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QContextMenuEvent>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
QString previewImagePath()
|
||||||
|
{
|
||||||
|
return QStringLiteral(PET_SOURCE_DIR) + QStringLiteral("/shiroko/preview.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PetWindow::PetWindow(QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_imageLabel(new QLabel(this))
|
||||||
|
, m_dragging(false)
|
||||||
|
, m_alwaysOnTop(true)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
m_imageLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
m_imageLabel->setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
|
||||||
|
auto *layout = new QVBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->addWidget(m_imageLabel);
|
||||||
|
|
||||||
|
loadPreviewImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::contextMenuEvent(QContextMenuEvent *event)
|
||||||
|
{
|
||||||
|
QMenu menu(this);
|
||||||
|
|
||||||
|
QAction *topAction = menu.addAction(QStringLiteral("取消置顶"));
|
||||||
|
topAction->setCheckable(true);
|
||||||
|
topAction->setChecked(m_alwaysOnTop);
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
QAction *exitAction = menu.addAction(QStringLiteral("退出"));
|
||||||
|
|
||||||
|
QAction *selectedAction = menu.exec(event->globalPos());
|
||||||
|
if (selectedAction == topAction)
|
||||||
|
{
|
||||||
|
setAlwaysOnTop(!m_alwaysOnTop);
|
||||||
|
}
|
||||||
|
else if (selectedAction == exitAction)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::mouseMoveEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (m_dragging && (event->buttons() & Qt::LeftButton))
|
||||||
|
{
|
||||||
|
move(event->globalPosition().toPoint() - m_dragOffset);
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::mouseMoveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
m_dragging = true;
|
||||||
|
m_dragOffset = event->globalPosition().toPoint() - frameGeometry().topLeft();
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
m_dragging = false;
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::mouseReleaseEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::loadPreviewImage()
|
||||||
|
{
|
||||||
|
const QString imagePath = previewImagePath();
|
||||||
|
QPixmap pixmap(imagePath);
|
||||||
|
if (pixmap.isNull())
|
||||||
|
{
|
||||||
|
m_imageLabel->setText(QStringLiteral("QtDesktopPet"));
|
||||||
|
resize(240, 160);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QSize targetSize(320, 320);
|
||||||
|
const QPixmap scaled = pixmap.scaled(targetSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
m_imageLabel->setPixmap(scaled);
|
||||||
|
resize(scaled.size());
|
||||||
|
|
||||||
|
if (const QScreen *screen = QGuiApplication::primaryScreen())
|
||||||
|
{
|
||||||
|
const QRect available = screen->availableGeometry();
|
||||||
|
move(available.center() - rect().center());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::setAlwaysOnTop(bool enabled)
|
||||||
|
{
|
||||||
|
m_alwaysOnTop = enabled;
|
||||||
|
|
||||||
|
Qt::WindowFlags flags = windowFlags();
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
flags |= Qt::WindowStaysOnTopHint;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags &= ~Qt::WindowStaysOnTopHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowFlags(flags);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class PetWindow : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PetWindow(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadPreviewImage();
|
||||||
|
void setAlwaysOnTop(bool enabled);
|
||||||
|
|
||||||
|
QLabel *m_imageLabel;
|
||||||
|
QPoint m_dragOffset;
|
||||||
|
bool m_dragging;
|
||||||
|
bool m_alwaysOnTop;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user