223 lines
8.6 KiB
C++
223 lines
8.6 KiB
C++
/***
|
|
|
|
Olive - Non-Linear Video Editor
|
|
Copyright (C) 2019 Olive Team
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
#include "mainwindow.h"
|
|
|
|
#include <QApplication>
|
|
#include <QDebug>
|
|
#include <QDesktopWidget>
|
|
#include <QMessageBox>
|
|
|
|
#include "mainmenu.h"
|
|
#include "mainstatusbar.h"
|
|
|
|
MainWindow::MainWindow(QWidget *parent) :
|
|
QMainWindow(parent)
|
|
{
|
|
#ifdef Q_OS_WINDOWS
|
|
// Qt on Windows has a bug that "de-maximizes" the window when widgets are added, resizing the window beforehand
|
|
// works around that issue and we just set it to whatever size is available
|
|
resize(qApp->desktop()->availableGeometry(this).size());
|
|
#endif
|
|
|
|
// Create empty central widget - we don't actually want a central widget but some of Qt's docking/undocking fails
|
|
// without it
|
|
QWidget* centralWidget = new QWidget(this);
|
|
centralWidget->setMaximumSize(QSize(0, 0));
|
|
setCentralWidget(centralWidget);
|
|
|
|
// Set tabs to be on top of panels (default behavior is bottom)
|
|
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
|
|
|
|
// Allow panels to be tabbed within each other
|
|
setDockNestingEnabled(true);
|
|
|
|
// Create and set main menu
|
|
MainMenu* main_menu = new MainMenu(this);
|
|
setMenuBar(main_menu);
|
|
|
|
// Create and set status bar
|
|
MainStatusBar* status_bar = new MainStatusBar(this);
|
|
status_bar->ConnectTaskManager(TaskManager::instance());
|
|
setStatusBar(status_bar);
|
|
|
|
// Create standard panels
|
|
node_panel_ = PanelManager::instance()->CreatePanel<NodePanel>(this);
|
|
addDockWidget(Qt::TopDockWidgetArea, node_panel_);
|
|
footage_viewer_panel_ = PanelManager::instance()->CreatePanel<FootageViewerPanel>(this);
|
|
addDockWidget(Qt::TopDockWidgetArea, footage_viewer_panel_);
|
|
param_panel_ = PanelManager::instance()->CreatePanel<ParamPanel>(this);
|
|
tabifyDockWidget(footage_viewer_panel_, param_panel_);
|
|
footage_viewer_panel_->raise();
|
|
viewer_panel_ = PanelManager::instance()->CreatePanel<ViewerPanel>(this);
|
|
addDockWidget(Qt::TopDockWidgetArea, viewer_panel_);
|
|
project_panel_ = PanelManager::instance()->CreatePanel<ProjectPanel>(this);
|
|
addDockWidget(Qt::BottomDockWidgetArea, project_panel_);
|
|
tool_panel_ = PanelManager::instance()->CreatePanel<ToolPanel>(this);
|
|
addDockWidget(Qt::BottomDockWidgetArea, tool_panel_);
|
|
timeline_panel_ = PanelManager::instance()->CreatePanel<TimelinePanel>(this);
|
|
addDockWidget(Qt::BottomDockWidgetArea, timeline_panel_);
|
|
audio_monitor_panel_ = PanelManager::instance()->CreatePanel<AudioMonitorPanel>(this);
|
|
addDockWidget(Qt::BottomDockWidgetArea, audio_monitor_panel_);
|
|
task_man_panel_ = PanelManager::instance()->CreatePanel<TaskManagerPanel>(this);
|
|
addDockWidget(Qt::BottomDockWidgetArea, task_man_panel_);
|
|
curve_panel_ = PanelManager::instance()->CreatePanel<CurvePanel>(this);
|
|
addDockWidget(Qt::BottomDockWidgetArea, curve_panel_);
|
|
|
|
// FIXME: This is fairly "hardcoded" behavior and doesn't support infinite panels
|
|
connect(node_panel_, &NodePanel::SelectionChanged, param_panel_, &ParamPanel::SetNodes);
|
|
connect(param_panel_, &ParamPanel::SelectedInputChanged, curve_panel_, &CurvePanel::SetInput);
|
|
connect(param_panel_, &ParamPanel::TimebaseChanged, curve_panel_, &CurvePanel::SetTimebase);
|
|
connect(timeline_panel_, &TimelinePanel::TimeChanged, param_panel_, &ParamPanel::SetTime);
|
|
connect(timeline_panel_, &TimelinePanel::TimeChanged, viewer_panel_, &ViewerPanel::SetTime);
|
|
connect(timeline_panel_, &TimelinePanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);
|
|
connect(timeline_panel_, &TimelinePanel::SelectionChanged, node_panel_, &NodePanel::SelectWithDependencies);
|
|
connect(viewer_panel_, &ViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTime);
|
|
connect(viewer_panel_, &ViewerPanel::TimeChanged, timeline_panel_, &TimelinePanel::SetTime);
|
|
connect(viewer_panel_, &ViewerPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);
|
|
connect(param_panel_, &ParamPanel::TimeChanged, viewer_panel_, &ViewerPanel::SetTime);
|
|
connect(param_panel_, &ParamPanel::TimeChanged, timeline_panel_, &TimelinePanel::SetTime);
|
|
connect(param_panel_, &ParamPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);
|
|
connect(curve_panel_, &CurvePanel::TimeChanged, viewer_panel_, &ViewerPanel::SetTime);
|
|
connect(curve_panel_, &CurvePanel::TimeChanged, timeline_panel_, &TimelinePanel::SetTime);
|
|
connect(curve_panel_, &CurvePanel::TimeChanged, param_panel_, &ParamPanel::SetTime);
|
|
connect(viewer_panel_->video_renderer(), &VideoRenderBackend::CachedTimeReady, timeline_panel_->ruler(), &TimeRuler::CacheTimeReady);
|
|
connect(viewer_panel_->video_renderer(), &VideoRenderBackend::RangeInvalidated, timeline_panel_->ruler(), &TimeRuler::CacheInvalidatedRange);
|
|
|
|
viewer_panel_->ConnectTimeBasedPanel(timeline_panel_);
|
|
viewer_panel_->ConnectTimeBasedPanel(param_panel_);
|
|
viewer_panel_->ConnectTimeBasedPanel(curve_panel_);
|
|
|
|
UpdateTitle();
|
|
}
|
|
|
|
void MainWindow::SetFullscreen(bool fullscreen)
|
|
{
|
|
if (fullscreen) {
|
|
setWindowState(windowState() | Qt::WindowFullScreen);
|
|
} else {
|
|
setWindowState(windowState() & ~Qt::WindowFullScreen);
|
|
}
|
|
}
|
|
|
|
void MainWindow::ToggleMaximizedPanel()
|
|
{
|
|
if (premaximized_state_.isEmpty()) {
|
|
// Assume nothing is maximized at the moment
|
|
|
|
// Find the currently focused panel
|
|
PanelWidget* currently_hovered = PanelManager::instance()->CurrentlyHovered();
|
|
|
|
// If no panel is hovered, do nothing
|
|
if (currently_hovered == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// If this panel is not actually on the main window, this is a no-op
|
|
if (currently_hovered->isFloating()) {
|
|
return;
|
|
}
|
|
|
|
// Save the current state so it can be restored later
|
|
premaximized_state_ = saveState();
|
|
|
|
// For every other panel that is on the main window, hide it
|
|
foreach (PanelWidget* panel, PanelManager::instance()->panels()) {
|
|
if (!panel->isFloating() && panel != currently_hovered) {
|
|
panel->setVisible(false);
|
|
}
|
|
}
|
|
} else {
|
|
// Assume we are currently maximized, restore the state
|
|
restoreState(premaximized_state_);
|
|
premaximized_state_.clear();
|
|
}
|
|
}
|
|
|
|
void MainWindow::ProjectOpen(Project* p)
|
|
{
|
|
// FIXME Use settings data to create panels and restore state if they exist
|
|
project_panel_->set_project(p);
|
|
|
|
SetDefaultLayout();
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *e)
|
|
{
|
|
if (isWindowModified()) {
|
|
QMessageBox mb(this);
|
|
|
|
mb.setIcon(QMessageBox::Question);
|
|
mb.setWindowTitle(tr("Unsaved Changes"));
|
|
mb.setText(tr("The project '%1' has unsaved changes. Would you like to save them?")
|
|
.arg(Core::instance()->GetActiveProject()->name()));
|
|
|
|
QPushButton* yes_btn = mb.addButton(tr("Save"), QMessageBox::YesRole);
|
|
mb.addButton(tr("Don't Save"), QMessageBox::NoRole);
|
|
QPushButton* cancel_btn = mb.addButton(QMessageBox::Cancel);
|
|
|
|
mb.exec();
|
|
|
|
if (mb.clickedButton() == cancel_btn
|
|
|| (mb.clickedButton() == yes_btn && !Core::instance()->SaveActiveProject())) {
|
|
// Don't close if the user clicked cancel on this messagebox OR they cancelled a save as operation
|
|
e->ignore();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Close viewers first since we don't want to delete any nodes while they might be mid-render
|
|
QList<ViewerPanel*> viewers = PanelManager::instance()->GetPanelsOfType<ViewerPanel>();
|
|
foreach (ViewerPanel* viewer, viewers) {
|
|
viewer->ConnectViewerNode(nullptr);
|
|
}
|
|
|
|
PanelManager::instance()->DeleteAllPanels();
|
|
|
|
QMainWindow::closeEvent(e);
|
|
}
|
|
|
|
void MainWindow::UpdateTitle()
|
|
{
|
|
setWindowTitle(QStringLiteral("%1 %2 - [*]%3").arg(QApplication::applicationName(),
|
|
QApplication::applicationVersion(),
|
|
tr("(untitled)")));
|
|
}
|
|
|
|
void MainWindow::SetDefaultLayout()
|
|
{
|
|
task_man_panel_->close();
|
|
task_man_panel_->setFloating(true);
|
|
curve_panel_->close();
|
|
curve_panel_->setFloating(true);
|
|
|
|
resizeDocks({node_panel_, param_panel_, viewer_panel_},
|
|
{width()/3, width()/3, width()/3},
|
|
Qt::Horizontal);
|
|
|
|
resizeDocks({project_panel_, tool_panel_, timeline_panel_, audio_monitor_panel_},
|
|
{width()/4, 1, width(), 1},
|
|
Qt::Horizontal);
|
|
|
|
resizeDocks({node_panel_, project_panel_},
|
|
{height()/2, height()/2},
|
|
Qt::Vertical);
|
|
}
|