mirror of
https://github.com/logos-co/logos-basecamp.git
synced 2026-08-27 14:51:07 +00:00
feat: Making macos traffic buttons to be overlayed on top of app and alligning app for this to look okay
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# logos-app-poc
|
||||
# logos-app
|
||||
|
||||
## How to Build
|
||||
|
||||
@@ -15,7 +15,7 @@ nix build '.#default'
|
||||
```
|
||||
|
||||
The result will include:
|
||||
- `/bin/logos-app-poc` - The main Logos application executable
|
||||
- `/bin/logos-app` - The main Logos application executable
|
||||
- All required modules and dependencies
|
||||
|
||||
#### Build Individual Components
|
||||
@@ -48,7 +48,7 @@ After building with `nix build`, you can run the application:
|
||||
|
||||
```bash
|
||||
# Run the main Logos application
|
||||
./result/bin/logos-app-poc
|
||||
./result/bin/logos-app
|
||||
```
|
||||
|
||||
The application will automatically load all required modules and dependencies. All components are bundled in the Nix store layout.
|
||||
|
||||
+14
-2
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(LogosApp LANGUAGES CXX)
|
||||
project(LogosApp LANGUAGES CXX OBJCXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
@@ -19,9 +19,10 @@ endif()
|
||||
|
||||
find_package(Qt6 COMPONENTS Widgets REQUIRED)
|
||||
|
||||
# Add interfaces directory to include path
|
||||
# Add interfaces and macos directories to include path
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/macos)
|
||||
|
||||
# Allow override from environment or command line (for nix builds)
|
||||
if(NOT DEFINED LOGOS_LIBLOGOS_ROOT)
|
||||
@@ -84,10 +85,17 @@ set(PROJECT_SOURCES
|
||||
main.cpp
|
||||
window.h
|
||||
window.cpp
|
||||
macos/trafficLightsTitleBar.h
|
||||
macos/trafficLightsTitleBar.cpp
|
||||
macos/macWindowStyle.h
|
||||
interfaces/IComponent.h
|
||||
resources.qrc
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND PROJECT_SOURCES macos/macWindowStyle.mm)
|
||||
endif()
|
||||
|
||||
qt_add_executable(LogosApp
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
@@ -98,6 +106,10 @@ target_link_libraries(LogosApp PRIVATE
|
||||
logos_core
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(LogosApp PRIVATE "-framework Cocoa" "-framework QuartzCore")
|
||||
endif()
|
||||
|
||||
# Copy the core library to the app's lib directory and fix its install name
|
||||
if(APPLE)
|
||||
if(_liblogos_is_source)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Logos Core POC
|
||||
# Logos App
|
||||
|
||||
## Building the Application
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 292 B |
Binary file not shown.
|
After Width: | Height: | Size: 223 B |
Binary file not shown.
|
After Width: | Height: | Size: 130 B |
@@ -5,7 +5,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>LogosApp</string>
|
||||
<string>Logos App</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>LogosApp</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>LogosApp</string>
|
||||
<string>Logos App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef MACWINDOWSTYLE_H
|
||||
#define MACWINDOWSTYLE_H
|
||||
|
||||
class QMainWindow;
|
||||
|
||||
void applyMacWindowRoundedCorners(QMainWindow* w, bool rounded = true);
|
||||
|
||||
#endif // MACWINDOWSTYLE_H
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <QtCore/qglobal.h>
|
||||
#ifdef Q_OS_MAC
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#endif
|
||||
|
||||
#include "macWindowStyle.h"
|
||||
#include <QMainWindow>
|
||||
|
||||
void applyMacWindowRoundedCorners(QMainWindow* w, bool rounded)
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
if (!w) return;
|
||||
NSView* nsView = (NSView*)w->winId();
|
||||
if (!nsView) return;
|
||||
|
||||
nsView.wantsLayer = YES;
|
||||
if (nsView.layer) {
|
||||
nsView.layer.cornerRadius = rounded ? 10.0 : 0.0;
|
||||
nsView.layer.masksToBounds = rounded;
|
||||
nsView.layer.borderWidth = rounded ? 0.5 : 0.0;
|
||||
nsView.layer.borderColor = rounded ? [NSColor separatorColor].CGColor : nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
#include "trafficLightsTitleBar.h"
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QWindow>
|
||||
#include <QIcon>
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
|
||||
QPushButton* makeTrafficButton(const QString& colorHex, const QString& borderHex, int size, QWidget* parent) {
|
||||
auto* btn = new QPushButton(parent);
|
||||
btn->setFixedSize(size, size);
|
||||
btn->setCursor(Qt::ArrowCursor);
|
||||
btn->setFlat(true);
|
||||
btn->setStyleSheet(
|
||||
QString("QPushButton {"
|
||||
" background-color: %1;"
|
||||
" border: 0.5px solid %2;"
|
||||
" border-radius: %3px;"
|
||||
"}"
|
||||
"QPushButton:hover { background-color: %1; }"
|
||||
"QPushButton:pressed { background-color: %1; }")
|
||||
.arg(colorHex, borderHex)
|
||||
.arg(size / 2));
|
||||
return btn;
|
||||
}
|
||||
|
||||
TrafficLightsTitleBar::TrafficLightsTitleBar(QWidget* parent) : QWidget(parent) {
|
||||
setFixedHeight(kTitleBarHeight);
|
||||
setCursor(Qt::ArrowCursor);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
setAutoFillBackground(false);
|
||||
|
||||
setMouseTracking(true);
|
||||
setAttribute(Qt::WA_Hover);
|
||||
|
||||
auto* layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(kLeftMargin, kTopMargin, 0, 0);
|
||||
layout->setSpacing(kButtonSpacing);
|
||||
|
||||
m_closeBtn = makeTrafficButton("#FF5F57", "#E0443E", kButtonSize, this);
|
||||
layout->addWidget(m_closeBtn);
|
||||
|
||||
m_minBtn = makeTrafficButton("#FEBC2E", "#DE9E24", kButtonSize, this);
|
||||
layout->addWidget(m_minBtn);
|
||||
|
||||
m_zoomBtn = makeTrafficButton("#28C840", "#1AAC37", kButtonSize, this);
|
||||
layout->addWidget(m_zoomBtn);
|
||||
|
||||
layout->addStretch(1);
|
||||
|
||||
connect(m_closeBtn, &QPushButton::clicked, this, [this]() { window()->hide(); });
|
||||
connect(m_minBtn, &QPushButton::clicked, this, [this]() { window()->showMinimized(); });
|
||||
connect(m_zoomBtn, &QPushButton::clicked, this, [this]() {
|
||||
QWidget* w = window();
|
||||
if (w->windowState() & Qt::WindowFullScreen)
|
||||
w->setWindowState(Qt::WindowNoState);
|
||||
else
|
||||
w->setWindowState(Qt::WindowFullScreen);
|
||||
});
|
||||
|
||||
m_closeBtn->installEventFilter(this);
|
||||
m_minBtn->installEventFilter(this);
|
||||
m_zoomBtn->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool TrafficLightsTitleBar::isOverButton(const QPoint& pos) const {
|
||||
if (m_closeBtn && m_closeBtn->isVisible() && m_closeBtn->geometry().contains(pos)) {
|
||||
return true;
|
||||
}
|
||||
if (m_minBtn && m_minBtn->isVisible() && m_minBtn->geometry().contains(pos)) {
|
||||
return true;
|
||||
}
|
||||
if (m_zoomBtn && m_zoomBtn->isVisible() && m_zoomBtn->geometry().contains(pos)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::setButtonIcon(QPushButton* btn, const QString& iconPath) {
|
||||
if (!btn) return;
|
||||
const QSize iconSize(6, 6);
|
||||
btn->setIcon(QIcon(iconPath));
|
||||
btn->setIconSize(iconSize);
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::setAllButtonIcons() {
|
||||
setButtonIcon(m_closeBtn, ":/icons/trafficlights/close.png");
|
||||
setButtonIcon(m_minBtn, ":/icons/trafficlights/minimise.png");
|
||||
setButtonIcon(m_zoomBtn, ":/icons/trafficlights/maximize.png");
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::clearAllButtonIcons() {
|
||||
if (m_closeBtn) m_closeBtn->setIcon(QIcon());
|
||||
if (m_minBtn) m_minBtn->setIcon(QIcon());
|
||||
if (m_zoomBtn) m_zoomBtn->setIcon(QIcon());
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::leaveEvent(QEvent* e) {
|
||||
QWidget::leaveEvent(e);
|
||||
clearAllButtonIcons();
|
||||
}
|
||||
|
||||
bool TrafficLightsTitleBar::eventFilter(QObject* watched, QEvent* event) {
|
||||
if (event->type() == QEvent::Enter) {
|
||||
if (watched == m_closeBtn || watched == m_minBtn || watched == m_zoomBtn) {
|
||||
setAllButtonIcons();
|
||||
}
|
||||
} else if (event->type() == QEvent::Leave) {
|
||||
if (watched == m_closeBtn || watched == m_minBtn || watched == m_zoomBtn) {
|
||||
clearAllButtonIcons();
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::forwardEventToCentralWidget(QMouseEvent* e) {
|
||||
QMainWindow* mainWindow = qobject_cast<QMainWindow*>(window());
|
||||
if (!mainWindow) return;
|
||||
|
||||
QWidget* centralWidget = mainWindow->centralWidget();
|
||||
if (!centralWidget) return;
|
||||
|
||||
// Map coordinates from title bar space to central widget space
|
||||
QPoint globalPos = mapToGlobal(e->pos());
|
||||
QPoint centralPos = centralWidget->mapFromGlobal(globalPos);
|
||||
|
||||
// Check if the position is within central widget bounds
|
||||
if (!centralWidget->rect().contains(centralPos)) return;
|
||||
|
||||
// Find the actual child widget at this position
|
||||
QWidget* targetWidget = centralWidget->childAt(centralPos);
|
||||
if (!targetWidget) {
|
||||
// No specific child at this position, send to central widget itself
|
||||
targetWidget = centralWidget;
|
||||
}
|
||||
|
||||
// Map coordinates to target widget's space
|
||||
QPoint targetPos = targetWidget->mapFromGlobal(globalPos);
|
||||
|
||||
// Create a new event with mapped coordinates
|
||||
QMouseEvent mappedEvent(
|
||||
e->type(),
|
||||
targetPos,
|
||||
e->globalPosition(),
|
||||
e->button(),
|
||||
e->buttons(),
|
||||
e->modifiers()
|
||||
);
|
||||
|
||||
// Send the event to the target widget
|
||||
QApplication::sendEvent(targetWidget, &mappedEvent);
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::mousePressEvent(QMouseEvent* e) {
|
||||
if (isOverButton(e->pos())) {
|
||||
QWidget::mousePressEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle left button for potential dragging
|
||||
// Forward all other buttons (right-click, middle-click, etc.) to central widget
|
||||
if (e->button() != Qt::LeftButton) {
|
||||
forwardEventToCentralWidget(e);
|
||||
e->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
// Left button: prepare for potential drag
|
||||
m_dragActive = false;
|
||||
m_dragStartPos = e->pos();
|
||||
e->accept();
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::mouseMoveEvent(QMouseEvent* e) {
|
||||
if (isOverButton(e->pos())) {
|
||||
QWidget::mouseMoveEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// If left button is pressed and we haven't started dragging yet
|
||||
if (!m_dragActive && (e->buttons() & Qt::LeftButton)) {
|
||||
// Check if we've moved enough to start a drag
|
||||
int distance = (e->pos() - m_dragStartPos).manhattanLength();
|
||||
if (distance >= kDragThresholdPx) {
|
||||
if (QWindow* w = window()->windowHandle()) {
|
||||
w->startSystemMove();
|
||||
m_dragActive = true;
|
||||
}
|
||||
}
|
||||
} else if (!(e->buttons() & Qt::LeftButton)) {
|
||||
// No left button - forward hover events to central widget
|
||||
forwardEventToCentralWidget(e);
|
||||
}
|
||||
|
||||
QWidget::mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::mouseReleaseEvent(QMouseEvent* e) {
|
||||
if (isOverButton(e->pos())) {
|
||||
QWidget::mouseReleaseEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this was a left button release and we never started dragging,
|
||||
// it was a click - forward it to the central widget
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
bool wasClick = !m_dragActive;
|
||||
m_dragActive = false;
|
||||
|
||||
if (wasClick) {
|
||||
// This was a click, not a drag - forward the release to central widget
|
||||
// Also synthesize a press event so the central widget gets a complete click
|
||||
QMainWindow* mainWindow = qobject_cast<QMainWindow*>(window());
|
||||
if (mainWindow) {
|
||||
QWidget* centralWidget = mainWindow->centralWidget();
|
||||
if (centralWidget) {
|
||||
QPoint globalPos = mapToGlobal(e->pos());
|
||||
QPoint centralPos = centralWidget->mapFromGlobal(globalPos);
|
||||
|
||||
if (centralWidget->rect().contains(centralPos)) {
|
||||
// Find the actual child widget at this position
|
||||
QWidget* targetWidget = centralWidget->childAt(centralPos);
|
||||
if (!targetWidget) {
|
||||
targetWidget = centralWidget;
|
||||
}
|
||||
|
||||
// Map coordinates to target widget's space
|
||||
QPoint targetPos = targetWidget->mapFromGlobal(globalPos);
|
||||
|
||||
// Send press event
|
||||
QMouseEvent pressEvent(
|
||||
QEvent::MouseButtonPress,
|
||||
targetPos,
|
||||
e->globalPosition(),
|
||||
e->button(),
|
||||
e->button(),
|
||||
e->modifiers()
|
||||
);
|
||||
QApplication::sendEvent(targetWidget, &pressEvent);
|
||||
|
||||
forwardEventToCentralWidget(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Non-left button release - forward to central widget
|
||||
forwardEventToCentralWidget(e);
|
||||
}
|
||||
}
|
||||
|
||||
void TrafficLightsTitleBar::mouseDoubleClickEvent(QMouseEvent* e) {
|
||||
if (isOverButton(e->pos())) {
|
||||
QWidget::mouseDoubleClickEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
forwardEventToCentralWidget(e);
|
||||
e->ignore();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef TRAFFICLIGHTSTITLEBAR_H
|
||||
#define TRAFFICLIGHTSTITLEBAR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPoint>
|
||||
#include <QEvent>
|
||||
|
||||
class QPushButton;
|
||||
class QMouseEvent;
|
||||
|
||||
class TrafficLightsTitleBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const int kTitleBarHeight = 28;
|
||||
static const int kButtonSize = 12;
|
||||
static const int kButtonSpacing = 6;
|
||||
static const int kLeftMargin = 10;
|
||||
static const int kTopMargin = 4;
|
||||
|
||||
explicit TrafficLightsTitleBar(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* e) override;
|
||||
void mouseMoveEvent(QMouseEvent* e) override;
|
||||
void mouseReleaseEvent(QMouseEvent* e) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* e) override;
|
||||
void leaveEvent(QEvent* e) override;
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
private:
|
||||
bool isOverButton(const QPoint& pos) const;
|
||||
void forwardEventToCentralWidget(QMouseEvent* e);
|
||||
void setButtonIcon(QPushButton* btn, const QString& iconPath);
|
||||
void setAllButtonIcons();
|
||||
void clearAllButtonIcons();
|
||||
|
||||
QPushButton* m_closeBtn = nullptr;
|
||||
QPushButton* m_minBtn = nullptr;
|
||||
QPushButton* m_zoomBtn = nullptr;
|
||||
|
||||
bool m_dragActive = false;
|
||||
QPoint m_dragStartPos;
|
||||
static const int kDragThresholdPx = 4;
|
||||
};
|
||||
|
||||
#endif // TRAFFICLIGHTSTITLEBAR_H
|
||||
@@ -2,5 +2,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/logos.png</file>
|
||||
<file>icons/trafficlights/close.png</file>
|
||||
<file>icons/trafficlights/minimise.png</file>
|
||||
<file>icons/trafficlights/maximize.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
+83
-6
@@ -13,6 +13,11 @@
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <IComponent.h>
|
||||
#include <QTimer>
|
||||
#ifdef Q_OS_MAC
|
||||
#include "trafficLightsTitleBar.h"
|
||||
#include "macWindowStyle.h"
|
||||
#endif
|
||||
|
||||
Window::Window(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
@@ -103,7 +108,6 @@ void Window::setupUi()
|
||||
|
||||
if (mainContent) {
|
||||
setCentralWidget(mainContent);
|
||||
|
||||
// Pass the package manager widget to main_ui if it was loaded
|
||||
if (packageManagerWidget && mainUiPlugin) {
|
||||
QMetaObject::invokeMethod(mainUiPlugin, "setPackageManagerWidget",
|
||||
@@ -127,15 +131,79 @@ void Window::setupUi()
|
||||
|
||||
layout->addWidget(messageLabel);
|
||||
setCentralWidget(fallbackWidget);
|
||||
|
||||
qWarning() << "Failed to load main UI plugin from:" << mainUiPluginPath;
|
||||
}
|
||||
|
||||
// Set window title and size
|
||||
setWindowTitle("Logos Core POC");
|
||||
resize(1024, 768);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||
setupMacOSDockReopen();
|
||||
// Create title bar after resize() so it gets full width from the start
|
||||
m_trafficLightsTitleBar = new TrafficLightsTitleBar(this);
|
||||
m_trafficLightsTitleBar->setGeometry(0, 0, width(), TrafficLightsTitleBar::kTitleBarHeight);
|
||||
m_trafficLightsTitleBar->show();
|
||||
m_trafficLightsTitleBar->raise();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::changeEvent(QEvent* event)
|
||||
{
|
||||
QMainWindow::changeEvent(event);
|
||||
#ifdef Q_OS_MAC
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
const bool fullScreen = (windowState() & Qt::WindowFullScreen) != 0;
|
||||
if (m_trafficLightsTitleBar) {
|
||||
if (fullScreen)
|
||||
m_trafficLightsTitleBar->hide();
|
||||
else
|
||||
m_trafficLightsTitleBar->show();
|
||||
}
|
||||
applyMacWindowRoundedCorners(this, !fullScreen);
|
||||
// This is needed to fix squared corners after exiting fullscreen mode
|
||||
if (!fullScreen) {
|
||||
const int w = width();
|
||||
const int h = height();
|
||||
resize(w - 1, h - 1);
|
||||
QTimer::singleShot(0, this, [this, w, h]() {
|
||||
resize(w, h);
|
||||
applyMacWindowRoundedCorners(this, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QMainWindow::resizeEvent(event);
|
||||
#ifdef Q_OS_MAC
|
||||
if (m_trafficLightsTitleBar && m_trafficLightsTitleBar->isVisible())
|
||||
m_trafficLightsTitleBar->setGeometry(0, 0, width(), TrafficLightsTitleBar::kTitleBarHeight);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::showEvent(QShowEvent* event)
|
||||
{
|
||||
QMainWindow::showEvent(event);
|
||||
#ifdef Q_OS_MAC
|
||||
applyMacWindowRoundedCorners(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void Window::setupMacOSDockReopen()
|
||||
{
|
||||
connect(qApp, &QApplication::applicationStateChanged, this, [this](Qt::ApplicationState state) {
|
||||
if (state == Qt::ApplicationActive && !isVisible()) {
|
||||
show();
|
||||
raise();
|
||||
activateWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
void Window::createTrayIcon()
|
||||
{
|
||||
if (!QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||
@@ -146,7 +214,7 @@ void Window::createTrayIcon()
|
||||
// Create tray icon
|
||||
m_trayIcon = new QSystemTrayIcon(this);
|
||||
setIcon();
|
||||
m_trayIcon->setToolTip("Logos Core POC");
|
||||
m_trayIcon->setToolTip("Logos App");
|
||||
|
||||
// Create context menu
|
||||
m_trayIconMenu = new QMenu(this);
|
||||
@@ -192,6 +260,15 @@ void Window::setIcon()
|
||||
|
||||
void Window::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
// In full screen, close only exits full screen (Discord-style); do not hide
|
||||
if (windowState() & Qt::WindowFullScreen) {
|
||||
setWindowState(Qt::WindowNoState);
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_trayIcon && m_trayIcon->isVisible()) {
|
||||
// Hide the window instead of closing
|
||||
hide();
|
||||
@@ -200,7 +277,7 @@ void Window::closeEvent(QCloseEvent *event)
|
||||
// Show a message to inform the user
|
||||
if (m_trayIcon->supportsMessages()) {
|
||||
m_trayIcon->showMessage(
|
||||
tr("Logos Core POC"),
|
||||
tr("Logos App"),
|
||||
tr("The application will continue to run in the system tray. "
|
||||
"Click the tray icon to restore the window."),
|
||||
QSystemTrayIcon::Information,
|
||||
|
||||
+12
-2
@@ -8,6 +8,9 @@ class LogosAPI;
|
||||
class QMenu;
|
||||
class QAction;
|
||||
class QCloseEvent;
|
||||
class QResizeEvent;
|
||||
class QShowEvent;
|
||||
class QWidget;
|
||||
|
||||
class Window : public QMainWindow
|
||||
{
|
||||
@@ -19,7 +22,10 @@ public:
|
||||
~Window();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void showHideWindow();
|
||||
@@ -30,12 +36,16 @@ private:
|
||||
void setupUi();
|
||||
void createTrayIcon();
|
||||
void setIcon();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void setupMacOSDockReopen();
|
||||
#endif
|
||||
|
||||
LogosAPI* m_logosAPI;
|
||||
QSystemTrayIcon* m_trayIcon;
|
||||
QMenu* m_trayIconMenu;
|
||||
QAction* m_showHideAction;
|
||||
QAction* m_quitAction;
|
||||
QWidget* m_trafficLightsTitleBar = nullptr;
|
||||
};
|
||||
|
||||
#endif // WINDOW_H
|
||||
#endif // WINDOW_H
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
description = "Logos App POC - Qt application with UI plugins";
|
||||
description = "Logos App - Qt application with UI plugins";
|
||||
|
||||
inputs = {
|
||||
# Follow the same nixpkgs as logos-liblogos to ensure compatibility
|
||||
@@ -168,7 +168,7 @@
|
||||
export LOGOS_PACKAGE_MANAGER_SRC="${logosPackageManagerSrc}"
|
||||
export LOGOS_CAPABILITY_MODULE_SRC="${logosCapabilityModuleSrc}"
|
||||
|
||||
echo "Logos App POC development environment"
|
||||
echo "Logos App development environment"
|
||||
echo ""
|
||||
echo "Nix packages (host builds):"
|
||||
echo " LOGOS_CPP_SDK_ROOT: $LOGOS_CPP_SDK_ROOT"
|
||||
|
||||
@@ -100,7 +100,7 @@ void MainContainer::setupUi()
|
||||
// Create main horizontal layout
|
||||
m_mainLayout = new QHBoxLayout(this);
|
||||
m_mainLayout->setSpacing(0);
|
||||
m_mainLayout->setContentsMargins(4, 2, 4, 2);
|
||||
m_mainLayout->setContentsMargins(4, 0, 4, 2);
|
||||
// When QML_UI is set, add it to each QML engine's import path so nested
|
||||
// components (e.g. SidebarIconButton) load from disk — no rebuild for UI changes.
|
||||
QString qmlUiPath = QProcessEnvironment::systemEnvironment().value("QML_UI", "");
|
||||
@@ -119,8 +119,8 @@ void MainContainer::setupUi()
|
||||
qDebug() << "Sidebar engine import paths:" << m_sidebarWidget->engine()->importPathList();
|
||||
m_sidebarWidget->rootContext()->setContextProperty("backend", m_backend);
|
||||
m_sidebarWidget->setSource(resolveQmlUrl("qml/panels/SidebarPanel.qml"));
|
||||
m_sidebarWidget->setMinimumWidth(80);
|
||||
m_sidebarWidget->setMaximumWidth(80);
|
||||
m_sidebarWidget->setMinimumWidth(60);
|
||||
m_sidebarWidget->setMaximumWidth(60);
|
||||
// set clear color to sidebar so that rounded corners don't show white
|
||||
m_sidebarWidget->setClearColor(bgColor);
|
||||
|
||||
@@ -128,7 +128,7 @@ void MainContainer::setupUi()
|
||||
QWidget* contentArea = new QWidget(this);
|
||||
QVBoxLayout* contentLayout = new QVBoxLayout(contentArea);
|
||||
contentLayout->setSpacing(0);
|
||||
contentLayout->setContentsMargins(4, 4, 4, 4);
|
||||
contentLayout->setContentsMargins(4, 9, 4, 4);
|
||||
// Create content stack
|
||||
m_contentStack = new QStackedWidget(contentArea);
|
||||
m_contentStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
@@ -14,7 +14,6 @@ MdiView::MdiView(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, windowCounter(0)
|
||||
, m_mdiAddBtn(nullptr)
|
||||
, m_emptyPlaceholder(nullptr)
|
||||
{
|
||||
setupUi();
|
||||
addMdiWindow();
|
||||
@@ -47,9 +46,6 @@ void MdiView::setupUi()
|
||||
setLayout(mainLayout);
|
||||
mdiArea->setViewMode(QMdiArea::TabbedView);
|
||||
|
||||
m_emptyPlaceholder = new MdiChild(mdiArea);
|
||||
m_emptyPlaceholder->setVisible(false);
|
||||
m_emptyPlaceholder->setGeometry(mdiArea->rect());
|
||||
mdiArea->installEventFilter(this);
|
||||
|
||||
// Ensure tab bar styling applies after the tab bar is created
|
||||
@@ -90,8 +86,7 @@ void MdiView::updateTabCloseButtons()
|
||||
if (mdiArea->viewMode() == QMdiArea::TabbedView) {
|
||||
QTabBar* tabBar = mdiArea->findChild<QTabBar*>();
|
||||
if (tabBar) {
|
||||
tabBar->setTabsClosable(true);
|
||||
|
||||
tabBar->setTabsClosable(false);
|
||||
disconnect(tabBar, &QTabBar::tabCloseRequested, nullptr, nullptr);
|
||||
|
||||
connect(tabBar, &QTabBar::tabCloseRequested, [this](int index) {
|
||||
@@ -112,8 +107,6 @@ void MdiView::updateTabCloseButtons()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateEmptyPlaceholder();
|
||||
}
|
||||
|
||||
void MdiView::insetTabBarGeometry(QTabBar *tabBar, int insetPx)
|
||||
@@ -151,8 +144,7 @@ void MdiView::customizeTabBarStyle(QTabBar* tabBar)
|
||||
tabBar->setElideMode(Qt::ElideRight);
|
||||
tabBar->setUsesScrollButtons(false);
|
||||
tabBar->setExpanding(false);
|
||||
tabBar->setFixedHeight(44);
|
||||
tabBar->setIconSize(QSize(20, 20));
|
||||
tabBar->setIconSize(QSize(15, 15));
|
||||
QScroller::grabGesture(tabBar, QScroller::LeftMouseButtonGesture);
|
||||
QScroller::grabGesture(tabBar, QScroller::TouchGesture);
|
||||
QScrollerProperties props = QScroller::scroller(tabBar)->scrollerProperties();
|
||||
@@ -172,16 +164,12 @@ void MdiView::customizeTabBarStyle(QTabBar* tabBar)
|
||||
background: #262626;
|
||||
color: #A4A4A4;
|
||||
|
||||
padding: 0px 24px 0px 32px;
|
||||
padding: 0px 8px 0px 4px;
|
||||
margin-right: 10px;
|
||||
margin-left: 0px;
|
||||
|
||||
margin-top: 9px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
height: 35px;
|
||||
height: 20px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
@@ -193,20 +181,43 @@ void MdiView::customizeTabBarStyle(QTabBar* tabBar)
|
||||
QTabBar::tab:hover {
|
||||
background: #262626;
|
||||
}
|
||||
|
||||
QTabBar::close-button {
|
||||
image: url(:/icons/close.png);
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-left: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
QTabBar::close-button:hover {
|
||||
background: #262626;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
)"));
|
||||
installTabBarCloseButtons(tabBar);
|
||||
}
|
||||
|
||||
void MdiView::installTabBarCloseButtons(QTabBar* tabBar)
|
||||
{
|
||||
if (!tabBar) return;
|
||||
const QTabBar::ButtonPosition closeSide = QTabBar::LeftSide;
|
||||
for (int i = 0; i < tabBar->count(); ++i) {
|
||||
QWidget* oldBtn = tabBar->tabButton(i, closeSide);
|
||||
if (oldBtn) {
|
||||
tabBar->setTabButton(i, closeSide, nullptr);
|
||||
oldBtn->deleteLater();
|
||||
}
|
||||
QToolButton* btn = new QToolButton(tabBar);
|
||||
btn->setIcon(QIcon(QStringLiteral(":/icons/close.png")));
|
||||
btn->setIconSize(QSize(12, 12));
|
||||
btn->setFixedSize(12, 12);
|
||||
btn->setCursor(Qt::PointingHandCursor);
|
||||
btn->setStyleSheet(QStringLiteral(R"(
|
||||
QToolButton { background: transparent; border: none; }
|
||||
QToolButton:hover { background: rgba(255,255,255,0.1); border-radius: 6px; }
|
||||
)"));
|
||||
connect(btn, &QToolButton::clicked, this, [tabBar, btn, closeSide]() {
|
||||
for (int j = 0; j < tabBar->count(); ++j) {
|
||||
if (tabBar->tabButton(j, closeSide) == btn) {
|
||||
tabBar->tabCloseRequested(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
btn->setVisible(false); // show only on tab hover
|
||||
btn->installEventFilter(this); // keep visible when hovering the button itself
|
||||
tabBar->setTabButton(i, closeSide, btn);
|
||||
}
|
||||
tabBar->setMouseTracking(true); // needed for hover-to-show close buttons
|
||||
}
|
||||
|
||||
void MdiView::ensureMdiAddButton(QTabBar* tabBar)
|
||||
@@ -219,20 +230,17 @@ void MdiView::ensureMdiAddButton(QTabBar* tabBar)
|
||||
if (!m_mdiAddBtn) {
|
||||
m_mdiAddBtn = new QToolButton(tabBar->parentWidget());
|
||||
m_mdiAddBtn->setIcon(QIcon(":/icons/add-button.png"));
|
||||
m_mdiAddBtn->setIconSize(QSize(24, 24));
|
||||
m_mdiAddBtn->setIconSize(QSize(15, 15));
|
||||
m_mdiAddBtn->setAutoRaise(true);
|
||||
m_mdiAddBtn->setCursor(Qt::PointingHandCursor);
|
||||
m_mdiAddBtn->setFixedSize(42, 35);
|
||||
m_mdiAddBtn->setFixedSize(25, 19);
|
||||
m_mdiAddBtn->setStyleSheet(QStringLiteral(R"(
|
||||
QToolButton {
|
||||
background: #2A2A2A;
|
||||
color: #FFFFFF;
|
||||
border-top-left-radius: 14px;
|
||||
border-top-right-radius: 14px;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 2px;
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
padding-top: 1px;
|
||||
}
|
||||
QToolButton:hover {
|
||||
background: #262626;
|
||||
@@ -283,34 +291,29 @@ void MdiView::repositionMdiAddButton()
|
||||
m_mdiAddBtn->raise();
|
||||
}
|
||||
|
||||
void MdiView::updateEmptyPlaceholder()
|
||||
{
|
||||
if (!m_emptyPlaceholder || !mdiArea)
|
||||
return;
|
||||
|
||||
const bool empty = mdiArea->subWindowList().isEmpty();
|
||||
m_emptyPlaceholder->setVisible(empty);
|
||||
if (empty) {
|
||||
int top = 0;
|
||||
if (QTabBar* bar = mdiArea->findChild<QTabBar*>())
|
||||
top = bar->mapTo(mdiArea, QPoint(0, bar->height())).y();
|
||||
m_emptyPlaceholder->setGeometry(0, top, mdiArea->width(), mdiArea->height() - top);
|
||||
m_emptyPlaceholder->raise();
|
||||
}
|
||||
}
|
||||
|
||||
bool MdiView::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
if (m_emptyPlaceholder && mdiArea && watched == mdiArea) {
|
||||
if (event->type() == QEvent::Resize || event->type() == QEvent::Show) {
|
||||
updateEmptyPlaceholder();
|
||||
}
|
||||
}
|
||||
|
||||
QTabBar* tabBar = mdiArea->findChild<QTabBar*>();
|
||||
if (tabBar && watched == tabBar) {
|
||||
if (event->type() == QEvent::Resize || event->type() == QEvent::Show) {
|
||||
repositionMdiAddButton();
|
||||
} else if (event->type() == QEvent::MouseMove) {
|
||||
const QPoint pos = tabBar->mapFromGlobal(QCursor::pos());
|
||||
for (int i = 0; i < tabBar->count(); ++i) {
|
||||
QWidget* closeBtn = tabBar->tabButton(i, QTabBar::LeftSide);
|
||||
if (closeBtn) {
|
||||
const QRect tabRect = tabBar->tabRect(i);
|
||||
const bool overTabOrButton = tabRect.contains(pos)
|
||||
|| closeBtn->geometry().contains(pos);
|
||||
closeBtn->setVisible(overTabOrButton);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::Leave) {
|
||||
for (int i = 0; i < tabBar->count(); ++i) {
|
||||
QWidget* closeBtn = tabBar->tabButton(i, QTabBar::LeftSide);
|
||||
if (closeBtn)
|
||||
closeBtn->setVisible(false);
|
||||
}
|
||||
} else if (event->type() == QEvent::Wheel && tabBar->count() > 1) {
|
||||
auto *wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
int delta = 0;
|
||||
@@ -327,6 +330,20 @@ bool MdiView::eventFilter(QObject* watched, QEvent* event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close button hover: show when pointer enters the button, hide on leave
|
||||
if (tabBar) {
|
||||
for (int i = 0; i < tabBar->count(); ++i) {
|
||||
if (tabBar->tabButton(i, QTabBar::LeftSide) == watched) {
|
||||
auto* w = static_cast<QWidget*>(watched);
|
||||
if (event->type() == QEvent::Enter)
|
||||
w->setVisible(true);
|
||||
else if (event->type() == QEvent::Leave)
|
||||
w->setVisible(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ private:
|
||||
|
||||
void ensureMdiAddButton(QTabBar* tabBar);
|
||||
void repositionMdiAddButton();
|
||||
void updateEmptyPlaceholder();
|
||||
|
||||
void customizeTabBarStyle(QTabBar* tabBar);
|
||||
void installTabBarCloseButtons(QTabBar* tabBar);
|
||||
void insetTabBarGeometry(QTabBar *tabBar, int insetPx);
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
@@ -57,8 +57,7 @@ private:
|
||||
QToolBar *toolBar;
|
||||
QVBoxLayout *mainLayout;
|
||||
QToolButton* m_mdiAddBtn;
|
||||
QWidget* m_emptyPlaceholder;
|
||||
|
||||
|
||||
// Map to keep track of plugin widgets and their MDI windows
|
||||
QMap<QWidget*, QMdiSubWindow*> m_pluginWindows;
|
||||
// Reverse map: subwindow -> widget
|
||||
|
||||
@@ -5,8 +5,8 @@ import Logos.Theme
|
||||
AbstractButton {
|
||||
id: root
|
||||
|
||||
implicitHeight: 50
|
||||
implicitWidth: 50
|
||||
implicitHeight: 38
|
||||
implicitWidth: 38
|
||||
|
||||
// Dark gray pill background extending to left edge when active/highlighted
|
||||
background: Rectangle {
|
||||
|
||||
@@ -9,7 +9,7 @@ Control {
|
||||
property alias contentModel: repeater.model
|
||||
signal moduleClicked(string name, int index)
|
||||
|
||||
padding: Theme.spacing.medium
|
||||
padding: Theme.spacing.small
|
||||
|
||||
background: Rectangle {
|
||||
id: bg
|
||||
|
||||
@@ -18,7 +18,8 @@ Control {
|
||||
signal updateLauncherIndex(int index)
|
||||
|
||||
padding: 0
|
||||
topPadding: Theme.spacing.large
|
||||
topPadding: Theme.spacing.large + _d.systemTitleBarPadding
|
||||
topInset: _d.systemTitleBarPadding
|
||||
|
||||
QtObject {
|
||||
id: _d
|
||||
@@ -39,6 +40,8 @@ Control {
|
||||
readonly property var unloadedApps: (root.launcherApps || []).filter(function(item) {
|
||||
return item && item.isLoaded === false
|
||||
})
|
||||
|
||||
readonly property int systemTitleBarPadding: Qt.platform.os === "osx" ? 30: 0
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
@@ -51,8 +54,8 @@ Control {
|
||||
|
||||
Image {
|
||||
// As per design
|
||||
Layout.preferredWidth: 64
|
||||
Layout.preferredHeight: 34
|
||||
Layout.preferredWidth: 46
|
||||
Layout.preferredHeight: 25
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
source: "qrc:/icons/basecamp.png"
|
||||
}
|
||||
|
||||
+18
-13
@@ -1,4 +1,4 @@
|
||||
# Builds the logos-app-poc standalone application
|
||||
# Builds the logos-app standalone application
|
||||
{ pkgs, common, src, logosLiblogos, logosSdk, logosPackageManager, logosCapabilityModule, logosDesignSystem, counterPlugin, counterQmlPlugin, mainUIPlugin, packageManagerUIPlugin, webviewAppPlugin }:
|
||||
|
||||
let
|
||||
@@ -7,7 +7,7 @@ let
|
||||
webkitgtk = pkgs.webkitgtk_4_1 or pkgs.webkitgtk_4_0 or pkgs.webkitgtk;
|
||||
in
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
pname = "logos-app-poc-app";
|
||||
pname = "logos-app";
|
||||
version = common.version;
|
||||
|
||||
inherit src;
|
||||
@@ -91,12 +91,9 @@ pkgs.stdenv.mkDerivation rec {
|
||||
# This is an aggregate runtime layout; avoid stripping to prevent hook errors
|
||||
dontStrip = true;
|
||||
|
||||
# Ensure proper Qt environment setup via wrapper
|
||||
qtWrapperArgs = [
|
||||
"--prefix" "LD_LIBRARY_PATH" ":" qtLibPath
|
||||
"--prefix" "QT_PLUGIN_PATH" ":" qtPluginPath
|
||||
"--prefix" "QML2_IMPORT_PATH" ":" qmlImportPath
|
||||
];
|
||||
# Skip wrapQtApps: wrapper renames binary to .LogosApp-wrapped; macOS Dock uses executable filename
|
||||
# We create a custom launcher that execs the binary (keeps process name "LogosApp")
|
||||
dontWrapQtApps = true;
|
||||
|
||||
# Additional environment variables for Qt and RPATH cleanup
|
||||
preFixup = ''
|
||||
@@ -136,7 +133,7 @@ pkgs.stdenv.mkDerivation rec {
|
||||
configurePhase = ''
|
||||
runHook preConfigure
|
||||
|
||||
echo "Configuring logos-app-poc-app..."
|
||||
echo "Configuring logos-app..."
|
||||
echo "liblogos: ${logosLiblogos}"
|
||||
echo "cpp-sdk: ${logosSdk}"
|
||||
echo "package-manager: ${logosPackageManager}"
|
||||
@@ -177,7 +174,7 @@ pkgs.stdenv.mkDerivation rec {
|
||||
runHook preBuild
|
||||
|
||||
cmake --build build
|
||||
echo "logos-app-poc-app built successfully!"
|
||||
echo "logos-app built successfully!"
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
@@ -271,12 +268,20 @@ pkgs.stdenv.mkDerivation rec {
|
||||
|
||||
# Note: webview_app QML and HTML files are now embedded in the plugin via qrc
|
||||
|
||||
# Create symlink for the expected binary name
|
||||
ln -s $out/bin/LogosApp $out/bin/logos-app-poc-app
|
||||
# Create launcher script (sets Qt env, execs binary - process name stays "LogosApp" for Dock)
|
||||
cat > $out/bin/logos-app << 'EOF'
|
||||
#!/bin/sh
|
||||
EOF
|
||||
echo "export QT_PLUGIN_PATH=\"${qtPluginPath}\"" >> $out/bin/logos-app
|
||||
echo "export QML2_IMPORT_PATH=\"${qmlImportPath}\"" >> $out/bin/logos-app
|
||||
echo "export DYLD_LIBRARY_PATH=\"${qtLibPath}:\$DYLD_LIBRARY_PATH\"" >> $out/bin/logos-app
|
||||
echo "export LD_LIBRARY_PATH=\"${qtLibPath}:\$LD_LIBRARY_PATH\"" >> $out/bin/logos-app
|
||||
echo 'exec "$(dirname "$0")/LogosApp" "$@"' >> $out/bin/logos-app
|
||||
chmod +x $out/bin/logos-app
|
||||
|
||||
# Create a README for reference
|
||||
cat > $out/README.txt <<EOF
|
||||
Logos App POC - Build Information
|
||||
Logos App - Build Information
|
||||
==================================
|
||||
liblogos: ${logosLiblogos}
|
||||
cpp-sdk: ${logosSdk}
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ let
|
||||
runtimeLibsStr = pkgs.lib.concatStringsSep " " (map toString runtimeLibs);
|
||||
in
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
pname = "logos-app-poc-appimage";
|
||||
pname = "logos-app-appimage";
|
||||
inherit version;
|
||||
|
||||
dontUnpack = true;
|
||||
@@ -77,7 +77,7 @@ pkgs.stdenv.mkDerivation rec {
|
||||
cat > "$appDir/usr/share/applications/logos-app.desktop" <<'EOF'
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Logos App POC
|
||||
Name=Logos App
|
||||
Exec=LogosApp
|
||||
Icon=logos-app
|
||||
Categories=Utility;
|
||||
@@ -114,7 +114,7 @@ EOF
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Logos App POC AppImage";
|
||||
description = "Logos App AppImage";
|
||||
platforms = platforms.linux;
|
||||
mainProgram = "LogosApp";
|
||||
};
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
{ pkgs, logosSdk, logosLiblogos }:
|
||||
|
||||
{
|
||||
pname = "logos-app-poc";
|
||||
pname = "logos-app";
|
||||
version = "1.0.0";
|
||||
|
||||
# Common native build inputs
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
# Metadata
|
||||
meta = with pkgs.lib; {
|
||||
description = "Logos App POC - Qt application with UI plugins";
|
||||
description = "Logos App - Qt application with UI plugins";
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
||||
|
||||
+5
-5
@@ -30,22 +30,22 @@ fi
|
||||
|
||||
# Print the paths being used
|
||||
echo "================================================"
|
||||
echo "Starting Logos App POC in DEVELOPMENT mode"
|
||||
echo "Starting Logos App in DEVELOPMENT mode"
|
||||
echo "================================================"
|
||||
echo "QML_UI path: $QML_UI"
|
||||
echo ""
|
||||
echo "QML files will be loaded from the filesystem."
|
||||
echo "The QML_UI path is also added to the engine import path, so"
|
||||
echo "nested components (e.g. SidebarIconButton) load from disk too."
|
||||
echo "Edit QML files and restart the app to see changes (no rebuild)."
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Run the app from the nix result
|
||||
if [ -f "./result/bin/LogosApp" ]; then
|
||||
# Use logos-app launcher (sets Qt env, execs LogosApp binary - Dock shows "LogosApp")
|
||||
if [ -f "./result/bin/logos-app" ]; then
|
||||
./result/bin/logos-app "$@"
|
||||
elif [ -f "./result/bin/LogosApp" ]; then
|
||||
./result/bin/LogosApp "$@"
|
||||
elif [ -f "./result/bin/logos-app-poc-app" ]; then
|
||||
./result/bin/logos-app-poc-app "$@"
|
||||
else
|
||||
echo "Error: Application binary not found in ./result/bin/"
|
||||
echo "Please build the app first with: nix build"
|
||||
|
||||
Reference in New Issue
Block a user