This commit is contained in:
2026-05-14 13:30:06 +08:00
parent 974946cee4
commit e43171521d
91 changed files with 10485 additions and 3254 deletions
+561
View File
@@ -0,0 +1,561 @@
#include "app/AppStyle.h"
namespace gui {
QString appStyleSheet() {
return QStringLiteral(R"QSS(
QWidget {
font-size: 13px;
}
/* ===== 属性面板容器 ===== */
#PropertyDockContent {
background: #f8f9fb;
}
/* 属性面板标签:清晰可读 */
#PropertyDockContent QLabel {
font-size: 12px;
color: #374151;
font-weight: 500;
}
#PropertyDockContent #PropertyPanelHeading {
font-size: 13px;
font-weight: 700;
color: #111827;
padding: 4px 0 2px 0;
}
/* 属性面板单行编辑 */
#PropertyDockContent #PropertyPanelLineEdit {
font-size: 12px;
border-radius: 6px;
padding: 4px 8px;
min-height: 22px;
max-height: 26px;
background: #ffffff;
border: 1px solid #d1d5db;
selection-background-color: rgba(59, 130, 246, 0.20);
}
#PropertyDockContent #PropertyPanelLineEdit:hover {
border: 1px solid #9ca3af;
}
#PropertyDockContent #PropertyPanelLineEdit:focus {
border: 1px solid #3b82f6;
background: #ffffff;
}
/* 属性面板下拉框 */
#PropertyDockContent #PropertyPanelComboBox {
font-size: 12px;
border-radius: 6px;
padding: 4px 8px;
min-height: 22px;
max-height: 26px;
background: #ffffff;
border: 1px solid #d1d5db;
}
#PropertyDockContent #PropertyPanelComboBox:hover {
border: 1px solid #9ca3af;
}
#PropertyDockContent #PropertyPanelComboBox:focus {
border: 1px solid #3b82f6;
}
#PropertyDockContent #PropertyPanelComboBox::drop-down {
width: 18px;
border: 0;
}
#PropertyDockContent #PropertyPanelComboBox::down-arrow {
image: none;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid #6b7280;
width: 0;
height: 0;
}
/* 属性面板多行编辑 */
#PropertyDockContent #PropertyPanelTextEdit {
font-size: 12px;
border-radius: 6px;
padding: 6px 8px;
background: #ffffff;
border: 1px solid #d1d5db;
selection-background-color: rgba(59, 130, 246, 0.20);
}
#PropertyDockContent #PropertyPanelTextEdit:hover {
border: 1px solid #9ca3af;
}
#PropertyDockContent #PropertyPanelTextEdit:focus {
border: 1px solid #3b82f6;
}
/* 属性面板按钮 */
#PropertyDockContent #PropertyPanelPushButton {
font-size: 12px;
font-weight: 500;
border-radius: 6px;
padding: 3px 12px;
min-height: 24px;
max-height: 26px;
background: #ffffff;
border: 1px solid #d1d5db;
color: #374151;
}
#PropertyDockContent #PropertyPanelPushButton:hover {
background: #eef2ff;
border: 1px solid #93b4fc;
color: #1d4ed8;
}
#PropertyDockContent #PropertyPanelPushButton:pressed {
background: #dbeafe;
border: 1px solid #60a5fa;
}
/* 属性面板复选框 */
#PropertyDockContent #PropertyPanelCheckBox {
font-size: 12px;
spacing: 6px;
color: #374151;
}
#PropertyDockContent #PropertyPanelCheckBox::indicator {
width: 16px;
height: 16px;
border-radius: 4px;
border: 1.5px solid #9ca3af;
background: #ffffff;
}
#PropertyDockContent #PropertyPanelCheckBox::indicator:hover {
border: 1.5px solid #3b82f6;
}
#PropertyDockContent #PropertyPanelCheckBox::indicator:checked {
background: #3b82f6;
border: 1.5px solid #2563eb;
}
/* 属性面板列表 */
#PropertyDockContent #PropertyPanelListWidget {
font-size: 12px;
border-radius: 6px;
padding: 4px;
background: #ffffff;
border: 1px solid #d1d5db;
}
#PropertyDockContent #PropertyPanelListWidget::item {
padding: 4px 8px;
border-radius: 4px;
}
#PropertyDockContent #PropertyPanelListWidget::item:selected {
background: rgba(59, 130, 246, 0.12);
color: #111827;
}
/* 属性面板紧凑数值框 */
#PropertyDockContent #CompactNumericSpin {
font-size: 12px;
border-radius: 6px;
padding: 0px;
min-height: 22px;
max-height: 26px;
background: #ffffff;
border: 1px solid #d1d5db;
}
#PropertyDockContent #CompactNumericSpin:hover {
border: 1px solid #9ca3af;
}
#PropertyDockContent #CompactNumericSpin:focus {
border: 1px solid #3b82f6;
}
#PropertyDockContent #CompactNumericSpin QLineEdit {
padding: 0px 4px;
margin: 0px;
min-height: 20px;
border: none;
background: transparent;
}
#PropertyDockContent #CompactNumericSpin::up-button,
#PropertyDockContent #CompactNumericSpin::down-button {
width: 14px;
border-left: 1px solid #e5e7eb;
background: #f9fafb;
}
#PropertyDockContent #CompactNumericSpin::up-button:hover,
#PropertyDockContent #CompactNumericSpin::down-button:hover {
background: #eef2ff;
}
/* 属性面板滑块 */
#PropertyDockContent QSlider::groove:horizontal {
height: 4px;
border-radius: 2px;
background: #e5e7eb;
}
#PropertyDockContent QSlider::handle:horizontal {
width: 14px;
height: 14px;
margin: -5px 0;
border-radius: 7px;
background: #ffffff;
border: 1.5px solid #d1d5db;
}
#PropertyDockContent QSlider::handle:horizontal:hover {
border: 1.5px solid #3b82f6;
background: #eef2ff;
}
/* 属性面板分割线 */
#PropertySectionSeparator {
max-height: 1px;
min-height: 1px;
background: #e5e7eb;
}
/* 全局紧凑数值框(非属性面板内) */
#CompactNumericSpin {
font-size: 12px;
border-radius: 6px;
padding: 0px;
min-height: 22px;
border: 1px solid #d1d5db;
background: #ffffff;
}
#CompactNumericSpin QLineEdit {
padding: 0px 4px;
margin: 0px;
min-height: 20px;
border: none;
background: transparent;
}
#CompactNumericSpin::up-button,
#CompactNumericSpin::down-button {
width: 14px;
border-left: 1px solid #e5e7eb;
background: #f9fafb;
}
#CompactNumericSpin::up-button:hover,
#CompactNumericSpin::down-button:hover {
background: #eef2ff;
}
/* ===== 主窗口 ===== */
QMainWindow {
background: #f3f4f6;
}
/* ===== 欢迎页 ===== */
#WelcomePage {
background: #f3f4f6;
}
#WelcomeCard {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 16px;
}
#WelcomeTitle {
font-size: 24px;
font-weight: 800;
color: #111827;
}
#WelcomeSectionTitle {
font-size: 15px;
font-weight: 700;
color: #111827;
}
#WelcomeDesc, #WelcomeHint {
color: #6b7280;
}
#WelcomePrimaryButton {
background: #3b82f6;
border: 1px solid #3b82f6;
color: #ffffff;
border-radius: 10px;
font-weight: 600;
padding: 8px 24px;
}
#WelcomePrimaryButton:hover {
background: #2563eb;
border: 1px solid #2563eb;
}
/* ===== 项目树眼睛按钮 ===== */
#ProjectTreeEyeButton {
border: 1.5px solid transparent;
border-radius: 6px;
padding: 0px;
color: #6b7280;
background: transparent;
font-weight: 600;
}
#ProjectTreeEyeButton:hover {
background: rgba(59, 130, 246, 0.08);
color: #3b82f6;
border: 1.5px solid rgba(59, 130, 246, 0.20);
}
#ProjectTreeEyeButton:checked {
color: #3b82f6;
background: rgba(59, 130, 246, 0.06);
}
/* ===== 项目树 ===== */
#ProjectTreeDockContent {
background: #f8f9fb;
}
#ProjectTree {
background: transparent;
border: none;
outline: 0;
}
#ProjectTree::item {
padding: 5px 8px;
border-radius: 6px;
color: #374151;
}
#ProjectTree::item:hover {
background: rgba(59, 130, 246, 0.06);
}
#ProjectTree::item:selected {
background: rgba(59, 130, 246, 0.10);
color: #111827;
border: none;
}
#ProjectTree::branch {
border: none;
}
/* ===== 停靠窗口 ===== */
QDockWidget {
titlebar-close-icon: none;
titlebar-normal-icon: none;
}
QDockWidget::title {
background: #ffffff;
padding: 8px 14px;
font-size: 13px;
font-weight: 700;
color: #111827;
border-bottom: 1px solid #e5e7eb;
}
/* 通用标签 */
QLabel {
color: #111827;
}
/* ===== 分组框 ===== */
QGroupBox {
border: 1px solid #e5e7eb;
border-radius: 10px;
margin-top: 14px;
background: #ffffff;
padding: 12px 8px 8px 8px;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 12px;
padding: 0 8px;
color: #374151;
font-weight: 600;
font-size: 12px;
}
/* ===== 通用输入控件 ===== */
QLineEdit, QTextEdit, QPlainTextEdit, QComboBox {
background: #ffffff;
border: 1px solid #d1d5db;
border-radius: 8px;
padding: 6px 10px;
selection-background-color: rgba(59, 130, 246, 0.20);
}
QLineEdit:hover, QTextEdit:hover, QPlainTextEdit:hover, QComboBox:hover {
border: 1px solid #9ca3af;
}
QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus, QComboBox:focus {
border: 1.5px solid #3b82f6;
}
QSpinBox, QDoubleSpinBox {
background: #ffffff;
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 0px;
font-size: 12px;
selection-background-color: rgba(59, 130, 246, 0.20);
}
QSpinBox QLineEdit, QDoubleSpinBox QLineEdit {
padding: 0px 4px;
margin: 0px;
border: none;
background: transparent;
min-height: 20px;
}
QSpinBox:hover, QDoubleSpinBox:hover {
border: 1px solid #9ca3af;
}
QSpinBox:focus, QDoubleSpinBox:focus {
border: 1.5px solid #3b82f6;
}
QAbstractSpinBox::up-button, QAbstractSpinBox::down-button {
width: 16px;
border-left: 1px solid #e5e7eb;
background: #f9fafb;
}
QAbstractSpinBox::up-button:hover, QAbstractSpinBox::down-button:hover {
background: #eef2ff;
}
QComboBox::drop-down {
border: 0;
width: 26px;
}
QComboBox::down-arrow {
image: none;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 6px solid #6b7280;
width: 0;
height: 0;
}
QComboBox QAbstractItemView {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 4px;
selection-background-color: rgba(59, 130, 246, 0.10);
}
/* ===== 按钮 ===== */
QPushButton, QToolButton {
background: #ffffff;
border: 1px solid #d1d5db;
border-radius: 8px;
padding: 7px 12px;
color: #374151;
}
QPushButton:hover, QToolButton:hover {
background: #f9fafb;
border: 1px solid #9ca3af;
}
QPushButton:pressed, QToolButton:pressed {
background: #f3f4f6;
border: 1px solid #6b7280;
}
QToolButton:checked {
background: rgba(59, 130, 246, 0.10);
border: 1px solid rgba(59, 130, 246, 0.40);
color: #1d4ed8;
}
/* ===== 复选框 ===== */
QCheckBox {
spacing: 8px;
color: #374151;
}
QCheckBox::indicator {
width: 18px;
height: 18px;
border-radius: 5px;
border: 1.5px solid #9ca3af;
background: #ffffff;
}
QCheckBox::indicator:hover {
border: 1.5px solid #3b82f6;
}
QCheckBox::indicator:checked {
background: #3b82f6;
border: 1.5px solid #2563eb;
}
/* ===== 列表/树形视图 ===== */
QListWidget, QTreeView, QTableView {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 10px;
outline: 0;
}
QListWidget::item, QTreeView::item, QTableView::item {
padding: 6px 10px;
}
QListWidget::item:hover, QTreeView::item:hover, QTableView::item:hover {
background: rgba(59, 130, 246, 0.04);
}
QListWidget::item:selected, QTreeView::item:selected, QTableView::item:selected {
background: rgba(59, 130, 246, 0.12);
color: #111827;
}
/* ===== 菜单 ===== */
QMenu {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 6px;
}
QMenu::item {
padding: 8px 12px;
border-radius: 6px;
}
QMenu::item:selected {
background: rgba(59, 130, 246, 0.08);
}
QMenu::separator {
height: 1px;
background: #e5e7eb;
margin: 4px 6px;
}
/* ===== 滚动条 ===== */
QScrollBar:vertical {
background: transparent;
width: 10px;
margin: 4px 2px 4px 2px;
}
QScrollBar::handle:vertical {
background: #d1d5db;
border-radius: 5px;
min-height: 32px;
}
QScrollBar::handle:vertical:hover {
background: #9ca3af;
}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
height: 0px;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
background: transparent;
}
QScrollBar:horizontal {
background: transparent;
height: 10px;
margin: 2px 4px 2px 4px;
}
QScrollBar::handle:horizontal {
background: #d1d5db;
border-radius: 5px;
min-width: 32px;
}
QScrollBar::handle:horizontal:hover {
background: #9ca3af;
}
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
width: 0px;
}
QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
background: transparent;
}
/* ===== 工具提示 ===== */
QToolTip {
background: #111827;
color: #ffffff;
border: 0;
padding: 8px 10px;
border-radius: 8px;
font-size: 12px;
}
)QSS");
}
} // namespace gui
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <QString>
namespace gui {
// 全局 QSS:仅负责外观统一,不承载业务逻辑。
QString appStyleSheet();
} // namespace gui
+11 -5
View File
@@ -1,16 +1,22 @@
#include "main_window/MainWindow.h"
#include "app/AppStyle.h"
#include "core/image/ImageDecodeConfig.h"
#include "core/large_image/VipsBackend.h"
#include <QApplication>
#include <QImageReader>
#include <QStyleFactory>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
app.setApplicationName(QStringLiteral("landscape tool"));
app.setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
app.setStyleSheet(gui::appStyleSheet());
// 全局放宽 Qt 图片分配限制(默认常见为 256MB),否则超大分辨率背景/深度可能在任意加载路径被拒绝。
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QImageReader::setAllocationLimit(1024); // MB
#endif
core::image_decode::prepareLargeImageReader();
const char* av0 = (argc > 0 && argv[0]) ? argv[0] : "landscape_tool";
core::VipsBackend::init(av0);
qAddPostRoutine([]() { core::VipsBackend::shutdown(); });
MainWindow window;
window.show();