change: UI and migrate to gtest

This commit is contained in:
2026-07-27 05:27:32 +08:00
parent dd5508e571
commit a84e75ef47
56 changed files with 4484 additions and 4949 deletions
+32
View File
@@ -44,12 +44,44 @@ MainStatusBar::MainStatusBar(QWidget *parent)
bar_->setMaximum(100);
bar_->setVisible(false);
// Permanent right-hand sequence info chips (resolution + frame rate)
resolution_label_ = new QLabel();
fps_label_ = new QLabel();
resolution_label_->setContentsMargins(6, 0, 6, 0);
fps_label_->setContentsMargins(6, 0, 6, 0);
addPermanentWidget(resolution_label_);
addPermanentWidget(fps_label_);
resolution_label_->setVisible(false);
fps_label_->setVisible(false);
showMessage(tr("Welcome to %1 %2")
.arg(QCoreApplication::applicationName(),
QCoreApplication::applicationVersion()),
10000);
}
void MainStatusBar::set_sequence_info(int width, int height, double fps)
{
if (width <= 0 || height <= 0) {
resolution_label_->setVisible(false);
fps_label_->setVisible(false);
return;
}
resolution_label_->setText(QStringLiteral("%1\u00d7%2").arg(width).arg(height));
// Show the frame rate as an integer when it is whole, otherwise keep one
// decimal place (e.g. 23.976 FPS).
const double rounded = qRound(fps);
QString fps_str = (qFuzzyCompare(fps, rounded))
? QString::number(static_cast<int>(rounded))
: QString::number(fps, 'f', 2);
fps_label_->setText(tr("%1 FPS").arg(fps_str));
resolution_label_->setVisible(true);
fps_label_->setVisible(true);
}
void MainStatusBar::connect_task_manager(EngineEventBridge *bridge)
{
bridge_ = bridge;
+16
View File
@@ -22,6 +22,7 @@
#ifndef OAK_MAINSTATUSBAR_H
#define OAK_MAINSTATUSBAR_H
#include <QLabel>
#include <QProgressBar>
#include <QStatusBar>
@@ -34,6 +35,10 @@ class EngineEventBridge;
/**
* @brief Shows abbreviated information from the global TaskManager
*
* Per the Oak UI design reference the status bar is a global information
* strip. The transient task message is shown on the left while the active
* sequence's resolution and frame rate are shown permanently on the right.
*/
class MainStatusBar : public QStatusBar {
Q_OBJECT
@@ -42,6 +47,14 @@ public:
void connect_task_manager(EngineEventBridge *bridge);
/**
* @brief Update the permanent right-hand sequence info chips.
*
* Plain (non-slot) method taking primitives so no engine C++ type leaks
* into the MOC-processed header. Pass width <= 0 to clear the chips.
*/
void set_sequence_info(int width, int height, double fps);
signals:
void double_clicked();
@@ -60,6 +73,9 @@ private:
QProgressBar *bar_;
QLabel *resolution_label_;
QLabel *fps_label_;
OakEngineTask *connected_task_;
int64_t task_progress_sub_;
+57 -54
View File
@@ -25,7 +25,6 @@
#include <QDebug>
#include <QMessageBox>
#include <QScreen>
#include <QToolBar>
#ifdef Q_OS_LINUX
#include <QOffscreenSurface>
@@ -44,7 +43,6 @@
#include "oakengine/undo.h"
#include "widget/viewer/vieweroutpututils.h"
#include "widget/toolbar/toolbar.h"
#include "core.h"
namespace olive
{
@@ -84,34 +82,11 @@ MainWindow::MainWindow(QWidget *parent)
// Create and set status bar
event_bridge_ = new EngineEventBridge(this);
MainStatusBar *status_bar = new MainStatusBar(this);
status_bar->connect_task_manager(event_bridge_);
connect(status_bar, &MainStatusBar::double_clicked, this,
status_bar_ = new MainStatusBar(this);
status_bar_->connect_task_manager(event_bridge_);
connect(status_bar_, &MainStatusBar::double_clicked, this,
&MainWindow::status_bar_double_clicked);
setStatusBar(status_bar);
// Create application toolbar (31px) — replaces the dockable ToolPanel by default
tool_bar_ = new QToolBar(this);
tool_bar_->setObjectName(QStringLiteral("AppToolbar"));
tool_bar_->setFixedHeight(31);
tool_bar_->setMovable(false);
tool_bar_->setFloatable(false);
Toolbar *toolbar_widget = new Toolbar(tool_bar_);
toolbar_widget->set_tool(Core::instance()->tool());
toolbar_widget->set_snapping(Core::instance()->snapping());
tool_bar_->addWidget(toolbar_widget);
addToolBar(Qt::TopToolBarArea, tool_bar_);
connect(toolbar_widget, &Toolbar::tool_changed, Core::instance(),
&Core::set_tool);
connect(Core::instance(), &Core::tool_changed, toolbar_widget,
&Toolbar::set_tool);
connect(toolbar_widget, &Toolbar::snapping_changed, Core::instance(),
&Core::set_snapping);
connect(Core::instance(), &Core::snapping_changed, toolbar_widget,
&Toolbar::set_snapping);
connect(toolbar_widget, &Toolbar::selected_transition_changed,
Core::instance(), &Core::set_selected_transition_object);
setStatusBar(status_bar_);
// Create standard panels
node_panel_ = new NodePanel();
@@ -772,6 +747,15 @@ void MainWindow::timeline_focused(ViewerOutput *viewer)
multicam_panel_->connect_viewer_node(viewer);
param_panel_->connect_viewer_node(viewer);
curve_panel_->connect_viewer_node(viewer);
// Update the global status bar info chips (resolution + frame rate)
if (viewer) {
VideoParams vp = viewer_output_video_params(viewer);
status_bar_->set_sequence_info(vp.width(), vp.height(),
vp.frame_rate().to_double());
} else {
status_bar_->set_sequence_info(0, 0, 0.0);
}
}
QString MainWindow::get_custom_shortcuts_file()
@@ -947,36 +931,56 @@ void MainWindow::focused_panel_changed(PanelWidget *panel)
void MainWindow::set_default_layout()
{
// Default layout per the Oak UI design reference (design/*.png):
//
// ┌─────────────┬───────────────────────────┬──────────────┐
// │ 素材查看器 │ 序列查看器 | 节点编辑器 │ 检查器|历史 │
// ├─────────────┤ │ │
// │ 项目 │ │ │
// ├─────────────┴───────────────────────────┴──────────────┤
// │ 工具条(31px) + 时间线 (full width) │
// ├────────────────────────────────────────────────────────┤
// │ 音频监视器 (26px thin strip) │
// └────────────────────────────────────────────────────────┘
KDDockWidgets::InitialOption o;
o.preferredSize = QSize(0, centralAreaGeometry().height());
// Top left - Tabify footage viewer, param panel, and node panel
addDockWidget(footage_viewer_panel_, KDDockWidgets::Location_OnTop, nullptr,
o);
footage_viewer_panel_->addDockWidgetAsTab(param_panel_);
footage_viewer_panel_->addDockWidgetAsTab(node_panel_);
param_panel_->raise();
// Top right - sequence viewer
addDockWidget(sequence_viewer_panel_, KDDockWidgets::Location_OnRight,
footage_viewer_panel_, o);
// Bottom center - timelines
// Timeline at the very bottom, spanning the full window width
addDockWidget(timeline_panels_.first(), KDDockWidgets::Location_OnBottom);
// Right of timeline - audio monitor
o.preferredSize = QSize(320, 0);
addDockWidget(audio_monitor_panel_, KDDockWidgets::Location_OnRight,
// Audio monitor: 26px ultra-thin strip below the timeline
o.preferredSize = QSize(0, 26);
addDockWidget(audio_monitor_panel_, KDDockWidgets::Location_OnBottom,
timeline_panels_.first(), o);
// Bottom left - project panel (tool panel is now the top toolbar;
// the dockable ToolPanel remains available via Window menu)
addDockWidget(project_panel_, KDDockWidgets::Location_OnLeft,
timeline_panels_.first());
project_panel_->addDockWidgetAsTab(history_panel_);
// Three-column workspace above the timeline. Establish the horizontal
// (left -> right) structure first so the column separators span the full
// workspace height, then subdivide the left column vertically.
o = KDDockWidgets::InitialOption();
o.preferredSize = QSize(0, centralAreaGeometry().height());
// Left column - footage viewer (top-left anchor)
addDockWidget(footage_viewer_panel_, KDDockWidgets::Location_OnTop, nullptr,
o);
// Center column - sequence viewer tabified with node editor
addDockWidget(sequence_viewer_panel_, KDDockWidgets::Location_OnRight,
footage_viewer_panel_, o);
sequence_viewer_panel_->addDockWidgetAsTab(node_panel_);
sequence_viewer_panel_->raise();
// Right column - inspector (param panel) with history
addDockWidget(param_panel_, KDDockWidgets::Location_OnRight,
sequence_viewer_panel_, o);
param_panel_->addDockWidgetAsTab(history_panel_);
param_panel_->raise();
// Left column bottom - project panel (below footage viewer)
addDockWidget(project_panel_, KDDockWidgets::Location_OnBottom,
footage_viewer_panel_);
project_panel_->raise();
// Hidden panels
// Hidden panels (all remain accessible via the Window menu)
tool_panel_->close();
pixel_sampler_panel_->close();
task_man_panel_->close();
@@ -991,9 +995,8 @@ void MainWindow::set_default_layout()
}
for (auto it = timeline_panels_.cbegin(); it != timeline_panels_.cend();
it++) {
auto p = *it;
if (p != timeline_panels_.first()) {
p->addDockWidgetAsTab(p);
if (*it != timeline_panels_.first()) {
(*it)->close();
}
}
+2 -5
View File
@@ -25,8 +25,6 @@
#include <kddockwidgets/Config.h>
#include <kddockwidgets/MainWindow.h>
#include <QToolBar>
#include "node/project/serializer/serializedlayoutinfo.h"
#include "node/project.h"
#include "panel/multicam/multicampanel.h"
@@ -55,6 +53,7 @@ namespace olive
{
class EngineEventBridge;
class MainStatusBar;
/**
* @brief Olive's main window responsible for docking widgets and the main menu bar.
@@ -154,9 +153,6 @@ private:
QByteArray premaximized_state_;
// Application toolbar (31px, replaces the dockable ToolPanel by default)
QToolBar *tool_bar_;
// Standard panels
ProjectPanel *project_panel_;
NodePanel *node_panel_;
@@ -170,6 +166,7 @@ private:
AudioMonitorPanel *audio_monitor_panel_;
TaskManagerPanel *task_man_panel_;
EngineEventBridge *event_bridge_;
MainStatusBar *status_bar_;
PixelSamplerPanel *pixel_sampler_panel_;
ScopePanel *scope_panel_;
QList<ViewerPanel *> viewer_panels_;