diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 43423d52..3ebae7ea 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -84,8 +84,7 @@ add_subdirectory( if (APPLE) set(ATLAS_APP_ICON - "${CMAKE_SOURCE_DIR}/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png" - CACHE FILEPATH "Atlas Engine macOS bundle icon" + CACHE FILEPATH "Atlas Engine macOS bundle icon" ) get_filename_component(ATLAS_APP_ICON_NAME "${ATLAS_APP_ICON}" NAME) set_source_files_properties("${ATLAS_APP_ICON}" PROPERTIES @@ -135,9 +134,14 @@ qt_add_resources(AtlasEditor "atlas_editor_assets" PREFIX "/editor" BASE "${CMAKE_SOURCE_DIR}/editor" FILES - "${CMAKE_SOURCE_DIR}/editor/assets/Icon-iOS-Default-1024x1024@1x.png" - "${CMAKE_SOURCE_DIR}/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png" - "${CMAKE_SOURCE_DIR}/editor/assets/atlas_ball_bright.png" + "${CMAKE_SOURCE_DIR}/editor/assets/atlas-app-dev.png" + "${CMAKE_SOURCE_DIR}/editor/assets/atlas-star.png" + "${CMAKE_SOURCE_DIR}/editor/assets/check.svg" + "${CMAKE_SOURCE_DIR}/editor/assets/close.svg" + "${CMAKE_SOURCE_DIR}/editor/assets/link.svg" + "${CMAKE_SOURCE_DIR}/editor/assets/chevron-down.svg" + "${CMAKE_SOURCE_DIR}/editor/assets/chevron-up.svg" + "${CMAKE_SOURCE_DIR}/editor/assets/atlas-app.png" "${CMAKE_SOURCE_DIR}/editor/assets/Manrope-VariableFont_wght.ttf" "${CMAKE_SOURCE_DIR}/editor/assets/Phosphor.ttf" "${CMAKE_SOURCE_DIR}/editor/assets/PHOSPHOR_LICENSE.txt" diff --git a/editor/assets/AtlasEngine.icon.json b/editor/assets/AtlasEngine.icon.json deleted file mode 100644 index b5ed7814..00000000 --- a/editor/assets/AtlasEngine.icon.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "fill": { - "automatic-gradient": "extended-srgb:0.00000,0.00000,0.00000,1.00000" - }, - "groups": [ - { - "layers": [ - { - "glass": true, - "image-name": "atlas_ball_bright.png", - "name": "atlas_ball_bright" - } - ], - "shadow": { - "kind": "neutral", - "opacity": 0.5 - }, - "translucency": { - "enabled": true, - "value": 0.5 - } - } - ], - "supported-platforms": { - "circles": [ - "watchOS" - ], - "squares": "shared" - } -} diff --git a/editor/assets/AtlasEngine.icon/Assets/atlasStarGradient.svg b/editor/assets/AtlasEngine.icon/Assets/atlasStarGradient.svg new file mode 100644 index 00000000..4b19137f --- /dev/null +++ b/editor/assets/AtlasEngine.icon/Assets/atlasStarGradient.svg @@ -0,0 +1,46 @@ + + diff --git a/editor/assets/AtlasEngine.icon/icon.json b/editor/assets/AtlasEngine.icon/icon.json new file mode 100644 index 00000000..93733db0 --- /dev/null +++ b/editor/assets/AtlasEngine.icon/icon.json @@ -0,0 +1,50 @@ +{ + "fill" : { + "linear-gradient" : [ + "srgb:1.00000,0.95276,0.98370,1.00000", + "srgb:0.69138,0.67074,0.76447,1.00000" + ], + "orientation" : { + "start" : { + "x" : 0.5, + "y" : 0 + }, + "stop" : { + "x" : 0.5, + "y" : 0.7 + } + } + }, + "groups" : [ + { + "layers" : [ + { + "fill" : "none", + "image-name" : "atlasStarGradient.svg", + "name" : "atlasStarGradient", + "position" : { + "scale" : 1.34, + "translation-in-points" : [ + 0, + 0 + ] + } + } + ], + "shadow" : { + "kind" : "neutral", + "opacity" : 0.5 + }, + "translucency" : { + "enabled" : true, + "value" : 0.3 + } + } + ], + "supported-platforms" : { + "circles" : [ + "watchOS" + ], + "squares" : "shared" + } +} \ No newline at end of file diff --git a/editor/assets/AtlasEngineDev.icon/Assets/atlasStar.svg b/editor/assets/AtlasEngineDev.icon/Assets/atlasStar.svg new file mode 100644 index 00000000..65a93fdf --- /dev/null +++ b/editor/assets/AtlasEngineDev.icon/Assets/atlasStar.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/editor/assets/AtlasEngineDev.icon.json b/editor/assets/AtlasEngineDev.icon/icon.json similarity index 62% rename from editor/assets/AtlasEngineDev.icon.json rename to editor/assets/AtlasEngineDev.icon/icon.json index a2c2a8c8..1aab94ac 100644 --- a/editor/assets/AtlasEngineDev.icon.json +++ b/editor/assets/AtlasEngineDev.icon/icon.json @@ -6,8 +6,16 @@ { "layers": [ { - "image-name": "atlas_ball_bright.png", - "name": "atlas_ball_bright" + "fill": "system-light", + "image-name": "atlasStar.svg", + "name": "atlasStar", + "position": { + "scale": 1.34, + "translation-in-points": [ + 0, + 0 + ] + } } ], "shadow": { diff --git a/editor/assets/Icon-iOS-Default-1024x1024@1x.png b/editor/assets/Icon-iOS-Default-1024x1024@1x.png deleted file mode 100644 index 8259c7c8..00000000 Binary files a/editor/assets/Icon-iOS-Default-1024x1024@1x.png and /dev/null differ diff --git a/editor/assets/atlas-app-dev.png b/editor/assets/atlas-app-dev.png new file mode 100644 index 00000000..bc4e561c Binary files /dev/null and b/editor/assets/atlas-app-dev.png differ diff --git a/editor/assets/atlas-app.icns b/editor/assets/atlas-app.icns new file mode 100644 index 00000000..d0a7ebab Binary files /dev/null and b/editor/assets/atlas-app.icns differ diff --git a/editor/assets/atlas-app.png b/editor/assets/atlas-app.png new file mode 100644 index 00000000..bda26463 Binary files /dev/null and b/editor/assets/atlas-app.png differ diff --git a/editor/assets/atlas-star.png b/editor/assets/atlas-star.png new file mode 100644 index 00000000..ff0d461a Binary files /dev/null and b/editor/assets/atlas-star.png differ diff --git a/editor/assets/atlasStar.svg b/editor/assets/atlasStar.svg new file mode 100644 index 00000000..65a93fdf --- /dev/null +++ b/editor/assets/atlasStar.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/editor/assets/atlasStarColored.svg b/editor/assets/atlasStarColored.svg new file mode 100644 index 00000000..65a93fdf --- /dev/null +++ b/editor/assets/atlasStarColored.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/editor/assets/atlasStarGradient.svg b/editor/assets/atlasStarGradient.svg new file mode 100644 index 00000000..4b19137f --- /dev/null +++ b/editor/assets/atlasStarGradient.svg @@ -0,0 +1,46 @@ + + diff --git a/editor/assets/atlas_ball_bright.png b/editor/assets/atlas_ball_bright.png deleted file mode 100644 index 18276831..00000000 Binary files a/editor/assets/atlas_ball_bright.png and /dev/null differ diff --git a/editor/assets/check.svg b/editor/assets/check.svg new file mode 100644 index 00000000..fc46d37e --- /dev/null +++ b/editor/assets/check.svg @@ -0,0 +1 @@ + diff --git a/editor/assets/chevron-down.svg b/editor/assets/chevron-down.svg new file mode 100644 index 00000000..131e5678 --- /dev/null +++ b/editor/assets/chevron-down.svg @@ -0,0 +1 @@ + diff --git a/editor/assets/chevron-up.svg b/editor/assets/chevron-up.svg new file mode 100644 index 00000000..1e2ffe9d --- /dev/null +++ b/editor/assets/chevron-up.svg @@ -0,0 +1 @@ + diff --git a/editor/assets/close.svg b/editor/assets/close.svg new file mode 100644 index 00000000..cadc964d --- /dev/null +++ b/editor/assets/close.svg @@ -0,0 +1 @@ + diff --git a/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png b/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png index fe0fe439..bda26463 100644 Binary files a/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png and b/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png differ diff --git a/editor/assets/iconFile-iOS-Default-1024x1024@1x.png b/editor/assets/iconFile-iOS-Default-1024x1024@1x.png deleted file mode 100644 index 90730d9b..00000000 Binary files a/editor/assets/iconFile-iOS-Default-1024x1024@1x.png and /dev/null differ diff --git a/editor/assets/landing.png b/editor/assets/landing.png deleted file mode 100644 index 48f4cf39..00000000 Binary files a/editor/assets/landing.png and /dev/null differ diff --git a/editor/assets/link.svg b/editor/assets/link.svg new file mode 100644 index 00000000..a1c931cf --- /dev/null +++ b/editor/assets/link.svg @@ -0,0 +1 @@ + diff --git a/editor/debug.cpp b/editor/debug.cpp index 40de2a8d..5d63dcca 100644 --- a/editor/debug.cpp +++ b/editor/debug.cpp @@ -8,6 +8,8 @@ */ #include +#include +#include #include #include #include @@ -98,18 +100,18 @@ QWidget* DebugComponentsView::createBasicControlsSection() { layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(8); - auto* normalButton = new QPushButton("Normal", container); - auto* defaultButton = new QPushButton("Default", container); + auto* normalButton = new styling::Button("Normal", container); + auto* defaultButton = new styling::Button("Default", container); defaultButton->setDefault(true); - auto* disabledButton = new QPushButton("Disabled", container); + auto* disabledButton = new styling::Button("Disabled", container); disabledButton->setEnabled(false); - auto* checkableButton = new QPushButton("Checkable", container); + auto* checkableButton = new styling::Button("Checkable", container); checkableButton->setCheckable(true); checkableButton->setChecked(true); - auto* toolButton = new QToolButton(container); + auto* toolButton = new styling::ToolButton(container); toolButton->setText("Tool"); layout->addWidget(normalButton); @@ -354,13 +356,13 @@ QWidget* DebugComponentsView::createCollapsibleSection() { layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(4); - auto* header = new QToolButton(section); + auto* header = new styling::ToolButton(section); header->setObjectName("collapsibleHeader"); header->setText("Transform"); header->setCheckable(true); header->setChecked(true); header->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - header->setArrowType(Qt::DownArrow); + header->setIcon(styling::icon(styling::Icon::CaretDown)); auto* body = new QWidget(section); body->setObjectName("collapsibleBody"); @@ -390,7 +392,7 @@ QWidget* DebugComponentsView::createCollapsibleSection() { form->addRow("Visibility", visible); QObject::connect(header, &QToolButton::toggled, section, [header, body, section](bool checked) { - header->setArrowType(checked ? Qt::DownArrow : Qt::RightArrow); + header->setIcon(styling::icon(checked ? styling::Icon::CaretDown : styling::Icon::CaretRight)); body->setVisible(checked); body->updateGeometry(); section->updateGeometry(); diff --git a/editor/main.cpp b/editor/main.cpp index abd90e0d..cb64c6d2 100644 --- a/editor/main.cpp +++ b/editor/main.cpp @@ -25,6 +25,7 @@ #include "editor/debug.h" #include "editor/application/toolchainInstaller.h" #include "editor/styling/icons.h" +#include "editor/styling/workbench.h" #include "editor/views/editorWindow.h" #include "editor/views/projectBrowser.h" #include "editor/views/splashScreen.h" @@ -51,10 +52,10 @@ int main(int argc, char **argv) { #ifndef Q_OS_MACOS #ifdef ATLAS_DEBUG_BUILD app.setWindowIcon( - QIcon(":/editor/assets/Icon-iOS-Default-1024x1024@1x.png")); + QIcon(":/editor/assets/atlas-app-dev.png")); #else app.setWindowIcon( - QIcon(":/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png")); + QIcon(":/editor/assets/atlas-app.png")); #endif #endif @@ -64,6 +65,7 @@ int main(int argc, char **argv) { app.setStyle("Fusion"); styling::applyTheme(app); + styling::installWorkbench(app); ToolchainInstaller::ensureInstalled(); auto *startupSplash = new SplashScreen(); diff --git a/editor/styling/dark.qss b/editor/styling/dark.qss index a7f9f02e..e2983148 100644 --- a/editor/styling/dark.qss +++ b/editor/styling/dark.qss @@ -1,153 +1,59 @@ * { font-family: "SF Pro Text", "Inter", "Segoe UI", "Arial"; - font-size: 11px; - color: #D6D6D6; - selection-background-color: #4772B3; - selection-color: #FFFFFF; + font-size: 13px; + color: #C5C5BE; + selection-background-color: #353532; + selection-color: #F1F1EC; } QWidget { - background-color: #1C1C1C; - color: #D6D6D6; + background: #191918; } QMainWindow, QDialog, -QFrame { - background-color: #1C1C1C; +#editorFrame, +#projectBrowserRoot { + background: #121211; } -QLabel { +QLabel, +QCheckBox, +QRadioButton, +QToolButton, +QPushButton { background: transparent; } QLabel:disabled { - color: #566174; -} - -QToolTip { - background-color: #303030; - color: #F7F9FC; - border: 1px solid #505050; - border-radius: 4px; - padding: 4px 6px; -} - -QGroupBox { - background-color: #242424; - border: 1px solid #3B3B3B; - border-radius: 4px; - margin-top: 13px; - padding: 7px; - color: #F1F4F8; - font-weight: 650; -} - -QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top left; - left: 9px; - padding: 0 6px; - color: #AEB8C8; - background-color: #242424; -} - -QScrollArea, -QAbstractScrollArea { - background-color: #202020; - border: none; -} - -QAbstractScrollArea::corner { - background-color: #202020; -} - -QScrollBar:vertical { - background-color: transparent; - width: 9px; - margin: 2px; - border: none; -} - -QScrollBar:horizontal { - background-color: transparent; - height: 9px; - margin: 2px; - border: none; -} - -QScrollBar::handle:vertical, -QScrollBar::handle:horizontal { - background-color: #4A4A4A; - border-radius: 4px; - min-height: 30px; - min-width: 30px; -} - -QScrollBar::handle:vertical:hover, -QScrollBar::handle:horizontal:hover { - background-color: #666666; + color: #62625D; } -QScrollBar::add-line, -QScrollBar::sub-line, -QScrollBar::add-page, -QScrollBar::sub-page { - background: none; - border: none; - width: 0; - height: 0; +QLabel[muted="true"] { + color: #92928B; } QPushButton, QToolButton { - background-color: #303030; - border: 1px solid #464646; - border-radius: 3px; - padding: 3px 8px; - color: #D8D8D8; - min-height: 22px; - font-weight: 500; + border: none; + border-radius: 7px; + padding: 5px 10px; + min-height: 24px; } QPushButton:hover, QToolButton:hover { - background-color: #3A3A3A; - border-color: #606060; -} - -QPushButton:pressed, -QToolButton:pressed { - background-color: #242424; - border-color: #4772B3; + background: #292928; } QPushButton:checked, QToolButton:checked { - background-color: #3B5F8A; - border-color: #5D8BC0; - color: #FFFFFF; -} - -QPushButton:default, -#primaryAction { - background-color: #4772B3; - border-color: #6791C9; - color: #FFFFFF; - font-weight: 650; -} - -QPushButton:default:hover, -#primaryAction:hover { - background-color: #5682C2; - border-color: #7AA1D4; + background: #30302E; } QPushButton:disabled, QToolButton:disabled { - background-color: #242424; - border-color: #333333; - color: #686868; + color: #646460; } QToolButton::menu-indicator { @@ -156,1015 +62,670 @@ QToolButton::menu-indicator { QLineEdit, QTextEdit, -QPlainTextEdit, +QPlainTextEdit { + background: #20201F; + border: 1px solid transparent; + border-radius: 6px; + padding: 7px 9px; + selection-background-color: #42423E; +} + +QLineEdit:hover, +QTextEdit:hover, +QPlainTextEdit:hover { + background: #242423; +} + +QLineEdit:focus, +QTextEdit:focus, +QPlainTextEdit:focus { + border-color: #53534D; +} + +QLineEdit:disabled, +QTextEdit:disabled, +QPlainTextEdit:disabled { + color: #666660; +} + QComboBox, QSpinBox, QDoubleSpinBox, QDateEdit, QTimeEdit, QDateTimeEdit { - background-color: #181818; - border: 1px solid #3D3D3D; - border-radius: 3px; - padding: 3px 7px; - color: #E2E2E2; - min-height: 22px; + background: #252524; + border: 1px solid transparent; + border-radius: 5px; + min-height: 24px; + padding: 3px 8px; + color: #D3D3CC; } -QLineEdit:hover, -QTextEdit:hover, -QPlainTextEdit:hover, QComboBox:hover, QSpinBox:hover, QDoubleSpinBox:hover { - border-color: #5A5A5A; + background: #2B2B29; } -QLineEdit:focus, -QTextEdit:focus, -QPlainTextEdit:focus, QComboBox:focus, QSpinBox:focus, QDoubleSpinBox:focus { - background-color: #222222; - border-color: #5D8BC0; + border-color: #666660; } -QLineEdit:disabled, -QTextEdit:disabled, QComboBox:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled { - background-color: #202020; - border-color: #303030; - color: #666666; + color: #666660; } QComboBox { - padding-right: 24px; + padding-right: 28px; } QComboBox::drop-down { - subcontrol-origin: padding; - subcontrol-position: top right; - width: 22px; - border-left: 1px solid #3B3B3B; + width: 26px; + border: none; } -QComboBox QAbstractItemView { - background-color: #292929; - border: 1px solid #4B4B4B; - border-radius: 4px; - padding: 3px; - selection-background-color: #3B5F8A; +QComboBox::down-arrow, +QAbstractSpinBox::down-arrow { + image: url(:/editor/assets/chevron-down.svg); + width: 12px; + height: 12px; +} + +QAbstractSpinBox::up-arrow { + image: url(:/editor/assets/chevron-up.svg); + width: 12px; + height: 12px; } QAbstractSpinBox::up-button, QAbstractSpinBox::down-button { - background-color: #292929; + background: transparent; border: none; - width: 16px; + width: 18px; } -QAbstractSpinBox::up-button:hover, -QAbstractSpinBox::down-button:hover { - background-color: #3E3E3E; +QComboBox QAbstractItemView { + background: #222221; + border: 1px solid #393936; + border-radius: 8px; + padding: 5px; } QCheckBox, QRadioButton { - spacing: 7px; - color: #C9D1DE; + spacing: 9px; } -QCheckBox::indicator, -QRadioButton::indicator { - width: 15px; - height: 15px; - background-color: #171717; - border: 1px solid #555555; - border-radius: 3px; +QCheckBox::indicator { + width: 16px; + height: 16px; + border: 1px solid #55554F; + border-radius: 4px; + background: #232322; } -QCheckBox::indicator:hover, -QRadioButton::indicator:hover { - border-color: #777777; +QCheckBox::indicator:hover { + border-color: #999991; +} + +QCheckBox::indicator:checked { + image: url(:/editor/assets/check.svg); + background: #74746C; + border-color: #999991; +} + +QCheckBox::indicator:indeterminate { + background: #999991; + border: 4px solid #44443F; +} + +QRadioButton::indicator { + width: 16px; + height: 16px; + background: #232322; + border: 1px solid #55554F; + border-radius: 9px; } -QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #4772B3; - border-color: #6D98CE; + width: 8px; + height: 8px; + background: #DDDDD5; + border: 5px solid #55554F; + border-radius: 9px; } QSlider::groove:horizontal { - background-color: #353535; - height: 4px; - border-radius: 2px; + height: 3px; + background: #343431; + border-radius: 1px; +} + +QSlider::sub-page:horizontal { + background: #93938A; + border-radius: 1px; } QSlider::handle:horizontal { - background-color: #5D8BC0; - border: 2px solid #A0B9D7; - width: 12px; - margin: -5px 0; - border-radius: 7px; + background: #D5D5CD; + border: none; + width: 10px; + margin: -4px 0; + border-radius: 5px; } QProgressBar { - background-color: #262626; - border: 1px solid #424242; + background: #292927; + border: none; border-radius: 3px; - height: 8px; + min-height: 6px; text-align: center; + color: #F1F1EC; } QProgressBar::chunk { - background-color: #4772B3; + background: #76766D; + border-radius: 3px; +} + +QScrollArea, +QAbstractScrollArea { + background: #191918; + border: none; +} + +QAbstractScrollArea::corner { + background: transparent; +} + +QScrollBar:vertical { + background: transparent; + border: none; + width: 8px; + margin: 3px 1px; +} + +QScrollBar:horizontal { + background: transparent; + border: none; + height: 8px; + margin: 1px 3px; +} + +QScrollBar::handle:vertical, +QScrollBar::handle:horizontal { + background: #3B3B36; border-radius: 3px; + min-height: 32px; + min-width: 32px; +} + +QScrollBar::handle:vertical:hover, +QScrollBar::handle:horizontal:hover { + background: #606059; +} + +QScrollBar::add-line, +QScrollBar::sub-line, +QScrollBar::add-page, +QScrollBar::sub-page { + border: none; + background: transparent; + width: 0; + height: 0; } QTreeView, QListView, -QListWidget, -QTableView, -QTableWidget { - background-color: #202020; - alternate-background-color: #242424; +QTableView { + background: #191918; border: none; - color: #DCE3EC; + outline: none; + alternate-background-color: #1D1D1C; show-decoration-selected: 1; } QTreeView::item, QListView::item, -QListWidget::item, -QTableView::item, -QTableWidget::item { - border: 1px solid transparent; - border-radius: 2px; - padding: 3px 5px; -} - -QTreeView::item:hover, -QListView::item:hover, -QListWidget::item:hover, -QTableView::item:hover, -QTableWidget::item:hover { - background-color: #303030; - border-color: #464646; +QTableView::item { + border: none; + padding: 5px 8px; } QTreeView::item:selected, QListView::item:selected, -QListWidget::item:selected, -QTableView::item:selected, -QTableWidget::item:selected { - background-color: #3B5F8A; - border-color: #5D8BC0; - color: #FFFFFF; +QTableView::item:selected { + background: #30302E; + color: #F1F1EC; } -QHeaderView { - background-color: #202020; +QHeaderView::section { + background: #191918; + border: none; + border-bottom: 1px solid #2B2B28; + color: #92928B; + padding: 9px; + font-weight: 400; } -QHeaderView::section { - background-color: #292929; +QGroupBox { + background: transparent; border: none; - border-right: 1px solid #404040; - border-bottom: 1px solid #404040; - padding: 5px 7px; - color: #98A4B7; - font-weight: 600; + border-top: 1px solid #2B2B28; + margin-top: 26px; + padding: 14px 2px 6px 2px; + font-weight: 500; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding: 0; + color: #DDDDD6; } QTabWidget::pane { - background-color: #202020; - border: 1px solid #3B3B3B; - border-radius: 0; + background: #191918; + border: none; +} + +QTabBar { + background: transparent; } QTabBar::tab { - background-color: #252525; + background: transparent; border: none; - border-right: 1px solid #393939; - border-bottom: 1px solid #3B3B3B; - color: #7F8B9D; - min-width: 88px; - padding: 5px 10px; - margin: 1px 0; - border-radius: 0; + color: #92928B; + padding: 9px 16px; + margin: 4px 3px; + border-radius: 6px; } -QTabBar::tab:hover { - background-color: #303030; - color: #C8D1DF; +QTabBar::tab:selected { + background: #2B2B29; + color: #EAEAE3; } -QTabBar::tab:selected { - background-color: #333333; - color: #F2F5F9; - border-bottom: 2px solid #5D8BC0; +QTabBar::tab:hover { + color: #EAEAE3; } -QMenuBar#atlasMenuBar { - background-color: #181818; - border-bottom: 1px solid #303030; - padding: 1px 6px; +QMenuBar { + background: #121211; + border: none; + padding: 3px 10px; } -QMenuBar#atlasMenuBar::item { +QMenuBar::item { background: transparent; - color: #B8C2D0; padding: 5px 9px; - border-radius: 3px; } -QMenuBar#atlasMenuBar::item:selected, -QMenuBar#atlasMenuBar::item:pressed { - background-color: #343434; - color: #FFFFFF; +QMenuBar::item:selected { + background: #2B2B29; + border-radius: 5px; } QMenu { - background-color: #292929; - border: 1px solid #515151; - border-radius: 4px; - padding: 4px; + background: #20201F; + border: 1px solid #393936; + border-radius: 8px; + padding: 6px; } QMenu::item { background: transparent; - border-radius: 2px; - padding: 6px 32px 6px 9px; - color: #DCE3EC; + padding: 9px 34px 9px 12px; + border-radius: 5px; } QMenu::item:selected { - background-color: #3B5F8A; - color: #FFFFFF; + background: #33332F; } QMenu::item:disabled { - color: #596477; + color: #64645E; } QMenu::separator { - background-color: #424242; + background: #343431; height: 1px; - margin: 5px 8px; + margin: 6px 10px; } -QSplitter::handle { - background-color: #111111; -} - -QSplitter::handle:horizontal { - width: 4px; +QToolTip { + background: #292927; + color: #E1E1DA; + border: 1px solid #44443E; + border-radius: 5px; + padding: 6px 9px; } -QSplitter::handle:vertical { - height: 4px; +QSplitter::handle { + background: #121211; } QSplitter::handle:hover { - background-color: #5D8BC0; + background: #41413C; } QStatusBar { - background-color: #181818; - border-top: 1px solid #303030; - color: #8490A4; + background: #121211; + color: #888882; + border: none; + padding: 3px 14px; + min-height: 24px; + font-size: 11px; +} + +QStatusBar::item { + border: none; } -#atlasStatusBar { - min-height: 23px; - padding: 0 6px; +#workspaceBar, +#workspaceChrome, +#workspaceIdentity, +#workspaceIdentityText, +#workspaceActivity, +#workspaceUtilities { + background: #121211; + border: none; } -#statusRuntimeIcon { +#workspaceBar { padding: 0; + spacing: 0; } -#statusRuntime { - background: transparent; - border-right: 1px solid #343434; +#workspaceProject { + color: #D7D7D0; + font-size: 13px; } -#statusRuntimeText { - color: #9BA79F; - font-size: 10px; +#workspaceSwitcher, +#workspaceSurface, +#workspaceHeading, +#editorWorkspaceStack { + background: #191918; + border: none; } -#statusRenderer { - background-color: #292929; - border: 1px solid #454545; - border-radius: 3px; - color: #B6BCB8; - font-size: 9px; - font-weight: 700; - padding: 2px 6px; +#workspaceHeading { + border-bottom: 1px solid #282825; } -#statusVersion { - color: #68758A; - font-size: 9px; - padding: 0 6px; +#workspaceSwitcher { + padding: 0; } -#workspaceBar { - background-color: #202020; +#workspaceMark { + background: transparent; border: none; - border-bottom: 1px solid #3B3B3B; - spacing: 4px; - padding: 3px 6px 3px 0; - min-height: 38px; } -#workspaceIdentity { +#workspaceContextPath, +#statusVersion, +#statusRenderer, +#statusRuntimeText, +#viewportFpsLabel, +#viewportShortcutHint { background: transparent; - border-right: 1px solid #424242; + color: #898982; + font-size: 11px; + border: none; } -#workspaceMark { - background-color: #292929; - border: 1px solid #3F3F3F; - border-radius: 4px; - padding: 3px; +#statusRuntime { + background: transparent; } -#workspaceIdentityText { - background: transparent; +#sceneTabs { + background: #191918; + border: none; } -#workspaceBrand { - color: #8C8C8C; - font-size: 8px; - font-weight: 750; +#sceneTabs::tab { + padding: 9px 14px; + min-width: 92px; } -#workspaceProject { - color: #EFEFEF; - font-size: 12px; - font-weight: 650; +#viewportTools { + background: #191918; } -#workspaceSwitcher { - background-color: #181818; - border: 1px solid #383838; - border-radius: 4px; - margin-left: 7px; +#viewportToolbar, +#panelToolbar, +#materialEditorHeader, +#postProcessingToolbar, +#workspaceToolbar { + background: #191918; + border: none; } -#workspaceModeButton { - background-color: #222222; - border: 1px solid transparent; - border-radius: 3px; - color: #A0A0A0; - padding: 3px 9px; - min-height: 22px; +#hierarchySearch, +#contentSearchField { + background: #222221; + padding: 6px 9px; } -#workspaceModeButton:hover { - background-color: #333333; - color: #E2E2E2; +#contentPathField { + background: transparent; + border: none; + color: #A7A7A0; } -#workspaceModeButton:checked { - background-color: #3B5F8A; - border-color: #5D8BC0; - color: #FFFFFF; +#inspectorScroll, +#inspectorContent, +#materialEditorBody, +#postProcessingBody, +#environmentPages, +#environmentWorkspace, +#environmentPage { + background: #191918; + border: none; } -#workspaceCommandButton, -#workspaceUtilityButton, -#workspaceBuildButton, -#workspaceLaunchButton { - min-width: 42px; - padding: 3px 9px; - margin-left: 2px; - min-height: 24px; -} - -#workspaceCommandButton, -#workspaceUtilityButton, -#workspaceBuildButton { - background-color: #292929; - border-color: #444444; -} - -#workspaceLaunchButton { - background-color: #3F684F; - border-color: #5A8B6B; - color: #FFFFFF; - font-weight: 650; -} - -#workspaceCommandButton:hover, -#workspaceUtilityButton:hover, -#workspaceBuildButton:hover, -#workspaceLaunchButton:hover { - background-color: #3A3A3A; - border-color: #606060; -} - -#workspaceLaunchButton:hover { - background-color: #4E7B5E; - border-color: #6B9B79; -} - -#workspaceContextBar { - background-color: #292929; - border: none; - border-bottom: 1px solid #3C3C3C; - spacing: 2px; - padding: 1px 5px 1px 0; - min-height: 27px; -} - -#workspaceBreadcrumb { - background: transparent; - border-right: 1px solid #414141; -} - -#workspaceContextIcon { +#inspectorHeader { background: transparent; -} - -#workspaceContextTitle { - color: #E0E0E0; - font-weight: 650; -} - -#workspaceContextPath { - color: #7F7F7F; -} - -#workspacePanelButton { - background-color: transparent; - border-color: transparent; - color: #8F8F8F; - padding: 2px 7px; - min-height: 20px; -} - -#workspacePanelButton:hover { - background-color: #363636; - color: #DADADA; -} - -#workspacePanelButton:checked { - background-color: #333333; - border-color: #4A4A4A; - color: #EAEAEA; -} - -#sceneTabs { - background-color: #181818; - border-bottom: 1px solid #3B3B3B; -} - -#sceneTabs::tab { - background-color: #242424; - border-right: 1px solid #3A3A3A; - color: #7F8B9D; - min-width: 112px; - padding: 5px 10px; - margin: 0; - border-radius: 0; -} - -#sceneTabs::tab:selected { - background-color: #333333; - color: #F3F6FA; - border-bottom: 2px solid #5D8BC0; -} - -#viewportTools { - background-color: #151515; -} - -#viewportToolbar { - background-color: #292929; - border-bottom: 1px solid #3B3B3B; -} - -#viewportPlaybackButton, -#viewportModeButton, -#viewportOptionButton, -#viewportShadingButton { - background-color: #292C2F; - border-color: #414549; - min-width: 25px; - min-height: 22px; - padding: 3px 5px; -} - -#viewportPlaybackButton:hover, -#viewportModeButton:hover, -#viewportOptionButton:hover, -#viewportShadingButton:hover { - background-color: #363A3E; - border-color: #5A5F65; -} - -#viewportModeButton:checked, -#viewportShadingButton:checked { - background-color: #3A4248; - border-color: #6F7B84; -} - -#viewportFpsLabel { - color: #9CA5A0; - font-size: 10px; - font-weight: 650; -} - -#viewportShortcutHint { - background-color: #141517; - border-top: 1px solid #303236; - color: #68758A; - font-size: 10px; - padding: 3px 7px; -} - -#panelToolbar, -#materialEditorHeader, -#postProcessingToolbar, -#workspaceToolbar { - background-color: #292929; - border-bottom: 1px solid #404040; - padding: 2px; -} - -#panelAddButton, -#materialSaveButton, -#workspaceApplyButton { - background-color: #333333; - border-color: #4C4C4C; - color: #D8DBDE; -} - -#panelMoreButton, -#browserNavigationButton, -#browserRevealButton { - background-color: transparent; - border-color: transparent; - min-width: 24px; -} - -#panelMoreButton:hover, -#browserNavigationButton:hover, -#browserRevealButton:hover { - background-color: #34373A; - border-color: #484C50; -} - -#contentPathField { - background-color: #1B1D1F; - color: #8490A4; - font-size: 11px; -} - -#contentSearchField { - min-width: 130px; -} - -QTreeView#hierarchyTree { - background-color: #202020; - border-top: 1px solid #303030; - padding: 3px 2px; -} - -QTreeView#hierarchyTree::item { - min-height: 22px; - padding: 1px 6px; -} - -QTreeView#hierarchyTree::item:hover { - background-color: #303030; - border-color: #444444; -} - -QTreeView#hierarchyTree::item:selected { - background-color: #3B5F8A; - border-color: #5D8BC0; - color: #FFFFFF; -} - -QListView#contentGrid { - background-color: #1C1C1C; - border-top: 1px solid #303030; - padding: 5px; -} - -QListView#contentGrid::item { - background-color: #252525; - border: 1px solid #363636; - border-radius: 4px; - padding: 6px; - color: #BCC6D4; -} - -QListView#contentGrid::item:hover { - background-color: #303030; - border-color: #505050; -} - -QListView#contentGrid::item:selected { - background-color: #3B5F8A; - border-color: #5D8BC0; - color: #FFFFFF; -} - -QScrollArea#inspectorScroll, -#inspectorContent, -#materialEditorBody, -#postProcessingBody { - background-color: #202020; border: none; -} - -#inspectorHeader { - background-color: #292929; - border: 1px solid #414141; - border-radius: 4px; - padding: 5px; + padding: 0; } #inspectorObjectIcon { - background-color: #343434; - border: 1px solid #4E4E4E; - border-radius: 4px; - padding: 4px; + background: transparent; + border: none; } #inspectorNameField { background: transparent; border: 1px solid transparent; - color: #F3F6FA; - font-size: 14px; - font-weight: 700; + color: #EAEAE3; + font-size: 18px; + font-weight: 500; + padding: 2px 0; } -#inspectorNameField:hover, #inspectorNameField:focus { - background-color: #202020; - border-color: #5A5A5A; + border-color: #55554F; } -#inspectorTypeLabel { - color: #7E8A9E; - font-size: 10px; - font-weight: 600; +#inspectorTypeLabel, +#inspectorPropertyLabel, +#materialTexturePath, +#materialEditorStatus, +#postProcessingStatus, +#workspaceStatus, +#workspaceAutoApply { + color: #93938C; + font-size: 12px; } #inspectorComponent { - background-color: #242424; - border: 1px solid #3D3D3D; - border-radius: 3px; - margin-top: 2px; -} - -#inspectorComponentHeaderRow { - background-color: #2D2D2D; - border-bottom: 1px solid #3B3B3B; - border-radius: 3px 3px 0 0; -} - -#inspectorComponentHeader { background: transparent; border: none; - color: #E8ECF2; - font-weight: 650; - text-align: left; - padding: 4px 7px; -} - -#inspectorComponentHeader:hover { - background-color: #383838; + border-top: 1px solid #2C2C29; + border-radius: 0; } -#inspectorComponentRemoveButton { +#inspectorComponentHeaderRow, +#inspectorComponentBody, +#inspectorPropertyRow, +#inspectorNestedGroup, +#inspectorAudioControls { background: transparent; border: none; - min-width: 22px; -} - -#inspectorComponentRemoveButton:hover { - background-color: #3A3031; - border: 1px solid #695556; -} - -#inspectorComponentBody { - background-color: #242424; - padding: 4px; -} - -#inspectorPropertyRow { - background: transparent; - min-height: 27px; -} - -#inspectorPropertyLabel { - color: #929EB0; - font-size: 11px; } #inspectorVectorField, -#inspectorColorField, -#inspectorNumericField { - background-color: #181818; - border: 1px solid #3D3D3D; - border-radius: 3px; +#inspectorNumericField, +#inspectorColorField { + background: #252524; + border: none; + border-radius: 5px; } #inspectorVectorField QDoubleSpinBox, #inspectorNumericField QDoubleSpinBox { background: transparent; border: none; + padding: 4px 2px; } #inspectorAxisX, #inspectorAxisY, #inspectorAxisZ { - border-radius: 2px; - color: #F1F1F1; - font-size: 9px; - font-weight: 750; - padding: 2px 5px; -} - -#inspectorAxisX { - background-color: #874747; -} - -#inspectorAxisY { - background-color: #477451; -} - -#inspectorAxisZ { - background-color: #435E86; -} - -#inspectorSyncButton, -#inspectorArrayButton { background: transparent; - border-color: transparent; - min-width: 22px; + font-size: 10px; + padding: 0 3px; } -#inspectorSyncButton[matched="true"] { - background-color: #343936; - border-color: #555F59; - color: #B6BEB9; -} +#inspectorAxisX { color: #CA9290; } +#inspectorAxisY { color: #9AB696; } +#inspectorAxisZ { color: #91A9C7; } #inspectorColorSwatch { - background-color: #292929; - border: 1px solid #4D4D4D; - border-radius: 3px; + border: 1px solid #45453F; + border-radius: 4px; padding: 2px; } #inspectorColorText { - color: #9CA8BA; - font-family: "Menlo"; - font-size: 10px; -} - -#inspectorNestedGroup { - background-color: #202020; - border: 1px solid #383838; - border-radius: 3px; - margin: 3px 0; - padding: 5px; + color: #B0B0A8; + font-family: "SF Mono", "Menlo", "Consolas"; + font-size: 11px; } #inspectorNestedTitle, -#inspectorArrayTitle { - color: #AEB8C8; - font-weight: 650; +#inspectorArrayTitle, +#materialTextureLabel { + color: #C9C9C1; + font-weight: 500; } #inspectorEmptyTitle, #materialEditorEmpty, #postProcessingEmpty { - color: #C4CDDA; - font-size: 14px; - font-weight: 650; -} - -#inspectorEmptyHint { - color: #728096; -} - -#inspectorOpenAssetButton, -#inspectorAddComponentButton { - background-color: #292929; - border: 1px dashed #5A5A5A; - color: #C7D0DD; - padding: 6px; -} - -#inspectorAddComponentButton:hover { - background-color: #363636; - border-color: #666666; - color: #FFFFFF; + color: #C7C7BF; + font-size: 15px; + font-weight: 400; } -#inspectorAudioControls { - background-color: #202020; - border-radius: 3px; +#inspectorEmptyHint, +#environmentPageSubtitle, +#dialogHeroSubtitle { + color: #92928B; } #materialEditorTitle, #postProcessingTitle, #postProcessingSectionTitle, -#inspectorCameraTitle, -#workspaceTitle { - color: #F3F6FA; +#workspaceTitle, +#inspectorCameraTitle { + color: #D9D9D2; font-size: 13px; - font-weight: 700; -} - -#materialEditorStatus, -#postProcessingStatus, -#workspaceStatus, -#workspaceAutoApply { - color: #7E8A9E; - font-size: 10px; + font-weight: 500; } #materialPreview { - background-color: #151515; - border: 1px solid #444444; - border-radius: 4px; -} - -#materialColorButton { - background-color: #292929; - border-color: #454545; - border-radius: 3px; - color: #C9CDD0; - text-align: left; - padding: 4px 8px; -} - -#materialColorButton:hover { - background-color: #34383B; - border-color: #5A5F65; + background: #151514; + border: none; + border-radius: 8px; } #materialTextureSlot { - background-color: #252525; - border: 1px solid #404040; - border-radius: 4px; - padding: 4px; + background: transparent; + border: none; + padding: 6px 0; } #materialTexturePreview { - background-color: #1A1A1A; - border: 1px solid #494949; - border-radius: 3px; - color: #9E897D; - font-weight: 750; -} - -#materialTextureLabel { - color: #D6DDE7; - font-weight: 650; -} - -#materialTexturePath { - color: #7D899C; -} - -#environmentPages, -#environmentWorkspace, -#environmentPage { - background-color: #202020; + background: #242423; border: none; + border-radius: 6px; } -QListWidget#environmentCategories { - background-color: #1B1B1B; - border-right: 1px solid #3B3B3B; - padding: 5px; -} - -QListWidget#environmentCategories::item { - padding: 6px 8px; - margin: 2px 0; -} - -QListWidget#environmentCategories::item:selected { - background-color: #3B5F8A; - border-left: 2px solid #5D8BC0; +#environmentCategories { + background: #191918; + border: none; + padding: 8px; } #environmentPageTitle { - color: #F3F6FA; - font-size: 17px; - font-weight: 750; -} - -#environmentPageSubtitle { - color: #778499; -} - -QGroupBox#environmentSection { - background-color: #242424; - border-color: #3B3B3B; -} - -ads--CDockContainerWidget { - background-color: #111111; -} - -ads--CDockContainerWidget > QSplitter { - background-color: #111111; + color: #E7E7E0; + font-size: 22px; + font-weight: 500; } +ads--CDockContainerWidget, +ads--CDockContainerWidget > QSplitter, ads--CDockContainerWidget ads--CDockSplitter::handle { - background-color: #111111; -} - -ads--CDockContainerWidget ads--CDockSplitter::handle:hover { - background-color: #5D8BC0; -} - -ads--CDockAreaWidget { - background-color: #202020; - border: 1px solid #343434; + background: #121211; } +ads--CDockAreaWidget, ads--CDockAreaWidget[focused="true"] { - border-color: #4A6382; -} - -ads--CDockAreaTitleBar { - background-color: #292929; - border-bottom: 1px solid #3B3B3B; - min-height: 25px; + background: #191918; + border: none; + border-radius: 9px; } +ads--CDockAreaTitleBar, ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { - background-color: #2D2D2D; + background: #191918; + border: none; + min-height: 40px; } #tabsContainerWidget { - background-color: transparent; -} - -ads--CTitleBarButton { background: transparent; - border: none; - border-radius: 2px; - min-width: 22px; - min-height: 22px; - padding: 2px; -} - -ads--CTitleBarButton:hover { - background-color: #404040; -} - -ads--CDockWidgetTab { - background-color: #292929; - border: none; - border-right: 1px solid #3A3A3A; - border-bottom: 1px solid #3B3B3B; - padding: 1px 5px; - margin: 1px 0; - border-radius: 0; -} - -ads--CDockWidgetTab:hover { - background-color: #333333; -} - -ads--CDockWidgetTab[activeTab="true"] { - background-color: #333333; - border-bottom: 2px solid #5D8BC0; } +ads--CDockWidgetTab, +ads--CDockWidgetTab[activeTab="true"], ads--CDockWidgetTab[focused="true"] { - background-color: #303030; + background: transparent; + border: none; + padding: 3px 10px; + margin: 3px; } ads--CDockWidgetTab #dockWidgetTabLabel { - color: #7F8B9D; - font-size: 11px; - padding: 4px 2px; + color: #A1A19A; + font-size: 13px; + padding: 4px 0; } -ads--CDockWidgetTab[activeTab="true"] #dockWidgetTabLabel, -ads--CDockWidgetTab[focused="true"] #dockWidgetTabLabel { - color: #F1F4F8; +ads--CDockWidgetTab[activeTab="true"] #dockWidgetTabLabel { + color: #DADAD3; } +ads--CTitleBarButton, #tabCloseButton, #dockAreaCloseButton, #detachGroupButton, @@ -1173,304 +734,337 @@ ads--CDockWidgetTab[focused="true"] #dockWidgetTabLabel { #tabsMenuButton { background: transparent; border: none; - min-width: 20px; - min-height: 20px; + padding: 4px; + min-width: 18px; + min-height: 18px; } -#tabCloseButton:hover, -#dockAreaCloseButton:hover, -#detachGroupButton:hover, -#dockAreaAutoHideButton:hover, -#dockAreaMinimizeButton:hover, -#tabsMenuButton:hover { - background-color: #424549; +ads--CTitleBarButton:hover, +#tabCloseButton:hover { + background: #2B2B29; + border-radius: 5px; } ads--CDockWidget { - background-color: #202020; + background: #191918; } ads--CAutoHideSideBar, #sideTabsContainerWidget { - background-color: #141517; + background: #121211; } ads--CAutoHideTab { - background-color: #202224; - border: 1px solid #404448; - color: #7F8B9D; - padding: 4px; - border-radius: 8px; + background: transparent; + border: none; + padding: 7px; } -ads--CAutoHideTab:hover, -ads--CAutoHideTab[activeTab="true"] { - background-color: #393F44; - border-color: #66737C; - color: #FFFFFF; +#projectSidebar { + background: #121211; + border: none; } -#projectBrowserRoot, #projectBrowserContent { - background-color: #18191B; -} - -#projectSidebar { - background-color: #151618; - border-right: 1px solid #303236; + background: #191918; + border: none; + border-radius: 10px; } #projectBrand { - color: #F5F7FA; + color: #E7E7E0; font-size: 16px; - font-weight: 750; -} - -#projectSidebarVersion { - color: #68758A; - font-size: 10px; - font-weight: 600; -} - -#projectNavSelected { - background-color: #34383C; - border: 1px solid #51575C; - border-left: 3px solid #79868F; - border-radius: 10px; - color: #DCE9FA; - padding: 6px 9px; - text-align: left; -} - -#projectNavSelected:disabled { - color: #DCE9FA; -} - -#projectBrowserTitle, -#dialogTitle { - color: #F4F6FA; - font-size: 24px; - font-weight: 750; + font-weight: 500; } +#projectSidebarVersion, +#projectSidebarCaption, +#projectPath, +#projectDate, #projectBrowserSubtitle, #dialogSubtitle, #emptyStateSubtitle, #templateDescription { - color: #7F8B9D; + color: #92928B; + font-size: 12px; } -#projectSearch { - background-color: #202224; - border: 1px solid #43474B; - border-radius: 11px; - padding: 7px 9px; - font-size: 13px; +#projectBrowserTitle, +#dialogTitle { + color: #EAEAE4; + font-size: 28px; + font-weight: 500; } -#projectSearch:focus { - border-color: #71808A; +#projectSearch { + background: #222221; + padding: 10px 12px; } #projectList { - background-color: transparent; + background: transparent; border: none; } -#projectList::item { +#projectRow { background: transparent; border: none; - padding: 0; + border-radius: 7px; } -#projectRow { - background-color: #242628; - border: 1px solid #3B3E41; - border-radius: 13px; +#projectRow:hover { + background: #242423; } -#projectRow:hover { - background-color: #2C2F32; - border-color: #565B61; +#projectRow[selected="true"] { + background: #30302E; } -#projectRow[available="false"] { - background-color: #202224; - border-color: #303235; +#projectName { + color: #DEDED7; + font-size: 14px; + font-weight: 400; } #projectIcon, #templateIcon { - background-color: #303337; - border: 1px solid #484C50; - border-radius: 10px; + background: transparent; + border: none; } -#projectName { - color: #EEF2F7; - font-size: 14px; - font-weight: 700; +#rendererBadge { + background: #262624; + border: none; + border-radius: 4px; + color: #ABABA2; + font-size: 10px; + padding: 4px 7px; } -#projectPath, -#projectDate { - color: #768398; - font-size: 10px; +#projectEmptyState { + background: transparent; + border: none; } -#rendererBadge { - background-color: #2C302E; - border: 1px solid #494F4B; +#emptyStateTitle { + color: #CFCFC7; + font-size: 20px; + font-weight: 400; +} + +QFrame[templateCard="true"] { + background: #20201F; + border: 1px solid transparent; border-radius: 8px; - color: #B4BBB6; - padding: 3px 7px; - font-size: 9px; - font-weight: 700; } -#projectMoreButton { - background: transparent; - border-color: transparent; +QFrame[templateCard="true"][selected="true"] { + background: #2A2A28; + border-color: #66665F; } -#projectMoreButton:hover { - background-color: #3E4246; - border-color: #51565B; +#templateOption, +#fieldLabel { + color: #BDBDB5; + font-weight: 400; } -#projectEmptyState { - background-color: #1E2022; - border: 1px dashed #484C51; - border-radius: 14px; +#dialogError { + color: #D69C95; + font-size: 12px; } -#emptyStateTitle { - color: #CDD5E1; - font-size: 16px; - font-weight: 700; +#dialogHero { + background: transparent; + border: none; + padding: 2px; +} + +#dialogHeroIcon { + background: transparent; + border: none; + padding: 4px; } -#createProjectDialog { - background-color: #1E2022; +#dialogHeroTitle { + color: #E3E3DB; + font-size: 22px; + font-weight: 500; } -QFrame[templateCard="true"] { - background-color: #242628; - border: 1px solid #42464A; - border-radius: 13px; +#exportSummary { + background: #1D1D1C; + border: none; + border-radius: 6px; + color: #9C9C94; + padding: 12px; } -QFrame[templateCard="true"]:hover { - background-color: #2B2E31; - border-color: #5A5F65; +#exportLog, +#runtimeErrors { + background: #161615; + border: none; + padding: 12px; + font-family: "SF Mono", "Menlo", "Consolas"; + font-size: 12px; + color: #C3BAB1; } -QFrame[templateCard="true"][selected="true"] { - background-color: #393F44; - border-color: #66737C; +#commandPaletteDialog, +#globalSearchDialog { + background: #191918; + border: 1px solid #373733; + border-radius: 10px; } -#templateOption { - color: #E7ECF3; - font-weight: 650; +#commandPaletteSearch, +#globalSearchField { + background: transparent; + border: none; + border-bottom: 1px solid #30302C; + border-radius: 0; + padding: 15px 12px; + font-size: 16px; } -#fieldLabel { - color: #AAB5C5; - font-size: 11px; - font-weight: 650; +#commandPaletteList, +#globalSearchResults { + background: transparent; + padding: 4px; } -#dialogError { - color: #FF7D8A; +#paletteHint, +#projectListHint { + background: transparent; + color: #7E7E77; font-size: 11px; + padding: 7px 12px; } -QPushButton[secondary="true"] { - background-color: #292C2F; - border-color: #494D52; +#splashCard { + background: #191918; + border: 1px solid #343430; + border-radius: 12px; } -QPushButton[secondary="true"]:hover { - background-color: #363A3E; - border-color: #5D6268; +#atlasSplash, +#splashIcon { + background: transparent; } -#projectSettingsDialog, -#exportDialog { - background-color: #18191B; +#splashTitle { + color: #ECECE6; + font-size: 36px; + font-weight: 500; } -#dialogHero { - background-color: #242628; - border: 1px solid #42464A; - border-radius: 13px; - padding: 6px; +#splashVersion, +#splashCompany, +#splashWarning { + color: #91918A; + font-size: 12px; } -#dialogHeroIcon { - background-color: #2B3034; - border: 1px solid #50575C; - border-radius: 10px; - padding: 6px; +#splashStatus { + color: #BFBFB7; + font-size: 12px; } -#dialogHeroTitle { - color: #F3F6FA; - font-size: 17px; - font-weight: 750; +#splashProgress { + background: #2C2C28; + border: none; + min-height: 0; + border-radius: 2px; } -#dialogHeroSubtitle, -#exportSummary { - color: #7F8B9D; +#splashProgress::chunk { + background: #BCBCB2; + border-radius: 2px; } -#exportSummary { - background-color: #232527; - border: 1px solid #3B3E42; - border-radius: 10px; - padding: 6px; +QPushButton:default { + background: #E5E5E1; + color: #191918; } -#exportLog { - background-color: #141517; - border-color: #404448; - color: #B7BDBC; - font-family: "Menlo"; - font-size: 10px; +#projectSectionLabel { + color: #82827B; + font-size: 12px; + padding: 3px 10px; } -#commandPaletteDialog, -#globalSearchDialog { - background-color: #202224; - border: 1px solid #5A5F65; - border-radius: 14px; +#searchPreviewPane { + background: #171716; + border: none; + border-left: 1px solid #30302C; } -#commandPaletteSearch, -#globalSearchField { - background-color: #1A1C1E; - border: 1px solid #505459; - border-radius: 11px; - padding: 7px 9px; - font-size: 14px; +#searchPreviewText { + background: transparent; + border: none; + padding: 0; + font-family: "SF Mono", "Menlo", "Consolas"; + font-size: 12px; + color: #B6B6AF; } -#commandPaletteSearch:focus, -#globalSearchField:focus { - border-color: #71808A; +#projectRow[available="false"] #projectName { + color: #82827B; } -#commandPaletteList, -#globalSearchResults { - background-color: #202224; +QAbstractSpinBox QLineEdit { + background: transparent; + border: none; + padding: 0; + min-height: 0; +} + +#inspectorVectorField { + background: transparent; border: none; +} + +#inspectorAxisField { + background: #252524; + border: 1px solid transparent; + border-radius: 6px; +} + +#inspectorAxisField:hover { + background: #2C2C29; + border-color: #44443F; +} + +#inspectorAxisField QDoubleSpinBox { + background: transparent; + border: none; + padding: 5px 2px; + min-height: 24px; +} + +#inspectorNumberField, +#inspectorNameField, +#inspectorColorText { + min-height: 26px; +} + +#inspectorAxisX, +#inspectorAxisY, +#inspectorAxisZ { + padding: 0; + font-size: 11px; +} + +QTabBar::close-button { + image: url(:/editor/assets/close.svg); + width: 14px; + height: 14px; padding: 5px; + border-radius: 5px; } -#commandPaletteList::item, -#globalSearchResults::item { - min-height: 30px; - padding: 6px 8px; +QTabBar::close-button:hover, +#tabCloseButton:hover, +#dockAreaCloseButton:hover { + background: #343431; } diff --git a/editor/styling/icons.cpp b/editor/styling/icons.cpp index 7eaadb58..0070f1a5 100644 --- a/editor/styling/icons.cpp +++ b/editor/styling/icons.cpp @@ -166,7 +166,8 @@ ushort codepoint(styling::Icon icon) { } QPixmap renderIcon(styling::Icon icon, const QColor &color, int size) { - QPixmap pixmap(size, size); + QPixmap pixmap(size * 2, size * 2); + pixmap.setDevicePixelRatio(2.0); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); @@ -176,7 +177,7 @@ QPixmap renderIcon(styling::Icon icon, const QColor &color, int size) { font.setPixelSize(qRound(size * 0.82)); font.setStyleStrategy(QFont::PreferAntialias); painter.setFont(font); - painter.drawText(pixmap.rect(), Qt::AlignCenter, + painter.drawText(QRect(0, 0, size, size), Qt::AlignCenter, QString(QChar(codepoint(icon)))); return pixmap; } @@ -196,11 +197,13 @@ bool styling::loadIconFont() { } QIcon styling::icon(Icon icon, const QColor &color) { + if (icon == Icon::Close) + return QIcon(":/editor/assets/close.svg"); loadIconFont(); if (iconFamily.isEmpty()) return {}; QIcon result; - const QColor disabled("#566174"); + const QColor disabled("#74746D"); const QColor active = color.lighter(118); for (const int size : {16, 20, 24, 32, 48}) { result.addPixmap(renderIcon(icon, color, size), QIcon::Normal, @@ -240,3 +243,10 @@ QIcon styling::colorSwatch(const QColor &color, const QSize &size) { painter.drawRoundedRect(bounds, 4.0, 4.0); return QIcon(pixmap); } + +QPixmap styling::brandMark(const QSize &size) { + QPixmap mark(":/editor/assets/atlas-star.png"); + mark = mark.scaled(size * 2, Qt::KeepAspectRatio, Qt::SmoothTransformation); + mark.setDevicePixelRatio(2.0); + return mark; +} diff --git a/editor/styling/theme.cpp b/editor/styling/theme.cpp index 13440703..5b37241c 100644 --- a/editor/styling/theme.cpp +++ b/editor/styling/theme.cpp @@ -16,12 +16,12 @@ void styling::applyColorPalette(QApplication& app) { QPalette p; - const QColor bg = QColor("#18191B"); - const QColor panel = QColor("#25272A"); - const QColor panel2 = QColor("#1E2022"); - const QColor text = QColor("#E7ECF3"); - const QColor mutedText = QColor("#8D9094"); - const QColor accent = QColor("#71808A"); + const QColor bg = QColor("#121211"); + const QColor panel = QColor("#20201F"); + const QColor panel2 = QColor("#191918"); + const QColor text = QColor("#D5D5CE"); + const QColor mutedText = QColor("#92928B"); + const QColor accent = QColor("#30302E"); p.setColor(QPalette::Window, bg); p.setColor(QPalette::WindowText, text); @@ -30,24 +30,24 @@ void styling::applyColorPalette(QApplication& app) { p.setColor(QPalette::ToolTipBase, panel2); p.setColor(QPalette::ToolTipText, text); p.setColor(QPalette::Text, text); - p.setColor(QPalette::Button, QColor("#2B2E31")); + p.setColor(QPalette::Button, QColor("#252524")); p.setColor(QPalette::ButtonText, text); p.setColor(QPalette::BrightText, QColor("#FFFFFF")); - p.setColor(QPalette::Light, QColor("#505357")); - p.setColor(QPalette::Midlight, QColor("#424549")); - p.setColor(QPalette::Mid, QColor("#34373A")); - p.setColor(QPalette::Dark, QColor("#141517")); + p.setColor(QPalette::Light, QColor("#50504A")); + p.setColor(QPalette::Midlight, QColor("#42423C")); + p.setColor(QPalette::Mid, QColor("#33332F")); + p.setColor(QPalette::Dark, QColor("#121211")); p.setColor(QPalette::Shadow, QColor("#0D0E0F")); p.setColor(QPalette::Highlight, accent); p.setColor(QPalette::HighlightedText, QColor("#FFFFFF")); p.setColor(QPalette::PlaceholderText, mutedText); - p.setColor(QPalette::Disabled, QPalette::WindowText, QColor("#566174")); - p.setColor(QPalette::Disabled, QPalette::Text, QColor("#566174")); - p.setColor(QPalette::Disabled, QPalette::ButtonText, QColor("#566174")); - p.setColor(QPalette::Disabled, QPalette::Button, QColor("#232527")); - p.setColor(QPalette::Disabled, QPalette::Base, QColor("#202224")); - p.setColor(QPalette::Disabled, QPalette::Highlight, QColor("#3A4146")); + p.setColor(QPalette::Disabled, QPalette::WindowText, QColor("#64645E")); + p.setColor(QPalette::Disabled, QPalette::Text, QColor("#64645E")); + p.setColor(QPalette::Disabled, QPalette::ButtonText, QColor("#64645E")); + p.setColor(QPalette::Disabled, QPalette::Button, QColor("#20201F")); + p.setColor(QPalette::Disabled, QPalette::Base, QColor("#191918")); + p.setColor(QPalette::Disabled, QPalette::Highlight, QColor("#30302E")); app.setPalette(p); } diff --git a/editor/styling/workbench.cpp b/editor/styling/workbench.cpp new file mode 100644 index 00000000..2fa2e4e4 --- /dev/null +++ b/editor/styling/workbench.cpp @@ -0,0 +1,325 @@ +#include "editor/styling/workbench.h" +#include "editor/styling/icons.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +bool prominent(const QAbstractButton *button) { + return button->objectName() == "primaryAction" || + button->objectName() == "workspaceLaunchButton" || + (qobject_cast(button) != nullptr && + qobject_cast(button)->isDefault()); +} + +void paintButton(QAbstractButton *button, bool showText, bool vertical, + bool hasMenu, bool isTool) { + QPainter painter(button); + painter.setRenderHint(QPainter::Antialiasing); + const bool enabled = button->isEnabled(); + const bool hover = enabled && button->underMouse(); + const bool header = button->objectName() == "inspectorComponentHeader"; + const bool selected = (button->isChecked() && !header) || + button->property("matched").toBool(); + const bool primary = prominent(button); + const QRectF bounds = QRectF(button->rect()).adjusted(0.5, 0.5, -0.5, -0.5); + QColor background(Qt::transparent); + if (primary) + background = !enabled ? QColor("#282827") + : button->isDown() ? QColor("#C6C6BF") + : hover ? QColor("#F4F4EE") : QColor("#E5E5E1"); + else if (button->isDown()) + background = QColor("#333331"); + else if (selected) + background = QColor("#30302E"); + else if (hover) + background = QColor("#292928"); + else if (!isTool && !header) + background = QColor("#242423"); + painter.setPen(Qt::NoPen); + painter.setBrush(background); + painter.drawRoundedRect(bounds, 7, 7); + if (button->hasFocus() && enabled) { + painter.setBrush(Qt::NoBrush); + painter.setPen(QPen(QColor("#777771"), 1)); + painter.drawRoundedRect(bounds.adjusted(1, 1, -1, -1), 6, 6); + } + const QColor foreground = !enabled ? QColor("#646460") + : primary ? QColor("#191918") + : selected || hover || header ? QColor("#ECECE7") + : QColor("#B6B6AF"); + QRect content = button->rect().adjusted(10, 0, -10, 0); + const bool preserveIconColor = button->property("preserveIconColor").toBool() || + button->objectName() == "materialColorButton" || + button->objectName() == "inspectorColorSwatch"; + const int iconSize = preserveIconColor ? button->iconSize().width() : 18; + const int iconHeight = preserveIconColor ? button->iconSize().height() : 18; + const bool hasIcon = !button->icon().isNull(); + if (hasMenu) + content.adjust(0, 0, -13, 0); + if (hasIcon) { + QRect iconRect; + if (!showText) + iconRect = QRect((button->width() - iconSize) / 2, + (button->height() - iconHeight) / 2, iconSize, iconHeight); + else if (vertical) + iconRect = QRect((button->width() - iconSize) / 2, 8, iconSize, iconHeight); + else + iconRect = QRect(content.left(), (button->height() - iconHeight) / 2, + iconSize, iconHeight); + QPixmap glyph = button->icon().pixmap(QSize(iconSize, iconHeight), + button->devicePixelRatioF()); + if (!preserveIconColor) { + QPainter tint(&glyph); + tint.setCompositionMode(QPainter::CompositionMode_SourceIn); + tint.fillRect(glyph.rect(), foreground); + } + painter.drawPixmap(iconRect, glyph); + if (showText && !vertical) + content.adjust(iconSize + 7, 0, 0, 0); + } + if (showText) { + QFont font = button->font(); + font.setPixelSize(13); + font.setWeight(primary || selected || header ? QFont::Medium : QFont::Normal); + painter.setFont(font); + painter.setPen(foreground); + if (vertical) + content.setTop(28); + const Qt::Alignment alignment = hasIcon && !vertical + ? Qt::AlignLeft | Qt::AlignVCenter + : Qt::AlignCenter; + painter.drawText(content, alignment, + painter.fontMetrics().elidedText(button->text().remove('&'), + Qt::ElideRight, content.width())); + } + if (hasMenu) { + painter.setPen(QPen(foreground, 1.3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + const QPointF center(button->width() - 12, button->height() / 2.0); + QPainterPath path; + path.moveTo(center + QPointF(-3, -1.5)); + path.lineTo(center + QPointF(0, 1.5)); + path.lineTo(center + QPointF(3, -1.5)); + painter.drawPath(path); + } +} + +class WorkbenchInstaller : public QObject { +public: + using QObject::QObject; +protected: + bool eventFilter(QObject *object, QEvent *event) override { + if (event->type() == QEvent::Polish) { + if (auto *button = qobject_cast(object)) { + if (button->accessibleName().isEmpty() && button->text().isEmpty()) + button->setAccessibleName(button->toolTip()); + } + if (auto *spin = qobject_cast(object)) + spin->setButtonSymbols(QAbstractSpinBox::NoButtons); + auto *view = qobject_cast(object); + if (view != nullptr && !view->property("workbenchStyled").toBool() && + !view->inherits("QTableView")) { + view->setProperty("workbenchStyled", true); + view->setItemDelegate(new styling::ItemDelegate(view)); + view->setMouseTracking(true); + view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + } + } + return QObject::eventFilter(object, event); + } +}; + +} + +QSize styling::Button::sizeHint() const { + QFont textFont = font(); + textFont.setPixelSize(13); + return QSize(QFontMetrics(textFont).horizontalAdvance(text().remove('&')) + + (icon().isNull() ? 28 : 53) + (menu() ? 14 : 0), 34); +} + +void styling::Button::paintEvent(QPaintEvent *) { + paintButton(this, true, false, menu() != nullptr, false); +} + +styling::ToolButton::ToolButton(QWidget *parent) : QToolButton(parent) { + setCursor(Qt::PointingHandCursor); + setFocusPolicy(Qt::StrongFocus); + setAutoRaise(true); + setIconSize(QSize(18, 18)); +} + +QSize styling::ToolButton::sizeHint() const { + if (toolButtonStyle() == Qt::ToolButtonIconOnly) + return QSize(34, 34); + QFont textFont = font(); + textFont.setPixelSize(13); + const int textWidth = QFontMetrics(textFont).horizontalAdvance(text().remove('&')); + if (toolButtonStyle() == Qt::ToolButtonTextUnderIcon) + return QSize(std::max(44, textWidth + 20), 52); + return QSize(textWidth + (icon().isNull() ? 24 : 49) + (menu() ? 14 : 0), 34); +} + +void styling::ToolButton::paintEvent(QPaintEvent *) { + paintButton(this, toolButtonStyle() != Qt::ToolButtonIconOnly, + toolButtonStyle() == Qt::ToolButtonTextUnderIcon, menu() != nullptr, true); +} + +styling::ItemDelegate::ItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {} + +void styling::ItemDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const { + QStyleOptionViewItem item(option); + initStyleOption(&item, index); + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + const bool selected = item.state & QStyle::State_Selected; + const bool hovered = item.state & QStyle::State_MouseOver; + const bool enabled = item.state & QStyle::State_Enabled; + const auto *list = qobject_cast(item.widget); + const bool grid = list != nullptr && list->viewMode() == QListView::IconMode; + const QRect bounds = item.rect.adjusted(3, 2, -3, -2); + painter->setPen(Qt::NoPen); + painter->setBrush(selected ? QColor("#30302E") + : hovered ? QColor("#242423") : QColor(Qt::transparent)); + painter->drawRoundedRect(bounds, 6, 6); + QRect textRect = bounds.adjusted(10, 0, -10, 0); + if (!item.icon.isNull()) { + const int size = grid ? 38 : 18; + QRect iconRect = grid ? QRect(bounds.center().x() - size / 2, bounds.top() + 14, size, size) + : QRect(textRect.left(), bounds.center().y() - size / 2, size, size); + item.icon.paint(painter, iconRect, Qt::AlignCenter, + enabled ? QIcon::Normal : QIcon::Disabled); + if (grid) + textRect.setTop(iconRect.bottom() + 9); + else + textRect.adjust(size + 9, 0, 0, 0); + } + if (item.features & QStyleOptionViewItem::HasCheckIndicator) { + const QRect check(textRect.left(), bounds.center().y() - 7, 14, 14); + painter->setPen(QPen(QColor("#666660"), 1)); + painter->setBrush(item.checkState == Qt::Checked ? QColor("#D5D5CF") : QColor("#242423")); + painter->drawRoundedRect(check, 3, 3); + if (item.checkState == Qt::Checked) + styling::icon(styling::Icon::Check, "#181817").paint(painter, check); + textRect.adjust(22, 0, 0, 0); + } + QFont font = item.font; + font.setPixelSize(13); + painter->setFont(font); + painter->setPen(!enabled ? QColor("#666660") + : selected ? QColor("#F0F0EA") : QColor("#BDBDB6")); + const QString secondary = index.data(styling::SecondaryTextRole).toString(); + if (!secondary.isEmpty() && !grid) { + QRect secondaryRect = textRect; + secondaryRect.setTop(bounds.top() + 27); + secondaryRect.setBottom(bounds.bottom() - 3); + QFont secondaryFont = font; + secondaryFont.setPixelSize(11); + painter->setFont(secondaryFont); + painter->setPen(QColor("#92928B")); + painter->drawText(secondaryRect, Qt::AlignLeft | Qt::AlignVCenter, + painter->fontMetrics().elidedText(secondary, Qt::ElideMiddle, + secondaryRect.width())); + textRect.setTop(bounds.top() + 3); + textRect.setBottom(bounds.top() + 25); + painter->setFont(font); + painter->setPen(selected ? QColor("#F0F0EA") : QColor("#BDBDB6")); + } + QString text = item.text; + const int shortcutAt = text.indexOf('\t'); + if (shortcutAt >= 0) { + const QString shortcut = text.mid(shortcutAt + 1); + text = text.left(shortcutAt); + const int shortcutWidth = painter->fontMetrics().horizontalAdvance(shortcut); + painter->setPen(QColor("#898983")); + painter->drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, shortcut); + textRect.adjust(0, 0, -shortcutWidth - 24, 0); + painter->setPen(selected ? QColor("#F0F0EA") : QColor("#BDBDB6")); + } + painter->drawText(textRect, grid ? Qt::AlignHCenter | Qt::AlignTop : Qt::AlignLeft | Qt::AlignVCenter, + painter->fontMetrics().elidedText(text, Qt::ElideMiddle, textRect.width())); + painter->restore(); +} + +QSize styling::ItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const { + const QVariant explicitSize = index.data(Qt::SizeHintRole); + if (explicitSize.isValid()) + return explicitSize.toSize(); + const auto *list = qobject_cast(option.widget); + if (list != nullptr && list->viewMode() == QListView::IconMode) + return QSize(120, 102); + QSize size = QStyledItemDelegate::sizeHint(option, index); + size.setHeight(index.data(styling::SecondaryTextRole).toString().isEmpty() ? 34 : 52); + return size; +} + +void styling::TreeView::drawBranches(QPainter *painter, const QRect &rect, + const QModelIndex &index) const { + if (!model()->hasChildren(index)) + return; + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(QPen(QColor("#94948D"), 1.3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + const QPointF center(rect.right() - indentation() / 2.0, rect.center().y()); + QPainterPath path; + path.moveTo(center + (isExpanded(index) ? QPointF(-3, -1.5) : QPointF(-1.5, -3))); + path.lineTo(center + (isExpanded(index) ? QPointF(0, 1.5) : QPointF(1.5, 0))); + path.lineTo(center + (isExpanded(index) ? QPointF(3, -1.5) : QPointF(-1.5, 3))); + painter->drawPath(path); + painter->restore(); +} + +void styling::installWorkbench(QApplication &app) { + app.installEventFilter(new WorkbenchInstaller(&app)); +} + +styling::WorkspaceStack::WorkspaceStack(QWidget *parent) : QStackedWidget(parent) { + layout()->setSizeConstraint(QLayout::SetNoConstraint); + connect(this, &QStackedWidget::currentChanged, this, [this] { updateGeometry(); }); +} + +QSize styling::WorkspaceStack::minimumSizeHint() const { + return currentWidget() != nullptr + ? currentWidget()->minimumSizeHint().expandedTo(currentWidget()->minimumSize()) + : QSize(0, 0); +} + +QSize styling::WorkspaceStack::sizeHint() const { + return currentWidget() != nullptr ? currentWidget()->sizeHint() : QSize(640, 480); +} + +styling::ElidedLabel::ElidedLabel(const QString &text, QWidget *parent) + : QLabel(text, parent) { + setToolTip(text); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); +} + +QSize styling::ElidedLabel::minimumSizeHint() const { + return QSize(0, fontMetrics().height()); +} + +QSize styling::ElidedLabel::sizeHint() const { + return QSize(std::min(320, fontMetrics().horizontalAdvance(text())), fontMetrics().height()); +} + +void styling::ElidedLabel::paintEvent(QPaintEvent *) { + QPainter painter(this); + painter.setFont(font()); + painter.setPen(palette().color(isEnabled() ? QPalette::Active : QPalette::Disabled, + QPalette::WindowText)); + painter.drawText(contentsRect(), Qt::AlignLeft | Qt::AlignVCenter, + fontMetrics().elidedText(text(), Qt::ElideMiddle, contentsRect().width())); +} diff --git a/editor/views/editor/editor.cpp b/editor/views/editor/editor.cpp index 9cfabbe5..d7cee368 100644 --- a/editor/views/editor/editor.cpp +++ b/editor/views/editor/editor.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + /* * editor.cpp * As part of the Atlas project @@ -67,7 +69,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -76,6 +80,8 @@ #include #include "DockManager.h" +#include "DockAreaWidget.h" +#include "IconProvider.h" #include "editor/debug.h" #include "editor/styling/icons.h" #include "editor/views/fileExplorer.h" @@ -90,8 +96,8 @@ #include "editor/views/splashScreen.h" namespace { -constexpr int DockStateVersion = 10; -constexpr auto DockStateKey = "docking/state/v10"; +constexpr int DockStateVersion = 11; +constexpr auto DockStateKey = "docking/state/v11"; QIcon commandIcon(const QString &name) { const QString command = name.toLower(); @@ -281,7 +287,7 @@ void EditorWindow::setupWindow() { project.has_value() ? project->name : QStringLiteral("Project"); updateWindowTitle(false); setMinimumSize(1100, 700); - resize(1440, 900); + resize(1512, 940); menuBar()->setNativeMenuBar(true); menuBar()->setObjectName("atlasMenuBar"); @@ -298,8 +304,22 @@ void EditorWindow::setupWindow() { ads::CDockManager::setConfigFlag(ads::CDockManager::DockAreaHasCloseButton, false); + auto &dockIcons = ads::CDockManager::iconProvider(); + const QIcon closeIcon(":/editor/assets/close.svg"); + dockIcons.registerCustomIcon(ads::TabCloseIcon, closeIcon); + dockIcons.registerCustomIcon(ads::DockAreaCloseIcon, closeIcon); + dockIcons.registerCustomIcon(ads::DockAreaUndockIcon, + styling::icon(styling::Icon::ArrowsOutCardinal)); + dockIcons.registerCustomIcon(ads::DockAreaMenuIcon, + styling::icon(styling::Icon::CaretDown)); coreManager = new ads::CDockManager(this); - setCentralWidget(coreManager); + auto *workspaceFrame = new QWidget(this); + workspaceFrame->setObjectName("editorFrame"); + auto *workspaceLayout = new QVBoxLayout(workspaceFrame); + workspaceLayout->setContentsMargins(10, 0, 10, 0); + workspaceLayout->setSpacing(0); + workspaceLayout->addWidget(coreManager); + setCentralWidget(workspaceFrame); dockManager = new EditorDockManager(coreManager); layoutSaveTimer = new QTimer(this); scriptWatcher = new QFileSystemWatcher(this); @@ -669,27 +689,68 @@ void EditorWindow::setupDocks() { [this] { workspaceChangesPending = true; }); connect(graphiteEditorPanel, &GraphiteEditorPanel::documentSaved, this, [this] { workspaceChangesPending = true; }); - workspaceStack = new QStackedWidget(this); + workspaceStack = new styling::WorkspaceStack(this); workspaceStack->setObjectName("editorWorkspaceStack"); workspaceStack->addWidget(viewportTools); workspaceStack->addWidget(materialEditorPanel); workspaceStack->addWidget(postProcessingPanel); workspaceStack->addWidget(graphiteEditorPanel); workspaceStack->setCurrentIndex(0); + auto *workspaceSurface = new QWidget(this); + workspaceSurface->setObjectName("workspaceSurface"); + auto *surfaceLayout = new QVBoxLayout(workspaceSurface); + surfaceLayout->setContentsMargins(0, 0, 0, 0); + surfaceLayout->setSpacing(0); + auto *workspaceHeading = new QWidget(workspaceSurface); + workspaceHeading->setObjectName("workspaceHeading"); + auto *headingLayout = new QHBoxLayout(workspaceHeading); + headingLayout->setContentsMargins(8, 5, 8, 5); + headingLayout->setSpacing(4); + auto *switcher = new QWidget(workspaceHeading); + switcher->setObjectName("workspaceSwitcher"); + auto *switcherLayout = new QHBoxLayout(switcher); + switcherLayout->setContentsMargins(0, 0, 0, 0); + switcherLayout->setSpacing(3); + workspaceModeGroup = new QButtonGroup(switcher); + workspaceModeGroup->setExclusive(true); + const QStringList modes{"Scene", "Shading", "Effects", "Interface"}; + for (int index = 0; index < modes.size(); ++index) { + auto *button = new styling::ToolButton(switcher); + button->setObjectName("workspaceModeButton"); + button->setToolButtonStyle(Qt::ToolButtonTextOnly); + button->setText(modes.at(index)); + button->setCheckable(true); + button->setChecked(index == 0); + workspaceModeGroup->addButton(button, index); + switcherLayout->addWidget(button); + connect(button, &QToolButton::clicked, this, + [this, index] { activateWorkspace(index); }); + } + headingLayout->addWidget(switcher); + headingLayout->addStretch(); + auto *workspaceSearch = new styling::ToolButton(workspaceHeading); + workspaceSearch->setIcon(styling::icon(styling::Icon::MagnifyingGlass)); + workspaceSearch->setToolTip("Search scenes, objects and assets"); + connect(workspaceSearch, &QToolButton::clicked, this, &EditorWindow::showGlobalSearch); + headingLayout->addWidget(workspaceSearch); + surfaceLayout->addWidget(workspaceHeading); + surfaceLayout->addWidget(workspaceStack, 1); auto *workspaceDock = dockManager->addPanel( {.id = "workspace", .title = "Workspace", - .widget = workspaceStack, + .widget = workspaceSurface, .area = EditorDockArea::Center, .icon = styling::icon(styling::Icon::CubeFocus, "#7E929C")}); workspaceDock->setFeature(ads::CDockWidget::NoTab, true); + if (auto *area = workspaceDock->dockAreaWidget()) + area->setDockAreaFlag(ads::CDockAreaWidget::HideSingleWidgetTitleBar, true); hierarchyPanel = new HierarchyPanel(viewportPanel); auto *hierarchyDock = dockManager->addPanel( {.id = "hierarchy", - .title = "Scene", + .title = "Scene Collection", .widget = hierarchyPanel, - .area = EditorDockArea::Right, + .area = EditorDockArea::Left, .icon = styling::icon(styling::Icon::TreeStructure, "#8498A8")}); inspectorPanel = new InspectorPanel(viewportPanel, projectFile); @@ -699,10 +760,6 @@ void EditorWindow::setupDocks() { .widget = inspectorPanel, .area = EditorDockArea::Right, .icon = styling::icon(styling::Icon::SlidersHorizontal, "#A1957D")}); - if (hierarchyDock->dockAreaWidget() != nullptr) { - coreManager->addDockWidget(ads::BottomDockWidgetArea, inspectorDock, - hierarchyDock->dockAreaWidget()); - } contentBrowser = new ContentBrowserPanel(projectFile); auto *contentDock = dockManager->addPanel( @@ -745,6 +802,8 @@ void EditorWindow::setupDocks() { }); workspaceDock->setAsCurrentTab(); + coreManager->setSplitterSizes(workspaceDock->dockAreaWidget(), {250, 870, 360}); + coreManager->setSplitterSizes(contentDock->dockAreaWidget(), {650, 240}); defaultDockState = coreManager->saveState(DockStateVersion); const QList managedDocks{workspaceDock, hierarchyDock, @@ -875,129 +934,84 @@ void EditorWindow::setupWorkspaceBar() { bar->setObjectName("workspaceBar"); bar->setMovable(false); bar->setFloatable(false); - bar->setIconSize(QSize(18, 18)); - bar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); addToolBar(Qt::TopToolBarArea, bar); - - auto *identity = new QWidget(bar); - identity->setObjectName("workspaceIdentity"); - auto *identityLayout = new QHBoxLayout(identity); - identityLayout->setContentsMargins(10, 2, 16, 2); - identityLayout->setSpacing(9); - auto *mark = new QLabel(identity); + auto *chrome = new QWidget(bar); + chrome->setObjectName("workspaceChrome"); + chrome->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + auto *layout = new QGridLayout(chrome); + layout->setContentsMargins(12, 7, 12, 7); + layout->setHorizontalSpacing(16); + layout->setColumnStretch(0, 1); + layout->setColumnStretch(2, 1); + auto *activity = new QWidget(chrome); + activity->setObjectName("workspaceActivity"); + auto *activityLayout = new QHBoxLayout(activity); + activityLayout->setContentsMargins(0, 0, 0, 0); + activityLayout->setSpacing(4); + auto *mark = new QLabel(activity); mark->setObjectName("workspaceMark"); -#ifdef ATLAS_DEBUG_BUILD - mark->setPixmap(QPixmap(":/editor/assets/Icon-iOS-Default-1024x1024@1x.png") - .scaled(24, 24, Qt::KeepAspectRatio, - Qt::SmoothTransformation)); -#else - mark->setPixmap(QPixmap(":/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png") - .scaled(24, 24, Qt::KeepAspectRatio, - Qt::SmoothTransformation)); -#endif - auto *identityText = new QWidget(identity); - identityText->setObjectName("workspaceIdentityText"); - auto *identityTextLayout = new QVBoxLayout(identityText); - identityTextLayout->setContentsMargins(0, 0, 0, 0); - identityTextLayout->setSpacing(0); - auto *brand = new QLabel("ATLAS ENGINE", identityText); - brand->setObjectName("workspaceBrand"); - auto *project = new QLabel(projectName, identityText); - project->setObjectName("workspaceProject"); - identityTextLayout->addWidget(brand); - identityTextLayout->addWidget(project); - identityLayout->addWidget(mark); - identityLayout->addWidget(identityText); - bar->addWidget(identity); - - auto *switcher = new QFrame(bar); - switcher->setObjectName("workspaceSwitcher"); - auto *switcherLayout = new QHBoxLayout(switcher); - switcherLayout->setContentsMargins(3, 3, 3, 3); - switcherLayout->setSpacing(1); - workspaceModeGroup = new QButtonGroup(switcher); - workspaceModeGroup->setExclusive(true); - bar->addWidget(switcher); - - addToolBarBreak(Qt::TopToolBarArea); - auto *contextBar = new QToolBar("Context", this); - contextBar->setObjectName("workspaceContextBar"); - contextBar->setMovable(false); - contextBar->setFloatable(false); - contextBar->setIconSize(QSize(15, 15)); - contextBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - addToolBar(Qt::TopToolBarArea, contextBar); - - auto *breadcrumb = new QWidget(contextBar); - breadcrumb->setObjectName("workspaceBreadcrumb"); - auto *breadcrumbLayout = new QHBoxLayout(breadcrumb); - breadcrumbLayout->setContentsMargins(8, 0, 12, 0); - breadcrumbLayout->setSpacing(7); - auto *workspaceContextIcon = new QLabel(breadcrumb); - workspaceContextIcon->setObjectName("workspaceContextIcon"); - workspaceContextIcon->setPixmap( - styling::icon(styling::Icon::CubeFocus, "#7E929C").pixmap(15, 15)); - auto *workspaceContextTitle = new QLabel("Scene", breadcrumb); - workspaceContextTitle->setObjectName("workspaceContextTitle"); - auto *workspaceContextPath = new QLabel("· Layout", breadcrumb); - workspaceContextPath->setObjectName("workspaceContextPath"); - breadcrumbLayout->addWidget(workspaceContextIcon); - breadcrumbLayout->addWidget(workspaceContextTitle); - breadcrumbLayout->addWidget(workspaceContextPath); - contextBar->addWidget(breadcrumb); - - const QStringList workspacePaths{"· Layout", "· Materials", "· Effects", - "· Interface"}; - auto addMode = [this, switcher, switcherLayout, workspaceContextIcon, - workspaceContextTitle, workspaceContextPath, - workspacePaths](const QString &text, styling::Icon icon, - const QColor &color, int index, - bool selected = false) { - auto *button = new QToolButton(switcher); - button->setObjectName("workspaceModeButton"); + mark->setPixmap(styling::brandMark(QSize(26, 26))); + activityLayout->addWidget(mark); + activityLayout->addSpacing(10); + auto addPanelToggle = [this, activity, activityLayout](const QString &id, + const QString &text, + styling::Icon icon) { + auto *dock = dockManager->panel(id); + if (dock == nullptr) + return; + auto *button = new styling::ToolButton(activity); + button->setObjectName("workspacePanelButton"); + button->setIcon(styling::icon(icon)); button->setText(text); - button->setIcon(styling::icon(icon, color)); - button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + button->setToolTip(text); button->setCheckable(true); - button->setChecked(selected); - button->setProperty("workspacePath", workspacePaths.at(index)); - workspaceModeGroup->addButton(button, index); - switcherLayout->addWidget(button); - connect(button, &QToolButton::clicked, this, - [this, workspaceContextIcon, workspaceContextTitle, - workspaceContextPath, workspacePaths, text, icon, color, - index] { - activateWorkspace(index); - workspaceContextIcon->setPixmap( - styling::icon(icon, color).pixmap(15, 15)); - workspaceContextTitle->setText(text); - workspaceContextPath->setText(workspacePaths.at(index)); + button->setChecked(!dock->isClosed()); + activityLayout->addWidget(button); + connect(button, &QToolButton::toggled, dock, + [dock](bool visible) { dock->toggleView(visible); }); + connect(dock, &ads::CDockWidget::viewToggled, button, + [button](bool visible) { + const QSignalBlocker blocker(button); + button->setChecked(visible); }); }; - addMode("Scene", styling::Icon::CubeFocus, "#7E929C", 0, true); - addMode("Shading", styling::Icon::Material, "#A1957D", 1); - addMode("Post-Processing", styling::Icon::FilmStrip, "#849589", 2); - addMode("Graphite", styling::Icon::Palette, "#849589", 3); - - auto *spacer = new QWidget(bar); - spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - bar->addWidget(spacer); - - auto *commands = new QToolButton(bar); - commands->setObjectName("workspaceCommandButton"); - commands->setIcon(styling::icon(styling::Icon::MagnifyingGlass, "#7E929C")); - commands->setText("Commands"); - commands->setToolTip("Command Palette · Command Shift P"); - bar->addWidget(commands); - connect(commands, &QToolButton::clicked, this, - &EditorWindow::showCommandPalette); - - auto *save = new QToolButton(bar); - save->setObjectName("workspaceUtilityButton"); - save->setIcon(styling::icon(styling::Icon::FloppyDisk, "#A1957D")); - save->setText("Save"); - save->setToolTip("Save Scene"); - bar->addWidget(save); + addPanelToggle("hierarchy", "Scene collection", styling::Icon::Sidebar); + addPanelToggle("fileExplorer", "Assets", styling::Icon::Folder); + addPanelToggle("inspector", "Inspector", styling::Icon::SlidersHorizontal); + auto *commands = new styling::ToolButton(activity); + commands->setIcon(styling::icon(styling::Icon::MagnifyingGlass)); + commands->setToolTip("Search commands · " + + QKeySequence("Ctrl+Shift+P").toString(QKeySequence::NativeText)); + connect(commands, &QToolButton::clicked, this, &EditorWindow::showCommandPalette); + activityLayout->addWidget(commands); + activityLayout->addStretch(); + layout->addWidget(activity, 0, 0); + + auto *project = new styling::ToolButton(chrome); + project->setObjectName("workspaceProject"); + project->setIcon(styling::icon(styling::Icon::FolderOpen)); + project->setText(projectName); + project->setMaximumWidth(280); + project->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + project->setPopupMode(QToolButton::InstantPopup); + project->setToolTip(projectName); + auto *projectMenu = new QMenu(project); + projectMenu->addAction("Project Settings…", this, &EditorWindow::showProjectSettings); + projectMenu->addAction("Input Actions…", this, &EditorWindow::showInputActions); + projectMenu->addSeparator(); + projectMenu->addAction("Export Project…", this, &EditorWindow::showExportDialog); + project->setMenu(projectMenu); + layout->addWidget(project, 0, 1, Qt::AlignCenter); + + auto *utilities = new QWidget(chrome); + utilities->setObjectName("workspaceUtilities"); + auto *utilityLayout = new QHBoxLayout(utilities); + utilityLayout->setContentsMargins(0, 0, 0, 0); + utilityLayout->setSpacing(5); + utilityLayout->addStretch(); + auto *save = new styling::ToolButton(utilities); + save->setIcon(styling::icon(styling::Icon::FloppyDisk)); + save->setToolTip("Save current work"); connect(save, &QToolButton::clicked, this, [this] { if (materialEditorPanel != nullptr && materialEditorPanel->isVisible()) materialEditorPanel->saveMaterial(); @@ -1006,57 +1020,25 @@ void EditorWindow::setupWorkspaceBar() { if (viewportPanel != nullptr) viewportPanel->saveRuntimeScene(); }); - - auto *build = new QToolButton(bar); - build->setObjectName("workspaceBuildButton"); - build->setIcon(styling::icon(styling::Icon::Package, "#A1957D")); - build->setText("Build"); - build->setToolTip("Build Project"); - bar->addWidget(build); - connect(build, &QToolButton::clicked, this, - [this] { runProjectCommand(true); }); - - auto *launch = new QToolButton(bar); + utilityLayout->addWidget(save); + auto *build = new styling::ToolButton(utilities); + build->setIcon(styling::icon(styling::Icon::Package)); + build->setToolTip("Build project"); + connect(build, &QToolButton::clicked, this, [this] { runProjectCommand(true); }); + utilityLayout->addWidget(build); + auto *launch = new styling::ToolButton(utilities); launch->setObjectName("workspaceLaunchButton"); - launch->setIcon(styling::icon(styling::Icon::RocketLaunch, "#849589")); + launch->setIcon(styling::icon(styling::Icon::Play)); launch->setText("Run"); - launch->setToolTip("Run Project"); - bar->addWidget(launch); - connect(launch, &QToolButton::clicked, this, - [this] { runProjectCommand(false); }); - - auto *contextSpacer = new QWidget(contextBar); - contextSpacer->setSizePolicy(QSizePolicy::Expanding, - QSizePolicy::Preferred); - contextBar->addWidget(contextSpacer); - auto addPanelToggle = [this, contextBar](const QString &id, - const QString &text, - styling::Icon icon) { - ads::CDockWidget *dock = dockManager->panel(id); - if (dock == nullptr) - return; - auto *button = new QToolButton(contextBar); - button->setObjectName("workspacePanelButton"); - button->setText(text); - button->setIcon(styling::icon(icon, "#8490A4")); - button->setCheckable(true); - button->setChecked(dock->isVisible()); - contextBar->addWidget(button); - connect(button, &QToolButton::toggled, dock, - [dock](bool visible) { dock->toggleView(visible); }); - connect(dock, &ads::CDockWidget::viewToggled, button, - [button](bool visible) { - const QSignalBlocker blocker(button); - button->setChecked(visible); - }); - }; - addPanelToggle("hierarchy", "Scene", styling::Icon::TreeStructure); - addPanelToggle("fileExplorer", "Assets", styling::Icon::FolderOpen); - addPanelToggle("inspector", "Inspector", - styling::Icon::SlidersHorizontal); + launch->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + launch->setToolTip("Run project"); + connect(launch, &QToolButton::clicked, this, [this] { runProjectCommand(false); }); + utilityLayout->addWidget(launch); + layout->addWidget(utilities, 0, 2); + bar->addWidget(chrome); statusBar()->setObjectName("atlasStatusBar"); - statusBar()->showMessage("Ready"); + statusBar()->showMessage("Scene workspace"); auto *runtimeStatus = new QWidget(statusBar()); runtimeStatus->setObjectName("statusRuntime"); auto *runtimeLayout = new QHBoxLayout(runtimeStatus); @@ -1100,6 +1082,28 @@ void EditorWindow::activateWorkspace(int index) { index >= workspaceStack->count()) return; const int previousIndex = workspaceStack->currentIndex(); + if (previousIndex != index && coreManager != nullptr) { + QSettings settings("Neutral Software", "Atlas Engine"); + const auto layoutKey = [](int mode) { + return QStringLiteral("workspace/layout/v11/%1").arg(mode); + }; + if (!restoringLayout) + settings.setValue(layoutKey(previousIndex), + coreManager->saveState(DockStateVersion)); + const QByteArray state = settings.value(layoutKey(index)).toByteArray(); + if (state.isEmpty() || !coreManager->restoreState(state, DockStateVersion)) { + if (index == 0) { + coreManager->restoreState(defaultDockState, DockStateVersion); + } else { + for (const QString &id : {QStringLiteral("hierarchy"), + QStringLiteral("inspector")}) { + if (auto *dock = dockManager->panel(id)) + dock->toggleView(false); + } + } + } + configureDockSplitters(); + } if (index == 0 && previousIndex == 1 && materialEditorPanel != nullptr) materialEditorPanel->flushPendingSave(); if (index == 0 && previousIndex == 3 && graphiteEditorPanel != nullptr) @@ -1678,7 +1682,7 @@ void EditorWindow::showExportDialog() { QDir(QFileInfo(projectFile).absolutePath()).filePath("Exports")) .toString(), &dialog); - auto *browse = new QPushButton("Choose…", &dialog); + auto *browse = new styling::Button("Choose…", &dialog); browse->setIcon(styling::icon(styling::Icon::FolderOpen, "#7E929C")); auto *outputRow = new QWidget(&dialog); auto *outputLayout = new QHBoxLayout(outputRow); @@ -1837,15 +1841,22 @@ void EditorWindow::showCommandPalette() { dialog.setObjectName("commandPaletteDialog"); dialog.setWindowTitle("Command Palette"); dialog.setWindowFlags(dialog.windowFlags() | Qt::FramelessWindowHint); - dialog.resize(620, 430); + dialog.resize(720, 470); auto *layout = new QVBoxLayout(&dialog); + layout->setContentsMargins(8, 8, 8, 8); + layout->setSpacing(4); auto *search = new QLineEdit(&dialog); search->setObjectName("commandPaletteSearch"); + search->setClearButtonEnabled(true); + search->addAction(styling::icon(styling::Icon::MagnifyingGlass), QLineEdit::LeadingPosition); search->setPlaceholderText("Type a command…"); auto *commands = new QListWidget(&dialog); commands->setObjectName("commandPaletteList"); layout->addWidget(search); layout->addWidget(commands, 1); + auto *hint = new QLabel("↑ ↓ Navigate Return Open Esc Dismiss", &dialog); + hint->setObjectName("paletteHint"); + layout->addWidget(hint); const QList actions = findChildren(); for (QAction *action : actions) { if (action->text().isEmpty() || action->isSeparator() || @@ -1936,17 +1947,96 @@ void EditorWindow::showGlobalSearch() { dialog.setObjectName("globalSearchDialog"); dialog.setWindowTitle("Search Atlas Project"); dialog.setWindowFlags(dialog.windowFlags() | Qt::FramelessWindowHint); - dialog.resize(680, 460); + dialog.resize(960, 560); auto *layout = new QVBoxLayout(&dialog); + layout->setContentsMargins(8, 8, 8, 8); + layout->setSpacing(4); auto *search = new QLineEdit(&dialog); search->setObjectName("globalSearchField"); + search->setClearButtonEnabled(true); + search->addAction(styling::icon(styling::Icon::MagnifyingGlass), QLineEdit::LeadingPosition); search->setPlaceholderText("Search scenes, assets, and commands…"); auto *results = new QListWidget(&dialog); results->setObjectName("globalSearchResults"); layout->addWidget(search); - layout->addWidget(results, 1); + auto *splitter = new QSplitter(Qt::Horizontal, &dialog); + splitter->setChildrenCollapsible(false); + splitter->setHandleWidth(1); + splitter->addWidget(results); + auto *previewPane = new QWidget(splitter); + previewPane->setObjectName("searchPreviewPane"); + auto *previewLayout = new QVBoxLayout(previewPane); + previewLayout->setContentsMargins(16, 14, 12, 10); + previewLayout->setSpacing(10); + auto *previewTitle = new styling::ElidedLabel("Preview", previewPane); + previewTitle->setObjectName("workspaceTitle"); + previewLayout->addWidget(previewTitle); + auto *previewStack = new QStackedWidget(previewPane); + auto *previewText = new QPlainTextEdit(previewStack); + previewText->setObjectName("searchPreviewText"); + previewText->setReadOnly(true); + previewText->setLineWrapMode(QPlainTextEdit::NoWrap); + previewText->setPlaceholderText("Select a result to preview it."); + auto *previewImage = new QLabel(previewStack); + previewImage->setAlignment(Qt::AlignCenter); + previewStack->addWidget(previewText); + previewStack->addWidget(previewImage); + previewLayout->addWidget(previewStack, 1); + splitter->addWidget(previewPane); + splitter->setSizes({480, 440}); + layout->addWidget(splitter, 1); + auto *hint = new QLabel("↑ ↓ Navigate Return Open Esc Dismiss", &dialog); + hint->setObjectName("paletteHint"); + layout->addWidget(hint); constexpr int SearchKindRole = Qt::UserRole + 1; constexpr int SearchValueRole = Qt::UserRole + 2; + connect(results, &QListWidget::currentItemChanged, &dialog, + [previewTitle, previewText, previewStack, previewImage](QListWidgetItem *item) { + previewStack->setCurrentIndex(0); + previewText->clear(); + previewImage->clear(); + if (item == nullptr || item->data(SearchKindRole).toInt() == 3) { + previewTitle->setText("Preview"); + return; + } + previewTitle->setText(item->text()); + previewTitle->setToolTip(item->toolTip()); + if (item->data(SearchKindRole).toInt() != 0) { + previewText->setPlainText(item->data(styling::SecondaryTextRole).toString()); + return; + } + const QString path = item->data(SearchValueRole).toString(); + const QFileInfo info(path); + const QStringList textTypes{"ts", "js", "json", "atlas", "ascene", "aui", + "amat", "toml", "txt", "md", "glsl", "vert", "frag"}; + if (textTypes.contains(info.suffix().toLower())) { + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.read(65536); + QString text = QString::fromUtf8(data); + if (!file.atEnd()) + text += "\n\n… Preview limited to 64 KB"; + previewText->setPlainText(text); + return; + } + } + QImageReader reader(path); + const QSize dimensions = reader.size(); + if (dimensions.isValid() && dimensions.width() <= 16384 && + dimensions.height() <= 16384) { + reader.setAutoTransform(true); + reader.setScaledSize(dimensions.scaled(QSize(360, 300), Qt::KeepAspectRatio)); + const QImage image = reader.read(); + if (!image.isNull()) { + previewImage->setPixmap(QPixmap::fromImage(image)); + previewStack->setCurrentIndex(1); + return; + } + } + previewText->setPlainText(QStringLiteral("%1\n\n%2\n%3 KB") + .arg(info.fileName(), item->data(styling::SecondaryTextRole).toString()) + .arg(info.size() / 1024.0, 0, 'f', 1)); + }); QDirIterator iterator(QFileInfo(projectFile).absolutePath(), QDir::Files, QDirIterator::Subdirectories); while (iterator.hasNext()) { @@ -1954,12 +2044,14 @@ void EditorWindow::showGlobalSearch() { const QString relative = QDir(QFileInfo(projectFile).absolutePath()).relativeFilePath(path); if (relative.startsWith(".git/") || relative.startsWith("build/") || - relative.startsWith("dist/")) + relative.startsWith("dist/") || relative.startsWith(".jj/") || + relative.startsWith("node_modules/") || relative.startsWith("target/")) continue; auto *item = new QListWidgetItem( - QStringLiteral("Asset %1").arg(relative), results); + QFileInfo(path).fileName(), results); item->setIcon(styling::icon(styling::Icon::File, "#7E929C")); item->setToolTip(path); + item->setData(styling::SecondaryTextRole, "Asset · " + QFileInfo(relative).path()); item->setData(SearchKindRole, 0); item->setData(SearchValueRole, path); } @@ -1976,9 +2068,10 @@ void EditorWindow::showGlobalSearch() { const int id = object.value("id").toInt(-1); if (!name.isEmpty() && id >= 0) { auto *item = new QListWidgetItem( - QStringLiteral("Object %1").arg(name), results); + name, results); item->setIcon(styling::icon(styling::Icon::Cube, "#8498A8")); item->setToolTip(object.value("type").toString()); + item->setData(styling::SecondaryTextRole, "Scene object · " + item->toolTip()); item->setData(SearchKindRole, 1); item->setData(SearchValueRole, id); } @@ -1992,10 +2085,11 @@ void EditorWindow::showGlobalSearch() { !action->isEnabled()) continue; auto *item = new QListWidgetItem( - QStringLiteral("Command %1").arg(action->text().remove('&')), + action->text().remove('&'), results); item->setIcon(action->icon()); item->setData(SearchKindRole, 2); + item->setData(styling::SecondaryTextRole, "Command · " + action->shortcut().toString(QKeySequence::NativeText)); item->setData(SearchValueRole, QVariant::fromValue( reinterpret_cast(action))); } @@ -2267,6 +2361,10 @@ void EditorWindow::saveLayout() { settings.setValue("window/geometry", saveGeometry()); settings.setValue(DockStateKey, coreManager->saveState(DockStateVersion)); + if (workspaceStack != nullptr) + settings.setValue( + QStringLiteral("workspace/layout/v11/%1").arg(workspaceStack->currentIndex()), + coreManager->saveState(DockStateVersion)); if (workspaceStack != nullptr) settings.setValue("workspace/mode", workspaceStack->currentIndex()); settings.sync(); @@ -2297,8 +2395,14 @@ void EditorWindow::restoreLayout() { void EditorWindow::configureDockSplitters() { if (coreManager == nullptr) return; + if (dockManager != nullptr) { + if (auto *workspace = dockManager->panel("workspace")) { + if (auto *area = workspace->dockAreaWidget()) + area->setDockAreaFlag(ads::CDockAreaWidget::HideSingleWidgetTitleBar, true); + } + } for (QSplitter *splitter : coreManager->findChildren()) { - splitter->setHandleWidth(4); + splitter->setHandleWidth(10); splitter->setOpaqueResize(true); splitter->setChildrenCollapsible(false); if (!splitter->property("atlasLayoutTracking").toBool()) { diff --git a/editor/views/editor/graphiteEditor.cpp b/editor/views/editor/graphiteEditor.cpp index dc5c50e0..0c30e4d4 100644 --- a/editor/views/editor/graphiteEditor.cpp +++ b/editor/views/editor/graphiteEditor.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + #include "editor/views/graphiteEditor.h" #include "editor/styling/icons.h" @@ -236,7 +238,7 @@ class GraphiteCanvas : public QWidget { void paintEvent(QPaintEvent *) override { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); - painter.fillRect(rect(), QColor("#17191D")); + painter.fillRect(rect(), QColor("#171716")); const QJsonObject canvas = document.value("canvas").toObject(); const double width = std::max(1.0, canvas.value("width").toDouble(1280)); const double height = @@ -410,7 +412,7 @@ class GraphiteCanvas : public QWidget { } if (path == selected) { painter.setBrush(Qt::NoBrush); - painter.setPen(QPen(QColor("#E39758"), 2.0 / canvasScale)); + painter.setPen(QPen(QColor("#B7A4ED"), 2.0 / canvasScale)); painter.drawRect(frame.adjusted(-2, -2, 2, 2)); } if (!element.value("components").toArray().isEmpty()) { @@ -452,11 +454,11 @@ GraphiteEditorPanel::GraphiteEditorPanel(ViewportPanel *viewport, titleLabel->setObjectName("materialEditorTitle"); statusLabel = new QLabel(header); statusLabel->setObjectName("materialEditorStatus"); - auto *attach = new QPushButton("Attach to Scene", header); + auto *attach = new styling::Button("Attach to Scene", header); attach->setIcon(styling::icon(styling::Icon::Assign, "#9E897D")); - auto *preview = new QPushButton("Preview Camera", header); + auto *preview = new styling::Button("Preview Camera", header); preview->setIcon(styling::icon(styling::Icon::MonitorPlay, "#849589")); - auto *save = new QPushButton("Save", header); + auto *save = new styling::Button("Save", header); save->setIcon(styling::icon(styling::Icon::FloppyDisk, "#A1957D")); headerLayout->addWidget(titleLabel, 1); headerLayout->addWidget(statusLabel); @@ -473,7 +475,7 @@ GraphiteEditorPanel::GraphiteEditorPanel(ViewportPanel *viewport, auto *outlineLayout = new QVBoxLayout(outline); outlineLayout->setContentsMargins(8, 8, 4, 8); auto *outlineToolbar = new QHBoxLayout(); - auto *add = new QToolButton(outline); + auto *add = new styling::ToolButton(outline); add->setText("Add"); add->setIcon(styling::icon(styling::Icon::Plus, "#8498A8")); add->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -490,10 +492,10 @@ GraphiteEditorPanel::GraphiteEditorPanel(ViewportPanel *viewport, for (const auto &[label, type] : types) addMenu->addAction(label, this, [this, type] { addElement(type); }); add->setMenu(addMenu); - auto *duplicate = new QToolButton(outline); + auto *duplicate = new styling::ToolButton(outline); duplicate->setIcon(styling::icon(styling::Icon::SquaresFour, "#7E929C")); duplicate->setToolTip("Duplicate selected element"); - auto *remove = new QToolButton(outline); + auto *remove = new styling::ToolButton(outline); remove->setIcon(styling::icon(styling::Icon::Trash, "#A17F7F")); remove->setToolTip("Delete selected element"); outlineToolbar->addWidget(add); @@ -925,7 +927,7 @@ void GraphiteEditorPanel::rebuildInspector() { QJsonObject fontData = document.value("defaultFont").toObject(); auto *fontPath = new QLineEdit(fontData.value("source").toString(), fontGroup); - auto *chooseFont = new QPushButton("Choose…", fontGroup); + auto *chooseFont = new styling::Button("Choose…", fontGroup); auto *fontRow = new QWidget(fontGroup); auto *fontRowLayout = new QHBoxLayout(fontRow); fontRowLayout->setContentsMargins(0, 0, 0, 0); @@ -1074,7 +1076,7 @@ void GraphiteEditorPanel::rebuildInspector() { } else { auto *source = new QLineEdit(element.value("source").toString(), contentGroup); - auto *choose = new QPushButton("Choose…", contentGroup); + auto *choose = new styling::Button("Choose…", contentGroup); auto *row = new QWidget(contentGroup); auto *rowLayout = new QHBoxLayout(row); rowLayout->setContentsMargins(0, 0, 0, 0); @@ -1135,10 +1137,12 @@ void GraphiteEditorPanel::rebuildInspector() { jsonColor(normal.value("foreground"), jsonColor(fallbackNormal.value("foreground"), QColor("#F5F6F8"))); - auto *backgroundButton = new QPushButton(appearance); + auto *backgroundButton = new styling::Button(appearance); + backgroundButton->setProperty("preserveIconColor", true); backgroundButton->setIcon(styling::colorSwatch(background)); backgroundButton->setText(background.name(QColor::HexArgb)); - auto *foregroundButton = new QPushButton(appearance); + auto *foregroundButton = new styling::Button(appearance); + foregroundButton->setProperty("preserveIconColor", true); foregroundButton->setIcon(styling::colorSwatch(foreground)); foregroundButton->setText(foreground.name(QColor::HexArgb)); auto *radius = @@ -1197,8 +1201,8 @@ void GraphiteEditorPanel::rebuildInspector() { item->setToolTip(component.value("source").toString()); } auto *componentButtons = new QHBoxLayout(); - auto *addScript = new QPushButton("Add Script…", components); - auto *removeScript = new QPushButton("Remove", components); + auto *addScript = new styling::Button("Add Script…", components); + auto *removeScript = new styling::Button("Remove", components); componentButtons->addWidget(addScript); componentButtons->addWidget(removeScript); componentsLayout->addWidget(componentList); @@ -1209,7 +1213,7 @@ void GraphiteEditorPanel::rebuildInspector() { auto *componentVariables = new QPlainTextEdit(components); componentVariables->setPlaceholderText("{}"); componentVariables->setMaximumHeight(92); - auto *applyComponent = new QPushButton("Apply Component", components); + auto *applyComponent = new styling::Button("Apply Component", components); componentForm->addRow("Class", componentClass); componentForm->addRow("Source", componentSource); componentForm->addRow("Variables", componentVariables); diff --git a/editor/views/editor/hierarchy.cpp b/editor/views/editor/hierarchy.cpp index 2b84b611..5cfb06a1 100644 --- a/editor/views/editor/hierarchy.cpp +++ b/editor/views/editor/hierarchy.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + /* * hierarchy.cpp * As part of the Atlas project @@ -130,7 +132,7 @@ HierarchyPanel::HierarchyPanel(ViewportPanel *viewport, QWidget *parent) : QWidget(parent), viewport(viewport) { setObjectName("hierarchyPanel"); auto *layout = new QVBoxLayout(this); - layout->setContentsMargins(4, 4, 4, 4); + layout->setContentsMargins(10, 0, 10, 10); layout->setSpacing(4); auto *toolbar = new QWidget(this); @@ -139,30 +141,32 @@ HierarchyPanel::HierarchyPanel(ViewportPanel *viewport, QWidget *parent) toolbarLayout->setContentsMargins(0, 0, 0, 0); toolbarLayout->setSpacing(4); - addButton = new QToolButton(toolbar); + addButton = new styling::ToolButton(toolbar); addButton->setObjectName("panelAddButton"); addButton->setIcon(styling::icon(styling::Icon::Plus, "#8498A8")); addButton->setText("Add"); - addButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + addButton->setToolButtonStyle(Qt::ToolButtonIconOnly); addButton->setPopupMode(QToolButton::InstantPopup); addButton->setToolTip("Add Object"); - moreButton = new QToolButton(toolbar); + moreButton = new styling::ToolButton(toolbar); moreButton->setObjectName("panelMoreButton"); moreButton->setIcon(styling::icon(styling::Icon::DotsVertical, "#8490A4")); moreButton->setPopupMode(QToolButton::InstantPopup); moreButton->setToolTip("Hierarchy actions"); - toolbarLayout->addWidget(addButton); + searchField = new QLineEdit(toolbar); searchField->setPlaceholderText("Search hierarchy"); searchField->setClearButtonEnabled(true); - searchField->setMaximumWidth(180); + searchField->setMinimumWidth(80); + searchField->setObjectName("hierarchySearch"); toolbarLayout->addWidget(searchField, 1); + toolbarLayout->addWidget(addButton); toolbarLayout->addWidget(moreButton); layout->addWidget(toolbar); - treeView = new QTreeView(this); + treeView = new styling::TreeView(this); treeView->setObjectName("hierarchyTree"); model = new QStandardItemModel(this); treeView->setModel(model); @@ -171,7 +175,7 @@ HierarchyPanel::HierarchyPanel(ViewportPanel *viewport, QWidget *parent) treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); treeView->setSelectionBehavior(QAbstractItemView::SelectRows); - treeView->setIndentation(16); + treeView->setIndentation(20); treeView->setIconSize(QSize(18, 18)); treeView->setContextMenuPolicy(Qt::CustomContextMenu); treeView->setUniformRowHeights(true); diff --git a/editor/views/editor/inspector.cpp b/editor/views/editor/inspector.cpp index 5d4988db..965900ef 100644 --- a/editor/views/editor/inspector.cpp +++ b/editor/views/editor/inspector.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + /* * inspector.cpp * As part of the Atlas project @@ -679,6 +681,7 @@ QDoubleSpinBox *numberField(double value, QWidget *parent) { field->setObjectName("inspectorNumberField"); field->setRange(-1000000000.0, 1000000000.0); field->setDecimals(4); + field->setMinimumHeight(34); field->setSingleStep(0.1); field->setButtonSymbols(QAbstractSpinBox::NoButtons); field->setValue(value); @@ -742,10 +745,9 @@ void addSyncPicker(QHBoxLayout *layout, const QString &path, const QJsonValue ¤t, const PropertyChanged &changed, const SyncProvider &provider, QWidget *valueEditor, QWidget *parent) { - auto *button = new QToolButton(parent); + auto *button = new styling::ToolButton(parent); button->setObjectName("inspectorSyncButton"); - button->setIcon( - styling::icon(styling::Icon::ArrowCounterClockwise, "#849589")); + button->setIcon(QIcon(":/editor/assets/link.svg")); button->setToolTip("Match this value with another property"); button->setPopupMode(QToolButton::InstantPopup); auto showMatch = [button, valueEditor](const QString &name) { @@ -860,12 +862,12 @@ QWidget *vectorField(const QJsonArray &value, const PropertyChanged &changed, auto *field = new QFrame(parent); field->setObjectName("inspectorVectorField"); auto *layout = new QHBoxLayout(field); - layout->setContentsMargins(3, 0, 3, 0); + layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(2); auto *valueEditor = new QWidget(field); auto *valueLayout = new QHBoxLayout(valueEditor); valueLayout->setContentsMargins(0, 0, 0, 0); - valueLayout->setSpacing(2); + valueLayout->setSpacing(6); layout->addWidget(valueEditor, 1); auto values = value; const int dimensions = std::clamp(static_cast(value.size()), 2, 3); @@ -874,15 +876,22 @@ QWidget *vectorField(const QJsonArray &value, const PropertyChanged &changed, const QStringList axes{"X", "Y", "Z"}; QList boxes; for (int index = 0; index < dimensions; ++index) { - auto *axis = new QLabel(axes.at(index), valueEditor); + auto *axisField = new QFrame(valueEditor); + axisField->setObjectName("inspectorAxisField"); + auto *axisLayout = new QHBoxLayout(axisField); + axisLayout->setContentsMargins(7, 0, 4, 0); + axisLayout->setSpacing(4); + auto *axis = new QLabel(axes.at(index), axisField); axis->setObjectName("inspectorAxis" + axes.at(index)); - auto *box = numberField(values.at(index).toDouble(), valueEditor); + axis->setFixedWidth(12); + auto *box = numberField(values.at(index).toDouble(), axisField); box->setButtonSymbols(QAbstractSpinBox::NoButtons); - box->setMinimumWidth(52); + box->setMinimumWidth(58); tagEditor(box, path, "vector", index); boxes.append(box); - valueLayout->addWidget(axis); - valueLayout->addWidget(box, 1); + axisLayout->addWidget(axis); + axisLayout->addWidget(box, 1); + valueLayout->addWidget(axisField, 1); } auto commit = [boxes, changed, path] { QJsonArray result; @@ -920,7 +929,7 @@ QWidget *colorField(const QJsonArray &value, const PropertyChanged &changed, ? std::clamp(static_cast(value.at(3).toDouble() * factor), 0, 255) : 255); - auto *swatch = new QPushButton(field); + auto *swatch = new styling::Button(field); swatch->setObjectName("inspectorColorSwatch"); swatch->setFixedSize(30, 22); auto *text = new QLineEdit(field); @@ -1054,15 +1063,20 @@ QWidget *primitiveField(const QString &name, const QString &path, QFrame *propertyRow(const QString &label, QWidget *editor, QWidget *parent) { auto *row = new QFrame(parent); row->setObjectName("inspectorPropertyRow"); - auto *layout = new QHBoxLayout(row); - layout->setContentsMargins(8, 3, 8, 3); - layout->setSpacing(8); - auto *name = new QLabel(label, row); + const bool wide = editor->objectName() == "inspectorVectorField" || + editor->objectName() == "inspectorColorField"; + QBoxLayout *layout = wide ? static_cast(new QVBoxLayout(row)) + : static_cast(new QHBoxLayout(row)); + layout->setContentsMargins(0, 5, 0, 5); + layout->setSpacing(wide ? 7 : 12); + auto *name = new styling::ElidedLabel(label, row); name->setObjectName("inspectorPropertyLabel"); - name->setMinimumWidth(82); - name->setMaximumWidth(108); + if (!wide) { + name->setMinimumWidth(90); + name->setMaximumWidth(112); + } layout->addWidget(name); - layout->addWidget(editor, 1); + layout->addWidget(editor, wide ? 0 : 1); return row; } @@ -1105,7 +1119,7 @@ void addPropertyRows(QVBoxLayout *layout, const QJsonObject &properties, headingLayout->setSpacing(4); auto *title = new QLabel(humanize(key), heading); title->setObjectName("inspectorNestedTitle"); - auto *add = new QToolButton(heading); + auto *add = new styling::ToolButton(heading); add->setObjectName("inspectorArrayButton"); add->setIcon(styling::icon(styling::Icon::Plus, "#8498A8")); add->setToolTip("Add item"); @@ -1136,7 +1150,7 @@ void addPropertyRows(QVBoxLayout *layout, const QJsonObject &properties, .arg(index + 1), itemHeading); itemTitle->setObjectName("inspectorArrayTitle"); - auto *remove = new QToolButton(itemHeading); + auto *remove = new styling::ToolButton(itemHeading); remove->setObjectName("inspectorArrayButton"); remove->setIcon( styling::icon(styling::Icon::Trash, "#A17F7F")); @@ -1283,14 +1297,14 @@ QFrame *componentCard(const QString &title, const QJsonObject &properties, card->setObjectName("inspectorComponent"); card->setProperty("inspectorScope", scope); auto *layout = new QVBoxLayout(card); - layout->setContentsMargins(0, 0, 0, 7); + layout->setContentsMargins(0, 10, 0, 4); layout->setSpacing(2); auto *headerRow = new QWidget(card); headerRow->setObjectName("inspectorComponentHeaderRow"); auto *headerLayout = new QHBoxLayout(headerRow); headerLayout->setContentsMargins(0, 0, 3, 0); headerLayout->setSpacing(2); - auto *header = new QToolButton(headerRow); + auto *header = new styling::ToolButton(headerRow); header->setObjectName("inspectorComponentHeader"); header->setText(title); header->setCheckable(true); @@ -1299,9 +1313,9 @@ QFrame *componentCard(const QString &title, const QJsonObject &properties, header->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); headerLayout->addWidget(header, 1); if (remove) { - auto *removeButton = new QToolButton(headerRow); + auto *removeButton = new styling::ToolButton(headerRow); removeButton->setObjectName("inspectorComponentRemoveButton"); - removeButton->setIcon(styling::icon(styling::Icon::Trash, "#A17F7F")); + removeButton->setIcon(QIcon(":/editor/assets/close.svg")); removeButton->setToolTip(QStringLiteral("Remove %1").arg(title)); headerLayout->addWidget(removeButton); QObject::connect(removeButton, &QToolButton::clicked, card, remove); @@ -1311,7 +1325,7 @@ QFrame *componentCard(const QString &title, const QJsonObject &properties, body->setObjectName("inspectorComponentBody"); auto *bodyLayout = new QVBoxLayout(body); bodyLayout->setContentsMargins(0, 2, 0, 0); - bodyLayout->setSpacing(1); + bodyLayout->setSpacing(5); addPropertyRows(bodyLayout, properties, path, changed, syncProvider, body); layout->addWidget(body); QObject::connect( @@ -1332,9 +1346,9 @@ QFrame *controllerActionsCard(const QJsonArray &actions, bool automaticMoving, card->setObjectName("inspectorComponent"); card->setProperty("inspectorScope", "camera:actions"); auto *layout = new QVBoxLayout(card); - layout->setContentsMargins(0, 0, 0, 7); + layout->setContentsMargins(0, 10, 0, 4); layout->setSpacing(2); - auto *header = new QToolButton(card); + auto *header = new styling::ToolButton(card); header->setObjectName("inspectorComponentHeader"); header->setText("Controller Actions"); header->setCheckable(true); @@ -1346,7 +1360,7 @@ QFrame *controllerActionsCard(const QJsonArray &actions, bool automaticMoving, body->setObjectName("inspectorComponentBody"); auto *bodyLayout = new QVBoxLayout(body); bodyLayout->setContentsMargins(0, 2, 0, 0); - bodyLayout->setSpacing(1); + bodyLayout->setSpacing(5); auto *automatic = new QCheckBox("Enable Automatic Movement", body); automatic->setChecked(automaticMoving); automatic->setCursor(Qt::PointingHandCursor); @@ -1359,7 +1373,7 @@ QFrame *controllerActionsCard(const QJsonArray &actions, bool automaticMoving, const QStringList labels{"Movement", "Look", "Vertical"}; QList pickers; for (int index = 0; index < labels.size(); ++index) { - auto *picker = new QToolButton(body); + auto *picker = new styling::ToolButton(body); picker->setObjectName("inspectorActionPicker"); picker->setPopupMode(QToolButton::InstantPopup); picker->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -1479,7 +1493,7 @@ InspectorPanel::InspectorPanel(ViewportPanel *viewport, const QString &projectFile, QWidget *parent) : QWidget(parent), viewport(viewport), projectFile(projectFile) { setObjectName("inspectorPanel"); - setMinimumWidth(400); + setMinimumWidth(360); setAcceptDrops(true); const QFileInfo projectInfo(projectFile); projectRoot = projectInfo.absoluteDir().absolutePath(); @@ -1492,8 +1506,8 @@ InspectorPanel::InspectorPanel(ViewportPanel *viewport, content = new QWidget(scrollArea); content->setObjectName("inspectorContent"); contentLayout = new QVBoxLayout(content); - contentLayout->setContentsMargins(8, 8, 8, 10); - contentLayout->setSpacing(8); + contentLayout->setContentsMargins(14, 4, 14, 16); + contentLayout->setSpacing(16); scrollArea->setWidget(content); layout->addWidget(scrollArea); if (viewport != nullptr) { @@ -1751,12 +1765,12 @@ void InspectorPanel::showObject(const QJsonObject &object) { auto *header = new QFrame(content); header->setObjectName("inspectorHeader"); auto *headerLayout = new QHBoxLayout(header); - headerLayout->setContentsMargins(10, 10, 10, 10); + headerLayout->setContentsMargins(0, 12, 0, 14); headerLayout->setSpacing(10); iconLabel = new QLabel(header); iconLabel->setObjectName("inspectorObjectIcon"); - iconLabel->setPixmap(inspectorIcon(this, type).pixmap(42, 42)); - iconLabel->setFixedSize(46, 46); + iconLabel->setPixmap(inspectorIcon(this, type).pixmap(28, 28)); + iconLabel->setFixedSize(32, 32); auto *identity = new QWidget(header); auto *identityLayout = new QVBoxLayout(identity); identityLayout->setContentsMargins(0, 0, 0, 0); @@ -1917,7 +1931,7 @@ void InspectorPanel::showObject(const QJsonObject &object) { for (int actionIndex = 0; actionIndex < audioActions.size(); ++actionIndex) { const QString &action = audioActions.at(actionIndex); - auto *button = new QToolButton(controls); + auto *button = new styling::ToolButton(controls); button->setIcon(styling::icon(audioIcons.at(actionIndex), audioColors.at(actionIndex))); button->setToolTip(action); @@ -1934,7 +1948,7 @@ void InspectorPanel::showObject(const QJsonObject &object) { contentLayout->addWidget(controls); } } - auto *addComponent = new QToolButton(content); + auto *addComponent = new styling::ToolButton(content); addComponent->setObjectName("inspectorAddComponentButton"); addComponent->setIcon(styling::icon(styling::Icon::Plus, "#8498A8")); addComponent->setText("Add Component"); @@ -2054,11 +2068,11 @@ void InspectorPanel::showCamera() { auto *header = new QFrame(content); header->setObjectName("inspectorHeader"); auto *headerLayout = new QHBoxLayout(header); - headerLayout->setContentsMargins(10, 10, 10, 10); + headerLayout->setContentsMargins(0, 12, 0, 14); headerLayout->setSpacing(10); auto *cameraIcon = new QLabel(header); cameraIcon->setObjectName("inspectorObjectIcon"); - cameraIcon->setPixmap(inspectorIcon(this, "camera").pixmap(42, 42)); + cameraIcon->setPixmap(inspectorIcon(this, "camera").pixmap(28, 28)); cameraIcon->setFixedSize(46, 46); auto *identity = new QWidget(header); auto *identityLayout = new QVBoxLayout(identity); @@ -2074,7 +2088,7 @@ void InspectorPanel::showCamera() { headerLayout->addWidget(identity, 1); contentLayout->addWidget(header); - auto *cameraView = new QToolButton(content); + auto *cameraView = new styling::ToolButton(content); cameraView->setObjectName("inspectorAddComponentButton"); cameraView->setCheckable(true); cameraView->setChecked(viewport != nullptr && viewport->isCameraFocused()); @@ -2156,12 +2170,12 @@ void InspectorPanel::showEnvironment() { auto *header = new QFrame(content); header->setObjectName("inspectorHeader"); auto *headerLayout = new QHBoxLayout(header); - headerLayout->setContentsMargins(10, 10, 10, 10); + headerLayout->setContentsMargins(0, 12, 0, 14); headerLayout->setSpacing(10); auto *environmentIcon = new QLabel(header); environmentIcon->setObjectName("inspectorObjectIcon"); environmentIcon->setPixmap( - inspectorIcon(this, "environment").pixmap(42, 42)); + inspectorIcon(this, "environment").pixmap(28, 28)); environmentIcon->setFixedSize(46, 46); auto *identity = new QWidget(header); auto *identityLayout = new QVBoxLayout(identity); @@ -2288,13 +2302,13 @@ void InspectorPanel::showFile() { auto *header = new QFrame(content); header->setObjectName("inspectorHeader"); auto *headerLayout = new QHBoxLayout(header); - headerLayout->setContentsMargins(10, 10, 10, 10); + headerLayout->setContentsMargins(0, 12, 0, 14); headerLayout->setSpacing(10); iconLabel = new QLabel(header); iconLabel->setObjectName("inspectorObjectIcon"); const QString iconType = info.isDir() ? "folder" : info.suffix(); - iconLabel->setPixmap(inspectorIcon(this, iconType).pixmap(42, 42)); - iconLabel->setFixedSize(46, 46); + iconLabel->setPixmap(inspectorIcon(this, iconType).pixmap(28, 28)); + iconLabel->setFixedSize(32, 32); auto *identity = new QWidget(header); auto *identityLayout = new QVBoxLayout(identity); identityLayout->setContentsMargins(0, 0, 0, 0); @@ -2381,7 +2395,7 @@ void InspectorPanel::showFile() { } } } - auto *open = new QPushButton("Open in Default App", content); + auto *open = new styling::Button("Open in Default App", content); open->setObjectName("inspectorOpenAssetButton"); connect(open, &QPushButton::clicked, this, [this] { QDesktopServices::openUrl(QUrl::fromLocalFile(inspectedFile)); diff --git a/editor/views/editor/materialEditor.cpp b/editor/views/editor/materialEditor.cpp index 5ad0d9f0..fd7ea709 100644 --- a/editor/views/editor/materialEditor.cpp +++ b/editor/views/editor/materialEditor.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + #include #include #include @@ -345,15 +347,15 @@ MaterialEditorPanel::MaterialEditorPanel(ViewportPanel *viewport, auto *header = new QWidget(this); header->setObjectName("materialEditorHeader"); auto *headerLayout = new QHBoxLayout(header); - headerLayout->setContentsMargins(8, 4, 8, 4); + headerLayout->setContentsMargins(12, 6, 12, 6); titleLabel = new QLabel("Material Editor", header); titleLabel->setObjectName("materialEditorTitle"); statusLabel = new QLabel(header); statusLabel->setObjectName("materialEditorStatus"); - auto *saveButton = new QPushButton("Save", header); + auto *saveButton = new styling::Button("Save", header); saveButton->setObjectName("materialSaveButton"); saveButton->setIcon(styling::icon(styling::Icon::FloppyDisk, "#A1957D")); - auto *assignButton = new QPushButton("Assign to Selected", header); + auto *assignButton = new styling::Button("Assign to Selected", header); assignButton->setObjectName("materialAssignButton"); assignButton->setIcon(styling::icon(styling::Icon::Assign, "#9E897D")); headerLayout->addWidget(titleLabel, 1); @@ -370,7 +372,7 @@ MaterialEditorPanel::MaterialEditorPanel(ViewportPanel *viewport, body->setObjectName("materialEditorBody"); bodyLayout = new QVBoxLayout(body); bodyLayout->setContentsMargins(10, 10, 10, 12); - bodyLayout->setSpacing(9); + bodyLayout->setSpacing(12); scroll->setWidget(body); layout->addWidget(scroll, 1); @@ -556,7 +558,7 @@ void MaterialEditorPanel::showMaterial() { auto *surface = new QGroupBox("Surface", properties); auto *surfaceForm = new QFormLayout(surface); - albedoButton = new QPushButton(surface); + albedoButton = new styling::Button(surface); displayColor(albedoButton, jsonColor(material.value("albedo"), QColor(204, 204, 204))); metallicField = scalarField(0.0, 1.0, 0.01, surface); @@ -576,7 +578,7 @@ void MaterialEditorPanel::showMaterial() { auto *emission = new QGroupBox("Emission", properties); auto *emissionForm = new QFormLayout(emission); - emissiveButton = new QPushButton(emission); + emissiveButton = new styling::Button(emission); displayColor(emissiveButton, jsonColor(material.value("emissiveColor"), Qt::black)); emissiveIntensityField = scalarField(0.0, 100.0, 0.1, emission); @@ -651,11 +653,11 @@ void MaterialEditorPanel::showMaterial() { field->setObjectName("materialTexturePath"); field->setReadOnly(true); field->setPlaceholderText("No image"); - auto *choose = new QToolButton(row); + auto *choose = new styling::ToolButton(row); choose->setText("Choose…"); choose->setIcon(styling::icon(styling::Icon::FolderOpen, "#7E929C")); choose->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - auto *clear = new QToolButton(row); + auto *clear = new styling::ToolButton(row); clear->setIcon(styling::icon(styling::Icon::Close, "#A17F7F")); clear->setToolTip("Remove texture"); auto *identity = new QWidget(row); diff --git a/editor/views/editor/postProcessing.cpp b/editor/views/editor/postProcessing.cpp index 24e9199b..1043e56f 100644 --- a/editor/views/editor/postProcessing.cpp +++ b/editor/views/editor/postProcessing.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + #include #include #include @@ -97,18 +99,18 @@ PostProcessingPanel::PostProcessingPanel(ViewportPanel *viewport, auto *toolbar = new QWidget(this); toolbar->setObjectName("postProcessingToolbar"); auto *toolbarLayout = new QHBoxLayout(toolbar); - toolbarLayout->setContentsMargins(8, 4, 8, 4); + toolbarLayout->setContentsMargins(12, 6, 12, 6); toolbarLayout->setSpacing(4); - auto *title = new QLabel("Post Processing", toolbar); + auto *title = new QLabel("Effects", toolbar); title->setObjectName("postProcessingTitle"); targetSelector = new QComboBox(toolbar); targetSelector->setMinimumWidth(180); - auto *addTargetButton = new QToolButton(toolbar); + auto *addTargetButton = new styling::ToolButton(toolbar); addTargetButton->setIcon( styling::icon(styling::Icon::Plus, "#8498A8")); addTargetButton->setText("Target"); addTargetButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - removeTargetButton = new QToolButton(toolbar); + removeTargetButton = new styling::ToolButton(toolbar); removeTargetButton->setText("Remove"); removeTargetButton->setIcon( styling::icon(styling::Icon::Trash, "#A17F7F")); @@ -130,7 +132,7 @@ PostProcessingPanel::PostProcessingPanel(ViewportPanel *viewport, body->setObjectName("postProcessingBody"); bodyLayout = new QVBoxLayout(body); bodyLayout->setContentsMargins(12, 12, 12, 14); - bodyLayout->setSpacing(9); + bodyLayout->setSpacing(12); scroll->setWidget(body); layout->addWidget(scroll, 1); @@ -249,7 +251,7 @@ void PostProcessingPanel::rebuildEditor() { effectsHeadingLayout->setContentsMargins(0, 4, 0, 0); auto *effectsTitle = new QLabel("Effect Stack", effectsHeading); effectsTitle->setObjectName("postProcessingSectionTitle"); - auto *addEffectButton = new QToolButton(effectsHeading); + auto *addEffectButton = new styling::ToolButton(effectsHeading); addEffectButton->setIcon( styling::icon(styling::Icon::Plus, "#8498A8")); addEffectButton->setText("Add Effect"); @@ -333,19 +335,19 @@ void PostProcessingPanel::rebuildEditor() { auto *actionsLayout = new QHBoxLayout(actions); actionsLayout->setContentsMargins(0, 0, 0, 0); actionsLayout->setSpacing(4); - auto *moveUp = new QToolButton(actions); + auto *moveUp = new styling::ToolButton(actions); moveUp->setText("Move Up"); moveUp->setIcon( styling::icon(styling::Icon::CaretUp, "#7E929C")); moveUp->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); moveUp->setEnabled(effectIndex > 0); - auto *moveDown = new QToolButton(actions); + auto *moveDown = new styling::ToolButton(actions); moveDown->setText("Move Down"); moveDown->setIcon( styling::icon(styling::Icon::CaretDown, "#7E929C")); moveDown->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); moveDown->setEnabled(effectIndex + 1 < effectStack.size()); - auto *remove = new QToolButton(actions); + auto *remove = new styling::ToolButton(actions); remove->setText("Remove Effect"); remove->setIcon( styling::icon(styling::Icon::Trash, "#A17F7F")); diff --git a/editor/views/editor/viewport.cpp b/editor/views/editor/viewport.cpp index a302a471..65b1c435 100644 --- a/editor/views/editor/viewport.cpp +++ b/editor/views/editor/viewport.cpp @@ -813,6 +813,8 @@ void ViewportPanel::showEvent(QShowEvent *event) { if (playbackState == 1) captureRuntimeInput(); if (runtimeContext != nullptr) { + runtimeContext->setEditorPathTracingPreview(pbrPreview); + runtimeContext->setEditorShadingMode(shadingMode); frameTimer->start(RuntimeFrameIntervalMs); return; } diff --git a/editor/views/editor/viewportTools.cpp b/editor/views/editor/viewportTools.cpp index d22a09dd..76764e28 100644 --- a/editor/views/editor/viewportTools.cpp +++ b/editor/views/editor/viewportTools.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + #include #include @@ -89,26 +91,26 @@ ViewportTools::ViewportTools(ViewportPanel *viewport, auto *toolbar = new QWidget(this); toolbar->setObjectName("viewportToolbar"); auto *tools = new QHBoxLayout(toolbar); - tools->setContentsMargins(5, 3, 5, 3); - tools->setSpacing(2); + tools->setContentsMargins(8, 4, 8, 4); + tools->setSpacing(3); - playButton = new QToolButton(toolbar); + playButton = new styling::ToolButton(toolbar); playButton->setObjectName("viewportPlaybackButton"); playButton->setIcon(styling::icon(styling::Icon::Play, "#849589")); playButton->setToolTip("Play"); - pauseButton = new QToolButton(toolbar); + pauseButton = new styling::ToolButton(toolbar); pauseButton->setObjectName("viewportPlaybackButton"); pauseButton->setIcon(styling::icon(styling::Icon::Pause, "#A1957D")); pauseButton->setToolTip("Pause"); - stepButton = new QToolButton(toolbar); + stepButton = new styling::ToolButton(toolbar); stepButton->setObjectName("viewportPlaybackButton"); stepButton->setIcon(styling::icon(styling::Icon::SkipForward, "#7E929C")); stepButton->setToolTip("Step one frame"); - stopButton = new QToolButton(toolbar); + stopButton = new styling::ToolButton(toolbar); stopButton->setObjectName("viewportPlaybackButton"); stopButton->setIcon(styling::icon(styling::Icon::Stop, "#A17F7F")); stopButton->setToolTip("Stop and restore the scene"); - reloadButton = new QToolButton(toolbar); + reloadButton = new styling::ToolButton(toolbar); reloadButton->setObjectName("viewportPlaybackButton"); reloadButton->setIcon( styling::icon(styling::Icon::ArrowCounterClockwise, "#71889A")); @@ -123,10 +125,10 @@ ViewportTools::ViewportTools(ViewportPanel *viewport, const QList transformIcons{ styling::Icon::CursorClick, styling::Icon::ArrowsOutCardinal, styling::Icon::ArrowClockwise, styling::Icon::BoundingBox}; - const QList transformColors{QColor("#7E929C"), QColor("#849589"), - QColor("#A1957D"), QColor("#71889A")}; + const QList transformColors{QColor("#C8C7BF"), QColor("#C8C7BF"), + QColor("#C8C7BF"), QColor("#C8C7BF")}; for (int index = 0; index < transformNames.size(); ++index) { - auto *button = new QToolButton(toolbar); + auto *button = new styling::ToolButton(toolbar); button->setObjectName("viewportModeButton"); button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setCheckable(true); @@ -145,13 +147,13 @@ ViewportTools::ViewportTools(ViewportPanel *viewport, } tools->addSpacing(10); - spaceButton = new QToolButton(toolbar); + spaceButton = new styling::ToolButton(toolbar); spaceButton->setObjectName("viewportOptionButton"); spaceButton->setIcon(styling::icon(styling::Icon::Globe, "#7E929C")); spaceButton->setToolTip("World transform space · Shift+T"); tools->addWidget(spaceButton); - cameraButton = new QToolButton(toolbar); + cameraButton = new styling::ToolButton(toolbar); cameraButton->setObjectName("viewportOptionButton"); cameraButton->setIcon(styling::icon(styling::Icon::Camera, "#9E897D")); cameraButton->setCheckable(true); @@ -204,7 +206,7 @@ ViewportTools::ViewportTools(ViewportPanel *viewport, styling::Icon::CubeTransparent, styling::Icon::DotsNine}; for (int index = 0; index < shadingNames.size(); ++index) { - auto *button = new QToolButton(toolbar); + auto *button = new styling::ToolButton(toolbar); button->setObjectName("viewportShadingButton"); button->setToolButtonStyle(pathTracingProject ? Qt::ToolButtonTextBesideIcon @@ -225,7 +227,7 @@ ViewportTools::ViewportTools(ViewportPanel *viewport, } } - auto *fpsButton = new QToolButton(toolbar); + auto *fpsButton = new styling::ToolButton(toolbar); fpsButton->setObjectName("viewportOptionButton"); fpsButton->setIcon(styling::icon(styling::Icon::Monitor, "#849589")); fpsButton->setCheckable(true); @@ -241,12 +243,12 @@ ViewportTools::ViewportTools(ViewportPanel *viewport, viewportHost = new ViewportHost(viewport, cameraAspect, this); layout->addWidget(viewportHost, 1); shortcutHint = - new QLabel("Tab Frame · Num 0 Camera · Shift+Middle/Right Pan · " - "Middle/Right Orbit · G Move · R Rotate · S Scale · X " - "Delete", - this); + new QLabel("Orbit Middle drag Pan Shift + drag Frame Tab", this); shortcutHint->setObjectName("viewportShortcutHint"); shortcutHint->setTextInteractionFlags(Qt::NoTextInteraction); + shortcutHint->setContentsMargins(12, 5, 12, 5); + shortcutHint->setToolTip("Tab Frame · Num 0 Camera · Shift+Middle/Right Pan · " + "Middle/Right Orbit · G Move · R Rotate · S Scale · X Delete"); layout->addWidget(shortcutHint); connect(playButton, &QToolButton::clicked, viewport, diff --git a/editor/views/general/contentBrowser.cpp b/editor/views/general/contentBrowser.cpp index e2ecbd1e..323c92dc 100644 --- a/editor/views/general/contentBrowser.cpp +++ b/editor/views/general/contentBrowser.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + /* * contentBrowser.cpp * As part of the Atlas project @@ -215,7 +217,7 @@ ContentBrowserPanel::ContentBrowserPanel(const QString &projectFile, } auto *layout = new QVBoxLayout(this); - layout->setContentsMargins(4, 4, 4, 4); + layout->setContentsMargins(6, 6, 6, 6); layout->setSpacing(4); auto *toolbar = new QWidget(this); @@ -224,17 +226,17 @@ ContentBrowserPanel::ContentBrowserPanel(const QString &projectFile, toolbarLayout->setContentsMargins(0, 0, 0, 0); toolbarLayout->setSpacing(4); - backButton = new QToolButton(toolbar); + backButton = new styling::ToolButton(toolbar); backButton->setObjectName("browserNavigationButton"); backButton->setIcon( styling::icon(styling::Icon::ArrowLeft, "#AAB4C4")); backButton->setToolTip("Back"); - forwardButton = new QToolButton(toolbar); + forwardButton = new styling::ToolButton(toolbar); forwardButton->setObjectName("browserNavigationButton"); forwardButton->setIcon( styling::icon(styling::Icon::ArrowRight, "#AAB4C4")); forwardButton->setToolTip("Forward"); - upButton = new QToolButton(toolbar); + upButton = new styling::ToolButton(toolbar); upButton->setObjectName("browserNavigationButton"); upButton->setIcon(styling::icon(styling::Icon::ArrowUp, "#AAB4C4")); upButton->setToolTip("Parent Folder"); @@ -245,24 +247,24 @@ ContentBrowserPanel::ContentBrowserPanel(const QString &projectFile, searchField = new QLineEdit(toolbar); searchField->setObjectName("contentSearchField"); - searchField->setPlaceholderText("Search"); + searchField->setPlaceholderText("Filter assets…"); searchField->setClearButtonEnabled(true); searchField->setMaximumWidth(180); - createButton = new QToolButton(toolbar); + createButton = new styling::ToolButton(toolbar); createButton->setObjectName("panelAddButton"); createButton->setIcon(styling::icon(styling::Icon::Plus, "#8498A8")); createButton->setText("Create"); createButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); createButton->setPopupMode(QToolButton::InstantPopup); - revealButton = new QToolButton(toolbar); + revealButton = new styling::ToolButton(toolbar); revealButton->setObjectName("browserRevealButton"); revealButton->setIcon( styling::icon(styling::Icon::FolderOpen, "#7E929C")); revealButton->setToolTip("Reveal in Finder"); - moreButton = new QToolButton(toolbar); + moreButton = new styling::ToolButton(toolbar); moreButton->setObjectName("panelMoreButton"); moreButton->setIcon( styling::icon(styling::Icon::DotsVertical, "#8490A4")); @@ -301,10 +303,10 @@ ContentBrowserPanel::ContentBrowserPanel(const QString &projectFile, gridView->setWrapping(true); gridView->setResizeMode(QListView::Adjust); gridView->setMovement(QListView::Static); - gridView->setGridSize(QSize(154, 118)); - gridView->setIconSize(QSize(50, 50)); + gridView->setGridSize(QSize(128, 106)); + gridView->setIconSize(QSize(42, 42)); gridView->setWordWrap(true); - gridView->setTextElideMode(Qt::ElideNone); + gridView->setTextElideMode(Qt::ElideMiddle); gridView->setSelectionMode(QAbstractItemView::ExtendedSelection); gridView->setDragEnabled(true); gridView->setDragDropMode(QAbstractItemView::DragOnly); diff --git a/editor/views/general/inputActionsDialog.cpp b/editor/views/general/inputActionsDialog.cpp index bb06ccf8..fed06db5 100644 --- a/editor/views/general/inputActionsDialog.cpp +++ b/editor/views/general/inputActionsDialog.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + #include #include @@ -178,6 +180,7 @@ void InputActionsDialog::setupUi() { root->setSpacing(12); auto *heading = new QLabel("Controller Actions", this); + heading->setObjectName("dialogHeroTitle"); QFont headingFont = heading->font(); headingFont.setPointSizeF(18); headingFont.setWeight(QFont::DemiBold); @@ -207,7 +210,7 @@ void InputActionsDialog::setupUi() { sidebarLayout->addWidget(actionList, 1); auto *sidebarButtons = new QHBoxLayout(); - auto *addButton = new QPushButton("Add", sidebar); + auto *addButton = new styling::Button("Add", sidebar); auto *addMenu = new QMenu(addButton); addMenu->addAction("Button", this, [this] { addAction(ActionKind::Button); }); @@ -216,8 +219,8 @@ void InputActionsDialog::setupUi() { addMenu->addAction("2D Axis", this, [this] { addAction(ActionKind::Axis2D); }); addButton->setMenu(addMenu); - duplicateButton = new QPushButton("Duplicate", sidebar); - removeButton = new QPushButton("Remove", sidebar); + duplicateButton = new styling::Button("Duplicate", sidebar); + removeButton = new styling::Button("Remove", sidebar); sidebarButtons->addWidget(addButton); sidebarButtons->addWidget(duplicateButton); sidebarButtons->addWidget(removeButton); @@ -261,8 +264,8 @@ void InputActionsDialog::setupUi() { buttonBindings->setSelectionMode(QAbstractItemView::SingleSelection); buttonLayout->addWidget(buttonBindings); auto *bindingButtons = new QHBoxLayout(); - auto *addBindingButton = new QPushButton("Add Binding", buttonPage); - auto *removeBindingButton = new QPushButton("Remove Binding", buttonPage); + auto *addBindingButton = new styling::Button("Add Binding", buttonPage); + auto *removeBindingButton = new styling::Button("Remove Binding", buttonPage); bindingButtons->addWidget(addBindingButton); bindingButtons->addWidget(removeBindingButton); bindingButtons->addStretch(); diff --git a/editor/views/general/projectBrowser.cpp b/editor/views/general/projectBrowser.cpp index ace9a885..1c43c1b7 100644 --- a/editor/views/general/projectBrowser.cpp +++ b/editor/views/general/projectBrowser.cpp @@ -1,3 +1,5 @@ +#include "editor/styling/workbench.h" + #include #include @@ -14,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -173,7 +177,7 @@ class CreateProjectDialog : public QDialog { } locationField->setText(defaultLocation); locationLayout->addWidget(locationField, 1); - auto *browse = new QPushButton("Browse…", this); + auto *browse = new styling::Button("Browse…", this); browse->setProperty("secondary", true); browse->setIcon(styling::icon(styling::Icon::FolderOpen, "#7E929C")); locationLayout->addWidget(browse); @@ -188,10 +192,10 @@ class CreateProjectDialog : public QDialog { auto *actions = new QHBoxLayout(); actions->addStretch(); - auto *cancel = new QPushButton("Cancel", this); + auto *cancel = new styling::Button("Cancel", this); cancel->setProperty("secondary", true); actions->addWidget(cancel); - createButton = new QPushButton("Create project", this); + createButton = new styling::Button("Create project", this); createButton->setObjectName("primaryAction"); createButton->setIcon( styling::icon(styling::Icon::RocketLaunch, "#FFFFFF")); @@ -269,12 +273,12 @@ class ProjectRow : public QFrame { auto *copy = new QVBoxLayout(); copy->setSpacing(3); - auto *title = new QLabel(project.name, this); + auto *title = new styling::ElidedLabel(project.name, this); title->setObjectName("projectName"); copy->addWidget(title); - auto *path = new QLabel(project.directory, this); + auto *path = new styling::ElidedLabel(project.directory, this); path->setObjectName("projectPath"); - path->setTextInteractionFlags(Qt::TextSelectableByMouse); + copy->addWidget(path); layout->addLayout(copy, 1); @@ -283,7 +287,7 @@ class ProjectRow : public QFrame { layout->addWidget(renderer); auto *date = - new QLabel(project.lastModified.isValid() + new QLabel(project.available && project.lastModified.isValid() ? project.lastModified.toString("d MMM yyyy") : QStringLiteral("Unavailable"), this); @@ -291,7 +295,7 @@ class ProjectRow : public QFrame { date->setMinimumWidth(90); layout->addWidget(date); - moreButton = new QToolButton(this); + moreButton = new styling::ToolButton(this); moreButton->setObjectName("projectMoreButton"); moreButton->setIcon( styling::icon(styling::Icon::DotsVertical, "#8490A4")); @@ -318,32 +322,23 @@ void ProjectBrowser::setupUi() { auto *root = new QWidget(this); root->setObjectName("projectBrowserRoot"); setCentralWidget(root); - auto *rootLayout = new QHBoxLayout(root); - rootLayout->setContentsMargins(0, 0, 0, 0); - rootLayout->setSpacing(0); + auto *rootLayout = new QVBoxLayout(root); + rootLayout->setContentsMargins(10, 10, 10, 10); + rootLayout->setSpacing(10); auto *sidebar = new QFrame(root); sidebar->setObjectName("projectSidebar"); - sidebar->setFixedWidth(224); - auto *sidebarLayout = new QVBoxLayout(sidebar); - sidebarLayout->setContentsMargins(22, 26, 22, 22); + sidebar->setFixedHeight(70); + auto *sidebarLayout = new QHBoxLayout(sidebar); + sidebarLayout->setContentsMargins(18, 8, 18, 8); sidebarLayout->setSpacing(18); auto *brandLayout = new QHBoxLayout(); brandLayout->setSpacing(11); auto *brandIcon = new QLabel(sidebar); brandIcon->setFixedSize(38, 38); -#ifdef ATLAS_DEBUG_BUILD - brandIcon->setPixmap( - QPixmap(":/editor/assets/Icon-iOS-Default-1024x1024@1x.png") - .scaled(brandIcon->size(), Qt::KeepAspectRatio, - Qt::SmoothTransformation)); -#else - brandIcon->setPixmap( - QPixmap(":/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png") - .scaled(brandIcon->size(), Qt::KeepAspectRatio, - Qt::SmoothTransformation)); -#endif + brandIcon->setPixmap(styling::brandMark(brandIcon->size())); + brandLayout->addWidget(brandIcon); auto *brandCopy = new QVBoxLayout(); brandCopy->setSpacing(0); @@ -357,19 +352,17 @@ void ProjectBrowser::setupUi() { brandLayout->addStretch(); sidebarLayout->addLayout(brandLayout); - auto *projectsNav = new QPushButton("Projects", sidebar); - projectsNav->setObjectName("projectNavSelected"); - projectsNav->setIcon(styling::icon(styling::Icon::SquaresFour, "#8498A8")); - projectsNav->setEnabled(false); - sidebarLayout->addWidget(projectsNav); sidebarLayout->addStretch(); + auto *sidebarCaption = new QLabel("Your next world starts here.", sidebar); + sidebarCaption->setObjectName("projectSidebarCaption"); + sidebarLayout->addWidget(sidebarCaption); rootLayout->addWidget(sidebar); auto *content = new QWidget(root); content->setObjectName("projectBrowserContent"); auto *contentLayout = new QVBoxLayout(content); - contentLayout->setContentsMargins(34, 30, 34, 30); + contentLayout->setContentsMargins(38, 32, 38, 24); contentLayout->setSpacing(20); auto *headingLayout = new QHBoxLayout(); @@ -384,11 +377,11 @@ void ProjectBrowser::setupUi() { headingCopy->addWidget(subtitle); headingLayout->addLayout(headingCopy, 1); - auto *openButton = new QPushButton("Open existing", content); + auto *openButton = new styling::Button("Open existing", content); openButton->setProperty("secondary", true); openButton->setIcon(styling::icon(styling::Icon::FolderOpen, "#7E929C")); headingLayout->addWidget(openButton); - auto *createButton = new QPushButton("New project", content); + auto *createButton = new styling::Button("New project", content); createButton->setObjectName("primaryAction"); createButton->setIcon(styling::icon(styling::Icon::Plus, "#FFFFFF")); headingLayout->addWidget(createButton); @@ -398,12 +391,16 @@ void ProjectBrowser::setupUi() { searchField->setObjectName("projectSearch"); searchField->setPlaceholderText("Search projects"); searchField->setClearButtonEnabled(true); + searchField->addAction(styling::icon(styling::Icon::MagnifyingGlass), QLineEdit::LeadingPosition); contentLayout->addWidget(searchField); + auto *sectionLabel = new QLabel("Recent projects", content); + sectionLabel->setObjectName("projectSectionLabel"); + contentLayout->addWidget(sectionLabel); projectStack = new QStackedWidget(content); projectList = new QListWidget(projectStack); projectList->setObjectName("projectList"); - projectList->setSpacing(8); + projectList->setSpacing(3); projectList->setSelectionMode(QAbstractItemView::SingleSelection); projectList->setContextMenuPolicy(Qt::CustomContextMenu); projectList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -426,6 +423,9 @@ void ProjectBrowser::setupUi() { emptyLayout->addStretch(); projectStack->addWidget(empty); contentLayout->addWidget(projectStack, 1); + auto *listHint = new QLabel("Double-click a project to open it · Return to continue", content); + listHint->setObjectName("projectListHint"); + contentLayout->addWidget(listHint); rootLayout->addWidget(content, 1); connect(createButton, &QPushButton::clicked, this, @@ -434,6 +434,23 @@ void ProjectBrowser::setupUi() { &ProjectBrowser::openExistingProject); connect(searchField, &QLineEdit::textChanged, this, &ProjectBrowser::filterProjects); + connect(projectList, &QListWidget::currentItemChanged, this, + [this](QListWidgetItem *current, QListWidgetItem *previous) { + for (auto *item : {previous, current}) { + if (item == nullptr) + continue; + auto *row = projectList->itemWidget(item); + if (row == nullptr) + continue; + row->setProperty("selected", item == current); + row->style()->unpolish(row); + row->style()->polish(row); + row->update(); + } + }); + auto *openShortcut = new QShortcut(QKeySequence(Qt::Key_Return), projectList); + openShortcut->setContext(Qt::WidgetWithChildrenShortcut); + connect(openShortcut, &QShortcut::activated, this, &ProjectBrowser::openSelectedProject); connect(projectList, &QListWidget::itemDoubleClicked, this, [this] { openSelectedProject(); }); connect(projectList, &QListWidget::customContextMenuRequested, this, @@ -447,7 +464,7 @@ void ProjectBrowser::reloadProjects() { auto *item = new QListWidgetItem(projectList); item->setData(ProjectPathRole, project.projectFile); item->setData(ProjectAvailableRole, project.available); - item->setSizeHint(QSize(0, 76)); + item->setSizeHint(QSize(0, 82)); auto *row = new ProjectRow(project, projectList); projectList->setItemWidget(item, row); connect(row->optionsButton(), &QToolButton::clicked, this, diff --git a/editor/views/general/splashScreen.cpp b/editor/views/general/splashScreen.cpp index 0868f40b..facf4750 100644 --- a/editor/views/general/splashScreen.cpp +++ b/editor/views/general/splashScreen.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -23,11 +24,11 @@ SplashScreen::SplashScreen(QWidget *parent) setAttribute(Qt::WA_TranslucentBackground); setModal(true); setObjectName("atlasSplash"); - setFixedSize(708, 252); + setFixedSize(640, 280); auto *card = new QFrame(this); card->setObjectName("splashCard"); - card->setGeometry(0, 0, 708, 252); + card->setGeometry(0, 0, 640, 280); auto *shadow = new QGraphicsDropShadowEffect(card); shadow->setBlurRadius(20.0); shadow->setOffset(0.0, 5.0); @@ -36,41 +37,28 @@ SplashScreen::SplashScreen(QWidget *parent) auto *icon = new QLabel(card); icon->setObjectName("splashIcon"); - icon->setGeometry(30, 38, 108, 108); -#ifdef ATLAS_DEBUG_BUILD - icon->setPixmap(QPixmap(":/editor/assets/Icon-iOS-Default-1024x1024@1x.png") - .scaled(icon->size(), Qt::KeepAspectRatio, - Qt::SmoothTransformation)); -#else - icon->setPixmap( - QPixmap(":/editor/assets/iconFile-iOS-Dark-1024x1024@1x.png") - .scaled(icon->size(), Qt::KeepAspectRatio, - Qt::SmoothTransformation)); -#endif + icon->setGeometry(30, 44, 104, 104); + icon->setPixmap(styling::brandMark(icon->size())); auto *title = new QLabel(card); title->setObjectName("splashTitle"); - title->setGeometry(164, 42, 514, 44); + title->setGeometry(158, 44, 444, 48); QFont titleFont = title->font(); titleFont.setLetterSpacing(QFont::AbsoluteSpacing, -0.3); titleFont.setKerning(true); -#ifdef ATLAS_RELEASE_BUILD title->setText("Atlas Engine"); -#else - title->setText("Atlas Engine (Development)"); title->setFont(titleFont); -#endif title->setWordWrap(false); title->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); auto *version = new QLabel(card); version->setObjectName("splashVersion"); - version->setGeometry(164, 86, 500, 28); + version->setGeometry(160, 100, 440, 24); #ifdef ATLAS_RELEASE_BUILD version->setText(QStringLiteral(ATLAS_VERSION)); #else - version->setText(QStringLiteral("%1 (build %2)") + version->setText(QStringLiteral("%1 · Development %2") .arg(QStringLiteral(ATLAS_VERSION), QStringLiteral(ATLAS_BUILD_STRING))); #endif @@ -78,85 +66,28 @@ SplashScreen::SplashScreen(QWidget *parent) auto *company = new QLabel("by neutral software", card); company->setObjectName("splashCompany"); - company->setGeometry(164, 114, 400, 22); + company->setGeometry(160, 128, 440, 22); company->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); statusLabel = new QLabel("Loading the engine…", card); statusLabel->setObjectName("splashStatus"); - statusLabel->setGeometry(164, 151, 500, 22); + statusLabel->setGeometry(36, 198, 568, 24); statusLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); auto *progress = new QProgressBar(card); progress->setObjectName("splashProgress"); - progress->setGeometry(164, 181, 500, 5); + progress->setGeometry(36, 232, 568, 4); progress->setRange(0, 0); progress->setTextVisible(false); #ifndef ATLAS_RELEASE_BUILD - auto *warning = new QLabel( - "As this software is in its development version issues may be found " - "with the experience. If you meant to use the traditional version " - "please access: https://atlasengine.org to get the official builds. " - "In development versions, the engine may require you to have a " - "runtime already installed therefore, make sure that you have an " - "appropriate runtime in your system that works with this version.", - card); + auto *warning = new QLabel("Development build · atlasengine.org", card); warning->setObjectName("splashWarning"); - warning->setGeometry(40, 199, 628, 44); + warning->setGeometry(36, 246, 568, 20); warning->setWordWrap(true); warning->setAlignment(Qt::AlignLeft | Qt::AlignTop); #endif - setStyleSheet(R"( -#atlasSplash { - background: transparent; -} -#splashCard { - background: #202224; - border: 1px solid #494D52; - border-radius: 18px; -} -#splashTitle { - background: transparent; - color: #F5F7FA; - font-size: 34px; - font-weight: 750; -} -#splashVersion { - background: transparent; - color: #8498A8; - font-size: 14px; - font-weight: 700; -} -#splashCompany { - background: transparent; - color: #7F8B9D; - font-family: "Manrope"; - font-size: 12px; - font-weight: 650; -} -#splashStatus { - background: transparent; - color: #B7C1CF; - font-size: 10px; - font-weight: 550; -} -#splashProgress { - background: #34373A; - border: none; - border-radius: 2px; -} -#splashProgress::chunk { - background: #71889A; - border-radius: 2px; -} -#splashWarning { - background: transparent; - color: #68758A; - font-size: 9px; - font-weight: 450; -} -)"); } void SplashScreen::start(const QString &statusText) { diff --git a/include/atlas/runtime/context.h b/include/atlas/runtime/context.h index a5f789f0..319e530a 100644 --- a/include/atlas/runtime/context.h +++ b/include/atlas/runtime/context.h @@ -89,6 +89,7 @@ class Context { bool cameraAutomaticMoving = false; bool editorCameraFocused = false; bool editorRuntime = false; + bool editorPathTracingPreview = true; bool materialPreviewRuntime = false; float materialPreviewYaw = 0.0f; float materialPreviewPitch = 0.0f; diff --git a/include/editor/core/themes.h b/include/editor/core/themes.h index 451ecf9b..7915d3f7 100644 --- a/include/editor/core/themes.h +++ b/include/editor/core/themes.h @@ -7,154 +7,60 @@ inline constexpr const char* DARK_THEME = "* {\n" " font-family: \"SF Pro Text\", \"Inter\", \"Segoe UI\", \"Arial\";\n" -" font-size: 11px;\n" -" color: #D6D6D6;\n" -" selection-background-color: #4772B3;\n" -" selection-color: #FFFFFF;\n" +" font-size: 13px;\n" +" color: #C5C5BE;\n" +" selection-background-color: #353532;\n" +" selection-color: #F1F1EC;\n" "}\n" "\n" "QWidget {\n" -" background-color: #1C1C1C;\n" -" color: #D6D6D6;\n" +" background: #191918;\n" "}\n" "\n" "QMainWindow,\n" "QDialog,\n" -"QFrame {\n" -" background-color: #1C1C1C;\n" +"#editorFrame,\n" +"#projectBrowserRoot {\n" +" background: #121211;\n" "}\n" "\n" -"QLabel {\n" +"QLabel,\n" +"QCheckBox,\n" +"QRadioButton,\n" +"QToolButton,\n" +"QPushButton {\n" " background: transparent;\n" "}\n" "\n" "QLabel:disabled {\n" -" color: #566174;\n" -"}\n" -"\n" -"QToolTip {\n" -" background-color: #303030;\n" -" color: #F7F9FC;\n" -" border: 1px solid #505050;\n" -" border-radius: 4px;\n" -" padding: 4px 6px;\n" -"}\n" -"\n" -"QGroupBox {\n" -" background-color: #242424;\n" -" border: 1px solid #3B3B3B;\n" -" border-radius: 4px;\n" -" margin-top: 13px;\n" -" padding: 7px;\n" -" color: #F1F4F8;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"QGroupBox::title {\n" -" subcontrol-origin: margin;\n" -" subcontrol-position: top left;\n" -" left: 9px;\n" -" padding: 0 6px;\n" -" color: #AEB8C8;\n" -" background-color: #242424;\n" -"}\n" -"\n" -"QScrollArea,\n" -"QAbstractScrollArea {\n" -" background-color: #202020;\n" -" border: none;\n" -"}\n" -"\n" -"QAbstractScrollArea::corner {\n" -" background-color: #202020;\n" -"}\n" -"\n" -"QScrollBar:vertical {\n" -" background-color: transparent;\n" -" width: 9px;\n" -" margin: 2px;\n" -" border: none;\n" -"}\n" -"\n" -"QScrollBar:horizontal {\n" -" background-color: transparent;\n" -" height: 9px;\n" -" margin: 2px;\n" -" border: none;\n" -"}\n" -"\n" -"QScrollBar::handle:vertical,\n" -"QScrollBar::handle:horizontal {\n" -" background-color: #4A4A4A;\n" -" border-radius: 4px;\n" -" min-height: 30px;\n" -" min-width: 30px;\n" -"}\n" -"\n" -"QScrollBar::handle:vertical:hover,\n" -"QScrollBar::handle:horizontal:hover {\n" -" background-color: #666666;\n" +" color: #62625D;\n" "}\n" "\n" -"QScrollBar::add-line,\n" -"QScrollBar::sub-line,\n" -"QScrollBar::add-page,\n" -"QScrollBar::sub-page {\n" -" background: none;\n" -" border: none;\n" -" width: 0;\n" -" height: 0;\n" +"QLabel[muted=\"true\"] {\n" +" color: #92928B;\n" "}\n" "\n" "QPushButton,\n" "QToolButton {\n" -" background-color: #303030;\n" -" border: 1px solid #464646;\n" -" border-radius: 3px;\n" -" padding: 3px 8px;\n" -" color: #D8D8D8;\n" -" min-height: 22px;\n" -" font-weight: 500;\n" +" border: none;\n" +" border-radius: 7px;\n" +" padding: 5px 10px;\n" +" min-height: 24px;\n" "}\n" "\n" "QPushButton:hover,\n" "QToolButton:hover {\n" -" background-color: #3A3A3A;\n" -" border-color: #606060;\n" -"}\n" -"\n" -"QPushButton:pressed,\n" -"QToolButton:pressed {\n" -" background-color: #242424;\n" -" border-color: #4772B3;\n" +" background: #292928;\n" "}\n" "\n" "QPushButton:checked,\n" "QToolButton:checked {\n" -" background-color: #3B5F8A;\n" -" border-color: #5D8BC0;\n" -" color: #FFFFFF;\n" -"}\n" -"\n" -"QPushButton:default,\n" -"#primaryAction {\n" -" background-color: #4772B3;\n" -" border-color: #6791C9;\n" -" color: #FFFFFF;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"QPushButton:default:hover,\n" -"#primaryAction:hover {\n" -" background-color: #5682C2;\n" -" border-color: #7AA1D4;\n" +" background: #30302E;\n" "}\n" "\n" "QPushButton:disabled,\n" "QToolButton:disabled {\n" -" background-color: #242424;\n" -" border-color: #333333;\n" -" color: #686868;\n" +" color: #646460;\n" "}\n" "\n" "QToolButton::menu-indicator {\n" @@ -163,1015 +69,670 @@ inline constexpr const char* DARK_THEME = "\n" "QLineEdit,\n" "QTextEdit,\n" -"QPlainTextEdit,\n" +"QPlainTextEdit {\n" +" background: #20201F;\n" +" border: 1px solid transparent;\n" +" border-radius: 6px;\n" +" padding: 7px 9px;\n" +" selection-background-color: #42423E;\n" +"}\n" +"\n" +"QLineEdit:hover,\n" +"QTextEdit:hover,\n" +"QPlainTextEdit:hover {\n" +" background: #242423;\n" +"}\n" +"\n" +"QLineEdit:focus,\n" +"QTextEdit:focus,\n" +"QPlainTextEdit:focus {\n" +" border-color: #53534D;\n" +"}\n" +"\n" +"QLineEdit:disabled,\n" +"QTextEdit:disabled,\n" +"QPlainTextEdit:disabled {\n" +" color: #666660;\n" +"}\n" +"\n" "QComboBox,\n" "QSpinBox,\n" "QDoubleSpinBox,\n" "QDateEdit,\n" "QTimeEdit,\n" "QDateTimeEdit {\n" -" background-color: #181818;\n" -" border: 1px solid #3D3D3D;\n" -" border-radius: 3px;\n" -" padding: 3px 7px;\n" -" color: #E2E2E2;\n" -" min-height: 22px;\n" +" background: #252524;\n" +" border: 1px solid transparent;\n" +" border-radius: 5px;\n" +" min-height: 24px;\n" +" padding: 3px 8px;\n" +" color: #D3D3CC;\n" "}\n" "\n" -"QLineEdit:hover,\n" -"QTextEdit:hover,\n" -"QPlainTextEdit:hover,\n" "QComboBox:hover,\n" "QSpinBox:hover,\n" "QDoubleSpinBox:hover {\n" -" border-color: #5A5A5A;\n" +" background: #2B2B29;\n" "}\n" "\n" -"QLineEdit:focus,\n" -"QTextEdit:focus,\n" -"QPlainTextEdit:focus,\n" "QComboBox:focus,\n" "QSpinBox:focus,\n" "QDoubleSpinBox:focus {\n" -" background-color: #222222;\n" -" border-color: #5D8BC0;\n" +" border-color: #666660;\n" "}\n" "\n" -"QLineEdit:disabled,\n" -"QTextEdit:disabled,\n" "QComboBox:disabled,\n" "QSpinBox:disabled,\n" "QDoubleSpinBox:disabled {\n" -" background-color: #202020;\n" -" border-color: #303030;\n" -" color: #666666;\n" +" color: #666660;\n" "}\n" "\n" "QComboBox {\n" -" padding-right: 24px;\n" +" padding-right: 28px;\n" "}\n" "\n" "QComboBox::drop-down {\n" -" subcontrol-origin: padding;\n" -" subcontrol-position: top right;\n" -" width: 22px;\n" -" border-left: 1px solid #3B3B3B;\n" +" width: 26px;\n" +" border: none;\n" "}\n" "\n" -"QComboBox QAbstractItemView {\n" -" background-color: #292929;\n" -" border: 1px solid #4B4B4B;\n" -" border-radius: 4px;\n" -" padding: 3px;\n" -" selection-background-color: #3B5F8A;\n" +"QComboBox::down-arrow,\n" +"QAbstractSpinBox::down-arrow {\n" +" image: url(:/editor/assets/chevron-down.svg);\n" +" width: 12px;\n" +" height: 12px;\n" +"}\n" +"\n" +"QAbstractSpinBox::up-arrow {\n" +" image: url(:/editor/assets/chevron-up.svg);\n" +" width: 12px;\n" +" height: 12px;\n" "}\n" "\n" "QAbstractSpinBox::up-button,\n" "QAbstractSpinBox::down-button {\n" -" background-color: #292929;\n" +" background: transparent;\n" " border: none;\n" -" width: 16px;\n" +" width: 18px;\n" "}\n" "\n" -"QAbstractSpinBox::up-button:hover,\n" -"QAbstractSpinBox::down-button:hover {\n" -" background-color: #3E3E3E;\n" +"QComboBox QAbstractItemView {\n" +" background: #222221;\n" +" border: 1px solid #393936;\n" +" border-radius: 8px;\n" +" padding: 5px;\n" "}\n" "\n" "QCheckBox,\n" "QRadioButton {\n" -" spacing: 7px;\n" -" color: #C9D1DE;\n" +" spacing: 9px;\n" "}\n" "\n" -"QCheckBox::indicator,\n" -"QRadioButton::indicator {\n" -" width: 15px;\n" -" height: 15px;\n" -" background-color: #171717;\n" -" border: 1px solid #555555;\n" -" border-radius: 3px;\n" +"QCheckBox::indicator {\n" +" width: 16px;\n" +" height: 16px;\n" +" border: 1px solid #55554F;\n" +" border-radius: 4px;\n" +" background: #232322;\n" "}\n" "\n" -"QCheckBox::indicator:hover,\n" -"QRadioButton::indicator:hover {\n" -" border-color: #777777;\n" +"QCheckBox::indicator:hover {\n" +" border-color: #999991;\n" +"}\n" +"\n" +"QCheckBox::indicator:checked {\n" +" image: url(:/editor/assets/check.svg);\n" +" background: #74746C;\n" +" border-color: #999991;\n" +"}\n" +"\n" +"QCheckBox::indicator:indeterminate {\n" +" background: #999991;\n" +" border: 4px solid #44443F;\n" +"}\n" +"\n" +"QRadioButton::indicator {\n" +" width: 16px;\n" +" height: 16px;\n" +" background: #232322;\n" +" border: 1px solid #55554F;\n" +" border-radius: 9px;\n" "}\n" "\n" -"QCheckBox::indicator:checked,\n" "QRadioButton::indicator:checked {\n" -" background-color: #4772B3;\n" -" border-color: #6D98CE;\n" +" width: 8px;\n" +" height: 8px;\n" +" background: #DDDDD5;\n" +" border: 5px solid #55554F;\n" +" border-radius: 9px;\n" "}\n" "\n" "QSlider::groove:horizontal {\n" -" background-color: #353535;\n" -" height: 4px;\n" -" border-radius: 2px;\n" +" height: 3px;\n" +" background: #343431;\n" +" border-radius: 1px;\n" +"}\n" +"\n" +"QSlider::sub-page:horizontal {\n" +" background: #93938A;\n" +" border-radius: 1px;\n" "}\n" "\n" "QSlider::handle:horizontal {\n" -" background-color: #5D8BC0;\n" -" border: 2px solid #A0B9D7;\n" -" width: 12px;\n" -" margin: -5px 0;\n" -" border-radius: 7px;\n" +" background: #D5D5CD;\n" +" border: none;\n" +" width: 10px;\n" +" margin: -4px 0;\n" +" border-radius: 5px;\n" "}\n" "\n" "QProgressBar {\n" -" background-color: #262626;\n" -" border: 1px solid #424242;\n" +" background: #292927;\n" +" border: none;\n" " border-radius: 3px;\n" -" height: 8px;\n" +" min-height: 6px;\n" " text-align: center;\n" +" color: #F1F1EC;\n" "}\n" "\n" "QProgressBar::chunk {\n" -" background-color: #4772B3;\n" +" background: #76766D;\n" +" border-radius: 3px;\n" +"}\n" +"\n" +"QScrollArea,\n" +"QAbstractScrollArea {\n" +" background: #191918;\n" +" border: none;\n" +"}\n" +"\n" +"QAbstractScrollArea::corner {\n" +" background: transparent;\n" +"}\n" +"\n" +"QScrollBar:vertical {\n" +" background: transparent;\n" +" border: none;\n" +" width: 8px;\n" +" margin: 3px 1px;\n" +"}\n" +"\n" +"QScrollBar:horizontal {\n" +" background: transparent;\n" +" border: none;\n" +" height: 8px;\n" +" margin: 1px 3px;\n" +"}\n" +"\n" +"QScrollBar::handle:vertical,\n" +"QScrollBar::handle:horizontal {\n" +" background: #3B3B36;\n" " border-radius: 3px;\n" +" min-height: 32px;\n" +" min-width: 32px;\n" +"}\n" +"\n" +"QScrollBar::handle:vertical:hover,\n" +"QScrollBar::handle:horizontal:hover {\n" +" background: #606059;\n" +"}\n" +"\n" +"QScrollBar::add-line,\n" +"QScrollBar::sub-line,\n" +"QScrollBar::add-page,\n" +"QScrollBar::sub-page {\n" +" border: none;\n" +" background: transparent;\n" +" width: 0;\n" +" height: 0;\n" "}\n" "\n" "QTreeView,\n" "QListView,\n" -"QListWidget,\n" -"QTableView,\n" -"QTableWidget {\n" -" background-color: #202020;\n" -" alternate-background-color: #242424;\n" +"QTableView {\n" +" background: #191918;\n" " border: none;\n" -" color: #DCE3EC;\n" +" outline: none;\n" +" alternate-background-color: #1D1D1C;\n" " show-decoration-selected: 1;\n" "}\n" "\n" "QTreeView::item,\n" "QListView::item,\n" -"QListWidget::item,\n" -"QTableView::item,\n" -"QTableWidget::item {\n" -" border: 1px solid transparent;\n" -" border-radius: 2px;\n" -" padding: 3px 5px;\n" -"}\n" -"\n" -"QTreeView::item:hover,\n" -"QListView::item:hover,\n" -"QListWidget::item:hover,\n" -"QTableView::item:hover,\n" -"QTableWidget::item:hover {\n" -" background-color: #303030;\n" -" border-color: #464646;\n" +"QTableView::item {\n" +" border: none;\n" +" padding: 5px 8px;\n" "}\n" "\n" "QTreeView::item:selected,\n" "QListView::item:selected,\n" -"QListWidget::item:selected,\n" -"QTableView::item:selected,\n" -"QTableWidget::item:selected {\n" -" background-color: #3B5F8A;\n" -" border-color: #5D8BC0;\n" -" color: #FFFFFF;\n" +"QTableView::item:selected {\n" +" background: #30302E;\n" +" color: #F1F1EC;\n" "}\n" "\n" -"QHeaderView {\n" -" background-color: #202020;\n" +"QHeaderView::section {\n" +" background: #191918;\n" +" border: none;\n" +" border-bottom: 1px solid #2B2B28;\n" +" color: #92928B;\n" +" padding: 9px;\n" +" font-weight: 400;\n" "}\n" "\n" -"QHeaderView::section {\n" -" background-color: #292929;\n" +"QGroupBox {\n" +" background: transparent;\n" " border: none;\n" -" border-right: 1px solid #404040;\n" -" border-bottom: 1px solid #404040;\n" -" padding: 5px 7px;\n" -" color: #98A4B7;\n" -" font-weight: 600;\n" +" border-top: 1px solid #2B2B28;\n" +" margin-top: 26px;\n" +" padding: 14px 2px 6px 2px;\n" +" font-weight: 500;\n" +"}\n" +"\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top left;\n" +" padding: 0;\n" +" color: #DDDDD6;\n" "}\n" "\n" "QTabWidget::pane {\n" -" background-color: #202020;\n" -" border: 1px solid #3B3B3B;\n" -" border-radius: 0;\n" +" background: #191918;\n" +" border: none;\n" +"}\n" +"\n" +"QTabBar {\n" +" background: transparent;\n" "}\n" "\n" "QTabBar::tab {\n" -" background-color: #252525;\n" +" background: transparent;\n" " border: none;\n" -" border-right: 1px solid #393939;\n" -" border-bottom: 1px solid #3B3B3B;\n" -" color: #7F8B9D;\n" -" min-width: 88px;\n" -" padding: 5px 10px;\n" -" margin: 1px 0;\n" -" border-radius: 0;\n" +" color: #92928B;\n" +" padding: 9px 16px;\n" +" margin: 4px 3px;\n" +" border-radius: 6px;\n" "}\n" "\n" -"QTabBar::tab:hover {\n" -" background-color: #303030;\n" -" color: #C8D1DF;\n" +"QTabBar::tab:selected {\n" +" background: #2B2B29;\n" +" color: #EAEAE3;\n" "}\n" "\n" -"QTabBar::tab:selected {\n" -" background-color: #333333;\n" -" color: #F2F5F9;\n" -" border-bottom: 2px solid #5D8BC0;\n" +"QTabBar::tab:hover {\n" +" color: #EAEAE3;\n" "}\n" "\n" -"QMenuBar#atlasMenuBar {\n" -" background-color: #181818;\n" -" border-bottom: 1px solid #303030;\n" -" padding: 1px 6px;\n" +"QMenuBar {\n" +" background: #121211;\n" +" border: none;\n" +" padding: 3px 10px;\n" "}\n" "\n" -"QMenuBar#atlasMenuBar::item {\n" +"QMenuBar::item {\n" " background: transparent;\n" -" color: #B8C2D0;\n" " padding: 5px 9px;\n" -" border-radius: 3px;\n" "}\n" "\n" -"QMenuBar#atlasMenuBar::item:selected,\n" -"QMenuBar#atlasMenuBar::item:pressed {\n" -" background-color: #343434;\n" -" color: #FFFFFF;\n" +"QMenuBar::item:selected {\n" +" background: #2B2B29;\n" +" border-radius: 5px;\n" "}\n" "\n" "QMenu {\n" -" background-color: #292929;\n" -" border: 1px solid #515151;\n" -" border-radius: 4px;\n" -" padding: 4px;\n" +" background: #20201F;\n" +" border: 1px solid #393936;\n" +" border-radius: 8px;\n" +" padding: 6px;\n" "}\n" "\n" "QMenu::item {\n" " background: transparent;\n" -" border-radius: 2px;\n" -" padding: 6px 32px 6px 9px;\n" -" color: #DCE3EC;\n" +" padding: 9px 34px 9px 12px;\n" +" border-radius: 5px;\n" "}\n" "\n" "QMenu::item:selected {\n" -" background-color: #3B5F8A;\n" -" color: #FFFFFF;\n" +" background: #33332F;\n" "}\n" "\n" "QMenu::item:disabled {\n" -" color: #596477;\n" +" color: #64645E;\n" "}\n" "\n" "QMenu::separator {\n" -" background-color: #424242;\n" +" background: #343431;\n" " height: 1px;\n" -" margin: 5px 8px;\n" +" margin: 6px 10px;\n" "}\n" "\n" -"QSplitter::handle {\n" -" background-color: #111111;\n" -"}\n" -"\n" -"QSplitter::handle:horizontal {\n" -" width: 4px;\n" +"QToolTip {\n" +" background: #292927;\n" +" color: #E1E1DA;\n" +" border: 1px solid #44443E;\n" +" border-radius: 5px;\n" +" padding: 6px 9px;\n" "}\n" "\n" -"QSplitter::handle:vertical {\n" -" height: 4px;\n" +"QSplitter::handle {\n" +" background: #121211;\n" "}\n" "\n" "QSplitter::handle:hover {\n" -" background-color: #5D8BC0;\n" +" background: #41413C;\n" "}\n" "\n" "QStatusBar {\n" -" background-color: #181818;\n" -" border-top: 1px solid #303030;\n" -" color: #8490A4;\n" +" background: #121211;\n" +" color: #888882;\n" +" border: none;\n" +" padding: 3px 14px;\n" +" min-height: 24px;\n" +" font-size: 11px;\n" +"}\n" +"\n" +"QStatusBar::item {\n" +" border: none;\n" "}\n" "\n" -"#atlasStatusBar {\n" -" min-height: 23px;\n" -" padding: 0 6px;\n" +"#workspaceBar,\n" +"#workspaceChrome,\n" +"#workspaceIdentity,\n" +"#workspaceIdentityText,\n" +"#workspaceActivity,\n" +"#workspaceUtilities {\n" +" background: #121211;\n" +" border: none;\n" "}\n" "\n" -"#statusRuntimeIcon {\n" +"#workspaceBar {\n" " padding: 0;\n" +" spacing: 0;\n" "}\n" "\n" -"#statusRuntime {\n" -" background: transparent;\n" -" border-right: 1px solid #343434;\n" +"#workspaceProject {\n" +" color: #D7D7D0;\n" +" font-size: 13px;\n" "}\n" "\n" -"#statusRuntimeText {\n" -" color: #9BA79F;\n" -" font-size: 10px;\n" +"#workspaceSwitcher,\n" +"#workspaceSurface,\n" +"#workspaceHeading,\n" +"#editorWorkspaceStack {\n" +" background: #191918;\n" +" border: none;\n" "}\n" "\n" -"#statusRenderer {\n" -" background-color: #292929;\n" -" border: 1px solid #454545;\n" -" border-radius: 3px;\n" -" color: #B6BCB8;\n" -" font-size: 9px;\n" -" font-weight: 700;\n" -" padding: 2px 6px;\n" +"#workspaceHeading {\n" +" border-bottom: 1px solid #282825;\n" "}\n" "\n" -"#statusVersion {\n" -" color: #68758A;\n" -" font-size: 9px;\n" -" padding: 0 6px;\n" +"#workspaceSwitcher {\n" +" padding: 0;\n" "}\n" "\n" -"#workspaceBar {\n" -" background-color: #202020;\n" +"#workspaceMark {\n" +" background: transparent;\n" " border: none;\n" -" border-bottom: 1px solid #3B3B3B;\n" -" spacing: 4px;\n" -" padding: 3px 6px 3px 0;\n" -" min-height: 38px;\n" "}\n" "\n" -"#workspaceIdentity {\n" +"#workspaceContextPath,\n" +"#statusVersion,\n" +"#statusRenderer,\n" +"#statusRuntimeText,\n" +"#viewportFpsLabel,\n" +"#viewportShortcutHint {\n" " background: transparent;\n" -" border-right: 1px solid #424242;\n" +" color: #898982;\n" +" font-size: 11px;\n" +" border: none;\n" "}\n" "\n" -"#workspaceMark {\n" -" background-color: #292929;\n" -" border: 1px solid #3F3F3F;\n" -" border-radius: 4px;\n" -" padding: 3px;\n" +"#statusRuntime {\n" +" background: transparent;\n" "}\n" "\n" -"#workspaceIdentityText {\n" -" background: transparent;\n" +"#sceneTabs {\n" +" background: #191918;\n" +" border: none;\n" "}\n" "\n" -"#workspaceBrand {\n" -" color: #8C8C8C;\n" -" font-size: 8px;\n" -" font-weight: 750;\n" +"#sceneTabs::tab {\n" +" padding: 9px 14px;\n" +" min-width: 92px;\n" "}\n" "\n" -"#workspaceProject {\n" -" color: #EFEFEF;\n" -" font-size: 12px;\n" -" font-weight: 650;\n" +"#viewportTools {\n" +" background: #191918;\n" "}\n" "\n" -"#workspaceSwitcher {\n" -" background-color: #181818;\n" -" border: 1px solid #383838;\n" -" border-radius: 4px;\n" -" margin-left: 7px;\n" +"#viewportToolbar,\n" +"#panelToolbar,\n" +"#materialEditorHeader,\n" +"#postProcessingToolbar,\n" +"#workspaceToolbar {\n" +" background: #191918;\n" +" border: none;\n" "}\n" "\n" -"#workspaceModeButton {\n" -" background-color: #222222;\n" -" border: 1px solid transparent;\n" -" border-radius: 3px;\n" -" color: #A0A0A0;\n" -" padding: 3px 9px;\n" -" min-height: 22px;\n" +"#hierarchySearch,\n" +"#contentSearchField {\n" +" background: #222221;\n" +" padding: 6px 9px;\n" "}\n" "\n" -"#workspaceModeButton:hover {\n" -" background-color: #333333;\n" -" color: #E2E2E2;\n" +"#contentPathField {\n" +" background: transparent;\n" +" border: none;\n" +" color: #A7A7A0;\n" "}\n" "\n" -"#workspaceModeButton:checked {\n" -" background-color: #3B5F8A;\n" -" border-color: #5D8BC0;\n" -" color: #FFFFFF;\n" +"#inspectorScroll,\n" +"#inspectorContent,\n" +"#materialEditorBody,\n" +"#postProcessingBody,\n" +"#environmentPages,\n" +"#environmentWorkspace,\n" +"#environmentPage {\n" +" background: #191918;\n" +" border: none;\n" "}\n" "\n" -"#workspaceCommandButton,\n" -"#workspaceUtilityButton,\n" -"#workspaceBuildButton,\n" -"#workspaceLaunchButton {\n" -" min-width: 42px;\n" -" padding: 3px 9px;\n" -" margin-left: 2px;\n" -" min-height: 24px;\n" -"}\n" -"\n" -"#workspaceCommandButton,\n" -"#workspaceUtilityButton,\n" -"#workspaceBuildButton {\n" -" background-color: #292929;\n" -" border-color: #444444;\n" -"}\n" -"\n" -"#workspaceLaunchButton {\n" -" background-color: #3F684F;\n" -" border-color: #5A8B6B;\n" -" color: #FFFFFF;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"#workspaceCommandButton:hover,\n" -"#workspaceUtilityButton:hover,\n" -"#workspaceBuildButton:hover,\n" -"#workspaceLaunchButton:hover {\n" -" background-color: #3A3A3A;\n" -" border-color: #606060;\n" -"}\n" -"\n" -"#workspaceLaunchButton:hover {\n" -" background-color: #4E7B5E;\n" -" border-color: #6B9B79;\n" -"}\n" -"\n" -"#workspaceContextBar {\n" -" background-color: #292929;\n" -" border: none;\n" -" border-bottom: 1px solid #3C3C3C;\n" -" spacing: 2px;\n" -" padding: 1px 5px 1px 0;\n" -" min-height: 27px;\n" -"}\n" -"\n" -"#workspaceBreadcrumb {\n" -" background: transparent;\n" -" border-right: 1px solid #414141;\n" -"}\n" -"\n" -"#workspaceContextIcon {\n" +"#inspectorHeader {\n" " background: transparent;\n" -"}\n" -"\n" -"#workspaceContextTitle {\n" -" color: #E0E0E0;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"#workspaceContextPath {\n" -" color: #7F7F7F;\n" -"}\n" -"\n" -"#workspacePanelButton {\n" -" background-color: transparent;\n" -" border-color: transparent;\n" -" color: #8F8F8F;\n" -" padding: 2px 7px;\n" -" min-height: 20px;\n" -"}\n" -"\n" -"#workspacePanelButton:hover {\n" -" background-color: #363636;\n" -" color: #DADADA;\n" -"}\n" -"\n" -"#workspacePanelButton:checked {\n" -" background-color: #333333;\n" -" border-color: #4A4A4A;\n" -" color: #EAEAEA;\n" -"}\n" -"\n" -"#sceneTabs {\n" -" background-color: #181818;\n" -" border-bottom: 1px solid #3B3B3B;\n" -"}\n" -"\n" -"#sceneTabs::tab {\n" -" background-color: #242424;\n" -" border-right: 1px solid #3A3A3A;\n" -" color: #7F8B9D;\n" -" min-width: 112px;\n" -" padding: 5px 10px;\n" -" margin: 0;\n" -" border-radius: 0;\n" -"}\n" -"\n" -"#sceneTabs::tab:selected {\n" -" background-color: #333333;\n" -" color: #F3F6FA;\n" -" border-bottom: 2px solid #5D8BC0;\n" -"}\n" -"\n" -"#viewportTools {\n" -" background-color: #151515;\n" -"}\n" -"\n" -"#viewportToolbar {\n" -" background-color: #292929;\n" -" border-bottom: 1px solid #3B3B3B;\n" -"}\n" -"\n" -"#viewportPlaybackButton,\n" -"#viewportModeButton,\n" -"#viewportOptionButton,\n" -"#viewportShadingButton {\n" -" background-color: #292C2F;\n" -" border-color: #414549;\n" -" min-width: 25px;\n" -" min-height: 22px;\n" -" padding: 3px 5px;\n" -"}\n" -"\n" -"#viewportPlaybackButton:hover,\n" -"#viewportModeButton:hover,\n" -"#viewportOptionButton:hover,\n" -"#viewportShadingButton:hover {\n" -" background-color: #363A3E;\n" -" border-color: #5A5F65;\n" -"}\n" -"\n" -"#viewportModeButton:checked,\n" -"#viewportShadingButton:checked {\n" -" background-color: #3A4248;\n" -" border-color: #6F7B84;\n" -"}\n" -"\n" -"#viewportFpsLabel {\n" -" color: #9CA5A0;\n" -" font-size: 10px;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"#viewportShortcutHint {\n" -" background-color: #141517;\n" -" border-top: 1px solid #303236;\n" -" color: #68758A;\n" -" font-size: 10px;\n" -" padding: 3px 7px;\n" -"}\n" -"\n" -"#panelToolbar,\n" -"#materialEditorHeader,\n" -"#postProcessingToolbar,\n" -"#workspaceToolbar {\n" -" background-color: #292929;\n" -" border-bottom: 1px solid #404040;\n" -" padding: 2px;\n" -"}\n" -"\n" -"#panelAddButton,\n" -"#materialSaveButton,\n" -"#workspaceApplyButton {\n" -" background-color: #333333;\n" -" border-color: #4C4C4C;\n" -" color: #D8DBDE;\n" -"}\n" -"\n" -"#panelMoreButton,\n" -"#browserNavigationButton,\n" -"#browserRevealButton {\n" -" background-color: transparent;\n" -" border-color: transparent;\n" -" min-width: 24px;\n" -"}\n" -"\n" -"#panelMoreButton:hover,\n" -"#browserNavigationButton:hover,\n" -"#browserRevealButton:hover {\n" -" background-color: #34373A;\n" -" border-color: #484C50;\n" -"}\n" -"\n" -"#contentPathField {\n" -" background-color: #1B1D1F;\n" -" color: #8490A4;\n" -" font-size: 11px;\n" -"}\n" -"\n" -"#contentSearchField {\n" -" min-width: 130px;\n" -"}\n" -"\n" -"QTreeView#hierarchyTree {\n" -" background-color: #202020;\n" -" border-top: 1px solid #303030;\n" -" padding: 3px 2px;\n" -"}\n" -"\n" -"QTreeView#hierarchyTree::item {\n" -" min-height: 22px;\n" -" padding: 1px 6px;\n" -"}\n" -"\n" -"QTreeView#hierarchyTree::item:hover {\n" -" background-color: #303030;\n" -" border-color: #444444;\n" -"}\n" -"\n" -"QTreeView#hierarchyTree::item:selected {\n" -" background-color: #3B5F8A;\n" -" border-color: #5D8BC0;\n" -" color: #FFFFFF;\n" -"}\n" -"\n" -"QListView#contentGrid {\n" -" background-color: #1C1C1C;\n" -" border-top: 1px solid #303030;\n" -" padding: 5px;\n" -"}\n" -"\n" -"QListView#contentGrid::item {\n" -" background-color: #252525;\n" -" border: 1px solid #363636;\n" -" border-radius: 4px;\n" -" padding: 6px;\n" -" color: #BCC6D4;\n" -"}\n" -"\n" -"QListView#contentGrid::item:hover {\n" -" background-color: #303030;\n" -" border-color: #505050;\n" -"}\n" -"\n" -"QListView#contentGrid::item:selected {\n" -" background-color: #3B5F8A;\n" -" border-color: #5D8BC0;\n" -" color: #FFFFFF;\n" -"}\n" -"\n" -"QScrollArea#inspectorScroll,\n" -"#inspectorContent,\n" -"#materialEditorBody,\n" -"#postProcessingBody {\n" -" background-color: #202020;\n" " border: none;\n" -"}\n" -"\n" -"#inspectorHeader {\n" -" background-color: #292929;\n" -" border: 1px solid #414141;\n" -" border-radius: 4px;\n" -" padding: 5px;\n" +" padding: 0;\n" "}\n" "\n" "#inspectorObjectIcon {\n" -" background-color: #343434;\n" -" border: 1px solid #4E4E4E;\n" -" border-radius: 4px;\n" -" padding: 4px;\n" +" background: transparent;\n" +" border: none;\n" "}\n" "\n" "#inspectorNameField {\n" " background: transparent;\n" " border: 1px solid transparent;\n" -" color: #F3F6FA;\n" -" font-size: 14px;\n" -" font-weight: 700;\n" +" color: #EAEAE3;\n" +" font-size: 18px;\n" +" font-weight: 500;\n" +" padding: 2px 0;\n" "}\n" "\n" -"#inspectorNameField:hover,\n" "#inspectorNameField:focus {\n" -" background-color: #202020;\n" -" border-color: #5A5A5A;\n" +" border-color: #55554F;\n" "}\n" "\n" -"#inspectorTypeLabel {\n" -" color: #7E8A9E;\n" -" font-size: 10px;\n" -" font-weight: 600;\n" +"#inspectorTypeLabel,\n" +"#inspectorPropertyLabel,\n" +"#materialTexturePath,\n" +"#materialEditorStatus,\n" +"#postProcessingStatus,\n" +"#workspaceStatus,\n" +"#workspaceAutoApply {\n" +" color: #93938C;\n" +" font-size: 12px;\n" "}\n" "\n" "#inspectorComponent {\n" -" background-color: #242424;\n" -" border: 1px solid #3D3D3D;\n" -" border-radius: 3px;\n" -" margin-top: 2px;\n" -"}\n" -"\n" -"#inspectorComponentHeaderRow {\n" -" background-color: #2D2D2D;\n" -" border-bottom: 1px solid #3B3B3B;\n" -" border-radius: 3px 3px 0 0;\n" -"}\n" -"\n" -"#inspectorComponentHeader {\n" " background: transparent;\n" " border: none;\n" -" color: #E8ECF2;\n" -" font-weight: 650;\n" -" text-align: left;\n" -" padding: 4px 7px;\n" -"}\n" -"\n" -"#inspectorComponentHeader:hover {\n" -" background-color: #383838;\n" +" border-top: 1px solid #2C2C29;\n" +" border-radius: 0;\n" "}\n" "\n" -"#inspectorComponentRemoveButton {\n" +"#inspectorComponentHeaderRow,\n" +"#inspectorComponentBody,\n" +"#inspectorPropertyRow,\n" +"#inspectorNestedGroup,\n" +"#inspectorAudioControls {\n" " background: transparent;\n" " border: none;\n" -" min-width: 22px;\n" -"}\n" -"\n" -"#inspectorComponentRemoveButton:hover {\n" -" background-color: #3A3031;\n" -" border: 1px solid #695556;\n" -"}\n" -"\n" -"#inspectorComponentBody {\n" -" background-color: #242424;\n" -" padding: 4px;\n" -"}\n" -"\n" -"#inspectorPropertyRow {\n" -" background: transparent;\n" -" min-height: 27px;\n" -"}\n" -"\n" -"#inspectorPropertyLabel {\n" -" color: #929EB0;\n" -" font-size: 11px;\n" "}\n" "\n" "#inspectorVectorField,\n" -"#inspectorColorField,\n" -"#inspectorNumericField {\n" -" background-color: #181818;\n" -" border: 1px solid #3D3D3D;\n" -" border-radius: 3px;\n" +"#inspectorNumericField,\n" +"#inspectorColorField {\n" +" background: #252524;\n" +" border: none;\n" +" border-radius: 5px;\n" "}\n" "\n" "#inspectorVectorField QDoubleSpinBox,\n" "#inspectorNumericField QDoubleSpinBox {\n" " background: transparent;\n" " border: none;\n" +" padding: 4px 2px;\n" "}\n" "\n" "#inspectorAxisX,\n" "#inspectorAxisY,\n" "#inspectorAxisZ {\n" -" border-radius: 2px;\n" -" color: #F1F1F1;\n" -" font-size: 9px;\n" -" font-weight: 750;\n" -" padding: 2px 5px;\n" -"}\n" -"\n" -"#inspectorAxisX {\n" -" background-color: #874747;\n" -"}\n" -"\n" -"#inspectorAxisY {\n" -" background-color: #477451;\n" -"}\n" -"\n" -"#inspectorAxisZ {\n" -" background-color: #435E86;\n" -"}\n" -"\n" -"#inspectorSyncButton,\n" -"#inspectorArrayButton {\n" " background: transparent;\n" -" border-color: transparent;\n" -" min-width: 22px;\n" +" font-size: 10px;\n" +" padding: 0 3px;\n" "}\n" "\n" -"#inspectorSyncButton[matched=\"true\"] {\n" -" background-color: #343936;\n" -" border-color: #555F59;\n" -" color: #B6BEB9;\n" -"}\n" +"#inspectorAxisX { color: #CA9290; }\n" +"#inspectorAxisY { color: #9AB696; }\n" +"#inspectorAxisZ { color: #91A9C7; }\n" "\n" "#inspectorColorSwatch {\n" -" background-color: #292929;\n" -" border: 1px solid #4D4D4D;\n" -" border-radius: 3px;\n" +" border: 1px solid #45453F;\n" +" border-radius: 4px;\n" " padding: 2px;\n" "}\n" "\n" "#inspectorColorText {\n" -" color: #9CA8BA;\n" -" font-family: \"Menlo\";\n" -" font-size: 10px;\n" -"}\n" -"\n" -"#inspectorNestedGroup {\n" -" background-color: #202020;\n" -" border: 1px solid #383838;\n" -" border-radius: 3px;\n" -" margin: 3px 0;\n" -" padding: 5px;\n" +" color: #B0B0A8;\n" +" font-family: \"SF Mono\", \"Menlo\", \"Consolas\";\n" +" font-size: 11px;\n" "}\n" "\n" "#inspectorNestedTitle,\n" -"#inspectorArrayTitle {\n" -" color: #AEB8C8;\n" -" font-weight: 650;\n" +"#inspectorArrayTitle,\n" +"#materialTextureLabel {\n" +" color: #C9C9C1;\n" +" font-weight: 500;\n" "}\n" "\n" "#inspectorEmptyTitle,\n" "#materialEditorEmpty,\n" "#postProcessingEmpty {\n" -" color: #C4CDDA;\n" -" font-size: 14px;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"#inspectorEmptyHint {\n" -" color: #728096;\n" -"}\n" -"\n" -"#inspectorOpenAssetButton,\n" -"#inspectorAddComponentButton {\n" -" background-color: #292929;\n" -" border: 1px dashed #5A5A5A;\n" -" color: #C7D0DD;\n" -" padding: 6px;\n" -"}\n" -"\n" -"#inspectorAddComponentButton:hover {\n" -" background-color: #363636;\n" -" border-color: #666666;\n" -" color: #FFFFFF;\n" +" color: #C7C7BF;\n" +" font-size: 15px;\n" +" font-weight: 400;\n" "}\n" "\n" -"#inspectorAudioControls {\n" -" background-color: #202020;\n" -" border-radius: 3px;\n" +"#inspectorEmptyHint,\n" +"#environmentPageSubtitle,\n" +"#dialogHeroSubtitle {\n" +" color: #92928B;\n" "}\n" "\n" "#materialEditorTitle,\n" "#postProcessingTitle,\n" "#postProcessingSectionTitle,\n" -"#inspectorCameraTitle,\n" -"#workspaceTitle {\n" -" color: #F3F6FA;\n" +"#workspaceTitle,\n" +"#inspectorCameraTitle {\n" +" color: #D9D9D2;\n" " font-size: 13px;\n" -" font-weight: 700;\n" -"}\n" -"\n" -"#materialEditorStatus,\n" -"#postProcessingStatus,\n" -"#workspaceStatus,\n" -"#workspaceAutoApply {\n" -" color: #7E8A9E;\n" -" font-size: 10px;\n" +" font-weight: 500;\n" "}\n" "\n" "#materialPreview {\n" -" background-color: #151515;\n" -" border: 1px solid #444444;\n" -" border-radius: 4px;\n" -"}\n" -"\n" -"#materialColorButton {\n" -" background-color: #292929;\n" -" border-color: #454545;\n" -" border-radius: 3px;\n" -" color: #C9CDD0;\n" -" text-align: left;\n" -" padding: 4px 8px;\n" -"}\n" -"\n" -"#materialColorButton:hover {\n" -" background-color: #34383B;\n" -" border-color: #5A5F65;\n" +" background: #151514;\n" +" border: none;\n" +" border-radius: 8px;\n" "}\n" "\n" "#materialTextureSlot {\n" -" background-color: #252525;\n" -" border: 1px solid #404040;\n" -" border-radius: 4px;\n" -" padding: 4px;\n" +" background: transparent;\n" +" border: none;\n" +" padding: 6px 0;\n" "}\n" "\n" "#materialTexturePreview {\n" -" background-color: #1A1A1A;\n" -" border: 1px solid #494949;\n" -" border-radius: 3px;\n" -" color: #9E897D;\n" -" font-weight: 750;\n" -"}\n" -"\n" -"#materialTextureLabel {\n" -" color: #D6DDE7;\n" -" font-weight: 650;\n" -"}\n" -"\n" -"#materialTexturePath {\n" -" color: #7D899C;\n" -"}\n" -"\n" -"#environmentPages,\n" -"#environmentWorkspace,\n" -"#environmentPage {\n" -" background-color: #202020;\n" +" background: #242423;\n" " border: none;\n" +" border-radius: 6px;\n" "}\n" "\n" -"QListWidget#environmentCategories {\n" -" background-color: #1B1B1B;\n" -" border-right: 1px solid #3B3B3B;\n" -" padding: 5px;\n" -"}\n" -"\n" -"QListWidget#environmentCategories::item {\n" -" padding: 6px 8px;\n" -" margin: 2px 0;\n" -"}\n" -"\n" -"QListWidget#environmentCategories::item:selected {\n" -" background-color: #3B5F8A;\n" -" border-left: 2px solid #5D8BC0;\n" +"#environmentCategories {\n" +" background: #191918;\n" +" border: none;\n" +" padding: 8px;\n" "}\n" "\n" "#environmentPageTitle {\n" -" color: #F3F6FA;\n" -" font-size: 17px;\n" -" font-weight: 750;\n" -"}\n" -"\n" -"#environmentPageSubtitle {\n" -" color: #778499;\n" -"}\n" -"\n" -"QGroupBox#environmentSection {\n" -" background-color: #242424;\n" -" border-color: #3B3B3B;\n" -"}\n" -"\n" -"ads--CDockContainerWidget {\n" -" background-color: #111111;\n" -"}\n" -"\n" -"ads--CDockContainerWidget > QSplitter {\n" -" background-color: #111111;\n" +" color: #E7E7E0;\n" +" font-size: 22px;\n" +" font-weight: 500;\n" "}\n" "\n" +"ads--CDockContainerWidget,\n" +"ads--CDockContainerWidget > QSplitter,\n" "ads--CDockContainerWidget ads--CDockSplitter::handle {\n" -" background-color: #111111;\n" -"}\n" -"\n" -"ads--CDockContainerWidget ads--CDockSplitter::handle:hover {\n" -" background-color: #5D8BC0;\n" -"}\n" -"\n" -"ads--CDockAreaWidget {\n" -" background-color: #202020;\n" -" border: 1px solid #343434;\n" +" background: #121211;\n" "}\n" "\n" +"ads--CDockAreaWidget,\n" "ads--CDockAreaWidget[focused=\"true\"] {\n" -" border-color: #4A6382;\n" -"}\n" -"\n" -"ads--CDockAreaTitleBar {\n" -" background-color: #292929;\n" -" border-bottom: 1px solid #3B3B3B;\n" -" min-height: 25px;\n" +" background: #191918;\n" +" border: none;\n" +" border-radius: 9px;\n" "}\n" "\n" +"ads--CDockAreaTitleBar,\n" "ads--CDockAreaWidget[focused=\"true\"] ads--CDockAreaTitleBar {\n" -" background-color: #2D2D2D;\n" +" background: #191918;\n" +" border: none;\n" +" min-height: 40px;\n" "}\n" "\n" "#tabsContainerWidget {\n" -" background-color: transparent;\n" -"}\n" -"\n" -"ads--CTitleBarButton {\n" " background: transparent;\n" -" border: none;\n" -" border-radius: 2px;\n" -" min-width: 22px;\n" -" min-height: 22px;\n" -" padding: 2px;\n" -"}\n" -"\n" -"ads--CTitleBarButton:hover {\n" -" background-color: #404040;\n" -"}\n" -"\n" -"ads--CDockWidgetTab {\n" -" background-color: #292929;\n" -" border: none;\n" -" border-right: 1px solid #3A3A3A;\n" -" border-bottom: 1px solid #3B3B3B;\n" -" padding: 1px 5px;\n" -" margin: 1px 0;\n" -" border-radius: 0;\n" -"}\n" -"\n" -"ads--CDockWidgetTab:hover {\n" -" background-color: #333333;\n" -"}\n" -"\n" -"ads--CDockWidgetTab[activeTab=\"true\"] {\n" -" background-color: #333333;\n" -" border-bottom: 2px solid #5D8BC0;\n" "}\n" "\n" +"ads--CDockWidgetTab,\n" +"ads--CDockWidgetTab[activeTab=\"true\"],\n" "ads--CDockWidgetTab[focused=\"true\"] {\n" -" background-color: #303030;\n" +" background: transparent;\n" +" border: none;\n" +" padding: 3px 10px;\n" +" margin: 3px;\n" "}\n" "\n" "ads--CDockWidgetTab #dockWidgetTabLabel {\n" -" color: #7F8B9D;\n" -" font-size: 11px;\n" -" padding: 4px 2px;\n" +" color: #A1A19A;\n" +" font-size: 13px;\n" +" padding: 4px 0;\n" "}\n" "\n" -"ads--CDockWidgetTab[activeTab=\"true\"] #dockWidgetTabLabel,\n" -"ads--CDockWidgetTab[focused=\"true\"] #dockWidgetTabLabel {\n" -" color: #F1F4F8;\n" +"ads--CDockWidgetTab[activeTab=\"true\"] #dockWidgetTabLabel {\n" +" color: #DADAD3;\n" "}\n" "\n" +"ads--CTitleBarButton,\n" "#tabCloseButton,\n" "#dockAreaCloseButton,\n" "#detachGroupButton,\n" @@ -1180,305 +741,338 @@ inline constexpr const char* DARK_THEME = "#tabsMenuButton {\n" " background: transparent;\n" " border: none;\n" -" min-width: 20px;\n" -" min-height: 20px;\n" +" padding: 4px;\n" +" min-width: 18px;\n" +" min-height: 18px;\n" "}\n" "\n" -"#tabCloseButton:hover,\n" -"#dockAreaCloseButton:hover,\n" -"#detachGroupButton:hover,\n" -"#dockAreaAutoHideButton:hover,\n" -"#dockAreaMinimizeButton:hover,\n" -"#tabsMenuButton:hover {\n" -" background-color: #424549;\n" +"ads--CTitleBarButton:hover,\n" +"#tabCloseButton:hover {\n" +" background: #2B2B29;\n" +" border-radius: 5px;\n" "}\n" "\n" "ads--CDockWidget {\n" -" background-color: #202020;\n" +" background: #191918;\n" "}\n" "\n" "ads--CAutoHideSideBar,\n" "#sideTabsContainerWidget {\n" -" background-color: #141517;\n" +" background: #121211;\n" "}\n" "\n" "ads--CAutoHideTab {\n" -" background-color: #202224;\n" -" border: 1px solid #404448;\n" -" color: #7F8B9D;\n" -" padding: 4px;\n" -" border-radius: 8px;\n" +" background: transparent;\n" +" border: none;\n" +" padding: 7px;\n" "}\n" "\n" -"ads--CAutoHideTab:hover,\n" -"ads--CAutoHideTab[activeTab=\"true\"] {\n" -" background-color: #393F44;\n" -" border-color: #66737C;\n" -" color: #FFFFFF;\n" +"#projectSidebar {\n" +" background: #121211;\n" +" border: none;\n" "}\n" "\n" -"#projectBrowserRoot,\n" "#projectBrowserContent {\n" -" background-color: #18191B;\n" -"}\n" -"\n" -"#projectSidebar {\n" -" background-color: #151618;\n" -" border-right: 1px solid #303236;\n" +" background: #191918;\n" +" border: none;\n" +" border-radius: 10px;\n" "}\n" "\n" "#projectBrand {\n" -" color: #F5F7FA;\n" +" color: #E7E7E0;\n" " font-size: 16px;\n" -" font-weight: 750;\n" -"}\n" -"\n" -"#projectSidebarVersion {\n" -" color: #68758A;\n" -" font-size: 10px;\n" -" font-weight: 600;\n" -"}\n" -"\n" -"#projectNavSelected {\n" -" background-color: #34383C;\n" -" border: 1px solid #51575C;\n" -" border-left: 3px solid #79868F;\n" -" border-radius: 10px;\n" -" color: #DCE9FA;\n" -" padding: 6px 9px;\n" -" text-align: left;\n" -"}\n" -"\n" -"#projectNavSelected:disabled {\n" -" color: #DCE9FA;\n" -"}\n" -"\n" -"#projectBrowserTitle,\n" -"#dialogTitle {\n" -" color: #F4F6FA;\n" -" font-size: 24px;\n" -" font-weight: 750;\n" +" font-weight: 500;\n" "}\n" "\n" +"#projectSidebarVersion,\n" +"#projectSidebarCaption,\n" +"#projectPath,\n" +"#projectDate,\n" "#projectBrowserSubtitle,\n" "#dialogSubtitle,\n" "#emptyStateSubtitle,\n" "#templateDescription {\n" -" color: #7F8B9D;\n" +" color: #92928B;\n" +" font-size: 12px;\n" "}\n" "\n" -"#projectSearch {\n" -" background-color: #202224;\n" -" border: 1px solid #43474B;\n" -" border-radius: 11px;\n" -" padding: 7px 9px;\n" -" font-size: 13px;\n" +"#projectBrowserTitle,\n" +"#dialogTitle {\n" +" color: #EAEAE4;\n" +" font-size: 28px;\n" +" font-weight: 500;\n" "}\n" "\n" -"#projectSearch:focus {\n" -" border-color: #71808A;\n" +"#projectSearch {\n" +" background: #222221;\n" +" padding: 10px 12px;\n" "}\n" "\n" "#projectList {\n" -" background-color: transparent;\n" +" background: transparent;\n" " border: none;\n" "}\n" "\n" -"#projectList::item {\n" +"#projectRow {\n" " background: transparent;\n" " border: none;\n" -" padding: 0;\n" +" border-radius: 7px;\n" "}\n" "\n" -"#projectRow {\n" -" background-color: #242628;\n" -" border: 1px solid #3B3E41;\n" -" border-radius: 13px;\n" +"#projectRow:hover {\n" +" background: #242423;\n" "}\n" "\n" -"#projectRow:hover {\n" -" background-color: #2C2F32;\n" -" border-color: #565B61;\n" +"#projectRow[selected=\"true\"] {\n" +" background: #30302E;\n" "}\n" "\n" -"#projectRow[available=\"false\"] {\n" -" background-color: #202224;\n" -" border-color: #303235;\n" +"#projectName {\n" +" color: #DEDED7;\n" +" font-size: 14px;\n" +" font-weight: 400;\n" "}\n" "\n" "#projectIcon,\n" "#templateIcon {\n" -" background-color: #303337;\n" -" border: 1px solid #484C50;\n" -" border-radius: 10px;\n" +" background: transparent;\n" +" border: none;\n" "}\n" "\n" -"#projectName {\n" -" color: #EEF2F7;\n" -" font-size: 14px;\n" -" font-weight: 700;\n" +"#rendererBadge {\n" +" background: #262624;\n" +" border: none;\n" +" border-radius: 4px;\n" +" color: #ABABA2;\n" +" font-size: 10px;\n" +" padding: 4px 7px;\n" "}\n" "\n" -"#projectPath,\n" -"#projectDate {\n" -" color: #768398;\n" -" font-size: 10px;\n" +"#projectEmptyState {\n" +" background: transparent;\n" +" border: none;\n" "}\n" "\n" -"#rendererBadge {\n" -" background-color: #2C302E;\n" -" border: 1px solid #494F4B;\n" +"#emptyStateTitle {\n" +" color: #CFCFC7;\n" +" font-size: 20px;\n" +" font-weight: 400;\n" +"}\n" +"\n" +"QFrame[templateCard=\"true\"] {\n" +" background: #20201F;\n" +" border: 1px solid transparent;\n" " border-radius: 8px;\n" -" color: #B4BBB6;\n" -" padding: 3px 7px;\n" -" font-size: 9px;\n" -" font-weight: 700;\n" "}\n" "\n" -"#projectMoreButton {\n" -" background: transparent;\n" -" border-color: transparent;\n" +"QFrame[templateCard=\"true\"][selected=\"true\"] {\n" +" background: #2A2A28;\n" +" border-color: #66665F;\n" "}\n" "\n" -"#projectMoreButton:hover {\n" -" background-color: #3E4246;\n" -" border-color: #51565B;\n" +"#templateOption,\n" +"#fieldLabel {\n" +" color: #BDBDB5;\n" +" font-weight: 400;\n" "}\n" "\n" -"#projectEmptyState {\n" -" background-color: #1E2022;\n" -" border: 1px dashed #484C51;\n" -" border-radius: 14px;\n" +"#dialogError {\n" +" color: #D69C95;\n" +" font-size: 12px;\n" "}\n" "\n" -"#emptyStateTitle {\n" -" color: #CDD5E1;\n" -" font-size: 16px;\n" -" font-weight: 700;\n" +"#dialogHero {\n" +" background: transparent;\n" +" border: none;\n" +" padding: 2px;\n" +"}\n" +"\n" +"#dialogHeroIcon {\n" +" background: transparent;\n" +" border: none;\n" +" padding: 4px;\n" "}\n" "\n" -"#createProjectDialog {\n" -" background-color: #1E2022;\n" +"#dialogHeroTitle {\n" +" color: #E3E3DB;\n" +" font-size: 22px;\n" +" font-weight: 500;\n" "}\n" "\n" -"QFrame[templateCard=\"true\"] {\n" -" background-color: #242628;\n" -" border: 1px solid #42464A;\n" -" border-radius: 13px;\n" +"#exportSummary {\n" +" background: #1D1D1C;\n" +" border: none;\n" +" border-radius: 6px;\n" +" color: #9C9C94;\n" +" padding: 12px;\n" "}\n" "\n" -"QFrame[templateCard=\"true\"]:hover {\n" -" background-color: #2B2E31;\n" -" border-color: #5A5F65;\n" +"#exportLog,\n" +"#runtimeErrors {\n" +" background: #161615;\n" +" border: none;\n" +" padding: 12px;\n" +" font-family: \"SF Mono\", \"Menlo\", \"Consolas\";\n" +" font-size: 12px;\n" +" color: #C3BAB1;\n" "}\n" "\n" -"QFrame[templateCard=\"true\"][selected=\"true\"] {\n" -" background-color: #393F44;\n" -" border-color: #66737C;\n" +"#commandPaletteDialog,\n" +"#globalSearchDialog {\n" +" background: #191918;\n" +" border: 1px solid #373733;\n" +" border-radius: 10px;\n" "}\n" "\n" -"#templateOption {\n" -" color: #E7ECF3;\n" -" font-weight: 650;\n" +"#commandPaletteSearch,\n" +"#globalSearchField {\n" +" background: transparent;\n" +" border: none;\n" +" border-bottom: 1px solid #30302C;\n" +" border-radius: 0;\n" +" padding: 15px 12px;\n" +" font-size: 16px;\n" "}\n" "\n" -"#fieldLabel {\n" -" color: #AAB5C5;\n" -" font-size: 11px;\n" -" font-weight: 650;\n" +"#commandPaletteList,\n" +"#globalSearchResults {\n" +" background: transparent;\n" +" padding: 4px;\n" "}\n" "\n" -"#dialogError {\n" -" color: #FF7D8A;\n" +"#paletteHint,\n" +"#projectListHint {\n" +" background: transparent;\n" +" color: #7E7E77;\n" " font-size: 11px;\n" +" padding: 7px 12px;\n" "}\n" "\n" -"QPushButton[secondary=\"true\"] {\n" -" background-color: #292C2F;\n" -" border-color: #494D52;\n" +"#splashCard {\n" +" background: #191918;\n" +" border: 1px solid #343430;\n" +" border-radius: 12px;\n" "}\n" "\n" -"QPushButton[secondary=\"true\"]:hover {\n" -" background-color: #363A3E;\n" -" border-color: #5D6268;\n" +"#atlasSplash,\n" +"#splashIcon {\n" +" background: transparent;\n" "}\n" "\n" -"#projectSettingsDialog,\n" -"#exportDialog {\n" -" background-color: #18191B;\n" +"#splashTitle {\n" +" color: #ECECE6;\n" +" font-size: 36px;\n" +" font-weight: 500;\n" "}\n" "\n" -"#dialogHero {\n" -" background-color: #242628;\n" -" border: 1px solid #42464A;\n" -" border-radius: 13px;\n" -" padding: 6px;\n" +"#splashVersion,\n" +"#splashCompany,\n" +"#splashWarning {\n" +" color: #91918A;\n" +" font-size: 12px;\n" "}\n" "\n" -"#dialogHeroIcon {\n" -" background-color: #2B3034;\n" -" border: 1px solid #50575C;\n" -" border-radius: 10px;\n" -" padding: 6px;\n" +"#splashStatus {\n" +" color: #BFBFB7;\n" +" font-size: 12px;\n" "}\n" "\n" -"#dialogHeroTitle {\n" -" color: #F3F6FA;\n" -" font-size: 17px;\n" -" font-weight: 750;\n" +"#splashProgress {\n" +" background: #2C2C28;\n" +" border: none;\n" +" min-height: 0;\n" +" border-radius: 2px;\n" "}\n" "\n" -"#dialogHeroSubtitle,\n" -"#exportSummary {\n" -" color: #7F8B9D;\n" +"#splashProgress::chunk {\n" +" background: #BCBCB2;\n" +" border-radius: 2px;\n" "}\n" "\n" -"#exportSummary {\n" -" background-color: #232527;\n" -" border: 1px solid #3B3E42;\n" -" border-radius: 10px;\n" -" padding: 6px;\n" +"QPushButton:default {\n" +" background: #E5E5E1;\n" +" color: #191918;\n" "}\n" "\n" -"#exportLog {\n" -" background-color: #141517;\n" -" border-color: #404448;\n" -" color: #B7BDBC;\n" -" font-family: \"Menlo\";\n" -" font-size: 10px;\n" +"#projectSectionLabel {\n" +" color: #82827B;\n" +" font-size: 12px;\n" +" padding: 3px 10px;\n" "}\n" "\n" -"#commandPaletteDialog,\n" -"#globalSearchDialog {\n" -" background-color: #202224;\n" -" border: 1px solid #5A5F65;\n" -" border-radius: 14px;\n" +"#searchPreviewPane {\n" +" background: #171716;\n" +" border: none;\n" +" border-left: 1px solid #30302C;\n" "}\n" "\n" -"#commandPaletteSearch,\n" -"#globalSearchField {\n" -" background-color: #1A1C1E;\n" -" border: 1px solid #505459;\n" -" border-radius: 11px;\n" -" padding: 7px 9px;\n" -" font-size: 14px;\n" +"#searchPreviewText {\n" +" background: transparent;\n" +" border: none;\n" +" padding: 0;\n" +" font-family: \"SF Mono\", \"Menlo\", \"Consolas\";\n" +" font-size: 12px;\n" +" color: #B6B6AF;\n" "}\n" "\n" -"#commandPaletteSearch:focus,\n" -"#globalSearchField:focus {\n" -" border-color: #71808A;\n" +"#projectRow[available=\"false\"] #projectName {\n" +" color: #82827B;\n" "}\n" "\n" -"#commandPaletteList,\n" -"#globalSearchResults {\n" -" background-color: #202224;\n" +"QAbstractSpinBox QLineEdit {\n" +" background: transparent;\n" +" border: none;\n" +" padding: 0;\n" +" min-height: 0;\n" +"}\n" +"\n" +"#inspectorVectorField {\n" +" background: transparent;\n" " border: none;\n" +"}\n" +"\n" +"#inspectorAxisField {\n" +" background: #252524;\n" +" border: 1px solid transparent;\n" +" border-radius: 6px;\n" +"}\n" +"\n" +"#inspectorAxisField:hover {\n" +" background: #2C2C29;\n" +" border-color: #44443F;\n" +"}\n" +"\n" +"#inspectorAxisField QDoubleSpinBox {\n" +" background: transparent;\n" +" border: none;\n" +" padding: 5px 2px;\n" +" min-height: 24px;\n" +"}\n" +"\n" +"#inspectorNumberField,\n" +"#inspectorNameField,\n" +"#inspectorColorText {\n" +" min-height: 26px;\n" +"}\n" +"\n" +"#inspectorAxisX,\n" +"#inspectorAxisY,\n" +"#inspectorAxisZ {\n" +" padding: 0;\n" +" font-size: 11px;\n" +"}\n" +"\n" +"QTabBar::close-button {\n" +" image: url(:/editor/assets/close.svg);\n" +" width: 14px;\n" +" height: 14px;\n" " padding: 5px;\n" +" border-radius: 5px;\n" "}\n" "\n" -"#commandPaletteList::item,\n" -"#globalSearchResults::item {\n" -" min-height: 30px;\n" -" padding: 6px 8px;\n" +"QTabBar::close-button:hover,\n" +"#tabCloseButton:hover,\n" +"#dockAreaCloseButton:hover {\n" +" background: #343431;\n" "}\n" ; diff --git a/include/editor/styling/icons.h b/include/editor/styling/icons.h index 784290bb..2fce2117 100644 --- a/include/editor/styling/icons.h +++ b/include/editor/styling/icons.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace styling { @@ -85,7 +86,8 @@ enum class Icon { }; bool loadIconFont(); -QIcon icon(Icon icon, const QColor &color = QColor("#AAB4C4")); +QPixmap brandMark(const QSize &size); +QIcon icon(Icon icon, const QColor &color = QColor("#B4B3AB")); QIcon colorSwatch(const QColor &color, const QSize &size = QSize(18, 18)); } diff --git a/include/editor/styling/workbench.h b/include/editor/styling/workbench.h new file mode 100644 index 00000000..3b79ef66 --- /dev/null +++ b/include/editor/styling/workbench.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class QApplication; + +namespace styling { + +inline constexpr int SecondaryTextRole = Qt::UserRole + 42; + +class Button : public QPushButton { +public: + using QPushButton::QPushButton; + QSize sizeHint() const override; +protected: + void paintEvent(QPaintEvent *) override; +}; + +class ToolButton : public QToolButton { +public: + explicit ToolButton(QWidget *parent = nullptr); + QSize sizeHint() const override; +protected: + void paintEvent(QPaintEvent *) override; +}; + +class ItemDelegate : public QStyledItemDelegate { +public: + explicit ItemDelegate(QObject *parent = nullptr); + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const override; +}; + +class TreeView : public QTreeView { +public: + using QTreeView::QTreeView; +protected: + void drawBranches(QPainter *painter, const QRect &rect, + const QModelIndex &index) const override; +}; + +class ElidedLabel : public QLabel { +public: + explicit ElidedLabel(const QString &text, QWidget *parent = nullptr); + QSize minimumSizeHint() const override; + QSize sizeHint() const override; +protected: + void paintEvent(QPaintEvent *) override; +}; + +class WorkspaceStack : public QStackedWidget { +public: + explicit WorkspaceStack(QWidget *parent = nullptr); + QSize minimumSizeHint() const override; + QSize sizeHint() const override; +}; + +void installWorkbench(QApplication &app); + +} diff --git a/include/editor/widgets/scrubbableSpinBox.h b/include/editor/widgets/scrubbableSpinBox.h index 463c68d0..50dcf856 100644 --- a/include/editor/widgets/scrubbableSpinBox.h +++ b/include/editor/widgets/scrubbableSpinBox.h @@ -16,6 +16,19 @@ class FlexibleDoubleSpinBox : public QDoubleSpinBox { : QDoubleSpinBox(parent) {} protected: + QString textFromValue(double value) const override { + QString text = QDoubleSpinBox::textFromValue(value); + const QString decimal = locale().decimalPoint(); + if (text.contains(decimal)) { + const QChar zero = locale().zeroDigit().at(0); + while (text.endsWith(zero)) + text.chop(1); + if (text.endsWith(decimal)) + text.chop(decimal.size()); + } + return text; + } + double valueFromText(const QString &text) const override { return QDoubleSpinBox::valueFromText(normalizedText(text)); } diff --git a/runtime/lib/context.cpp b/runtime/lib/context.cpp index 9f334c13..6c9593e5 100644 --- a/runtime/lib/context.cpp +++ b/runtime/lib/context.cpp @@ -4927,6 +4927,7 @@ bool Context::setEditorShadingMode(int mode) { } bool Context::setEditorPathTracingPreview(bool enabled) { + editorPathTracingPreview = enabled; if (window == nullptr || !editorRuntime) { return false; } diff --git a/runtime/lib/runtime.cpp b/runtime/lib/runtime.cpp index 61dc9127..0a384a4c 100644 --- a/runtime/lib/runtime.cpp +++ b/runtime/lib/runtime.cpp @@ -63,4 +63,10 @@ void RuntimeScene::initialize(Window &window) { } runtimeContext->loadMainScene(window); +#ifdef METAL + if (runtimeContext->editorRuntime && + runtimeContext->config.renderer == "pathtracing") { + window.setEditorPathTracingPreview(runtimeContext->editorPathTracingPreview); + } +#endif } diff --git a/scripts/package_app.py b/scripts/package_app.py index bc5dd9c8..dcaefbfc 100755 --- a/scripts/package_app.py +++ b/scripts/package_app.py @@ -28,13 +28,11 @@ def require(name, override=None): return Path(candidate) -def compile_icon(config, artwork, output_directory, work_directory, deployment_target): +def compile_icon(icon_source, output_directory, work_directory, deployment_target): source = work_directory / "AtlasEngine.icon" if source.exists(): shutil.rmtree(source) - (source / "Assets").mkdir(parents=True) - shutil.copy2(config, source / "icon.json") - shutil.copy2(artwork, source / "Assets" / "atlas_ball_bright.png") + shutil.copytree(icon_source, source) if output_directory.exists(): shutil.rmtree(output_directory) output_directory.mkdir(parents=True) @@ -292,19 +290,17 @@ def main(): app_name = "Atlas Engine.app" built_app = build_directory / "bin" / app_name packaged_app = dist_directory / app_name - icon_config = ( + icon_source = ( root / "editor" / "assets" - / ("AtlasEngine.icon.json" if args.release else "AtlasEngineDev.icon.json") + / ("AtlasEngine.icon" if args.release else "AtlasEngineDev.icon") ) - icon_artwork = root / "editor" / "assets" / "atlas_ball_bright.png" assets_directory.mkdir(parents=True, exist_ok=True) dist_directory.mkdir(parents=True, exist_ok=True) icon, icon_assets = compile_icon( - icon_config, - icon_artwork, + icon_source, assets_directory / "compiled-icon", assets_directory, deployment_target,