right click menu in node view for adding nodes

This commit is contained in:
itsmattkc
2019-04-13 15:57:09 +10:00
parent e20b1d35c2
commit 6bf62017ea
18 changed files with 309 additions and 294 deletions
+107
View File
@@ -43,11 +43,13 @@
#include "dialogs/newsequencedialog.h"
#include "dialogs/loaddialog.h"
#include "dialogs/autocutsilencedialog.h"
#include "effects/effectloaders.h"
#include "project/loadthread.h"
#include "project/savethread.h"
#include "timeline/sequence.h"
#include "ui/mediaiconservice.h"
#include "ui/mainwindow.h"
#include "ui/menu.h"
#include "ui/updatenotification.h"
#include "undo/undostack.h"
@@ -450,6 +452,40 @@ void OliveGlobal::PasteInternal(Sequence *s, bool insert)
}
}
void OliveGlobal::EffectMenuAction(QAction *q)
{
ComboAction* ca = new ComboAction();
NodeType node_type = static_cast<NodeType>(q->data().toInt());
Node* n = olive::node_library[node_type].get();
for (int i=0;i<effect_menu_selected_clips.size();i++) {
Clip* c = effect_menu_selected_clips.at(i);
if (c->type() == n->subtype()) {
if (n->type() == EFFECT_TYPE_TRANSITION) {
if (c->opening_transition == nullptr) {
ca->append(new AddTransitionCommand(c,
nullptr,
nullptr,
node_type,
olive::config.default_transition_length));
}
if (c->closing_transition == nullptr) {
ca->append(new AddTransitionCommand(nullptr,
c,
nullptr,
node_type,
olive::config.default_transition_length));
}
} else {
ca->append(new AddEffectCommand(c, nullptr, node_type));
}
}
}
olive::undo_stack.push(ca);
update_ui(true);
}
void OliveGlobal::ImportProject(const QString &fn)
{
LoadProject(fn, false);
@@ -644,6 +680,77 @@ bool OliveGlobal::CheckForActiveSequence(bool show_msg)
return true;
}
void OliveGlobal::ShowEffectMenu(EffectType type, olive::TrackType subtype, const QVector<Clip*> selected_clips)
{
effect_menu_selected_clips = selected_clips;
olive::effects_loaded.lock();
Menu effects_menu(olive::MainWindow);
effects_menu.setToolTipsVisible(true);
for (int i=0;i<olive::node_library.size();i++) {
NodePtr node = olive::node_library.at(i);
if (node != nullptr && node->type() == type && node->subtype() == subtype) {
QAction* action = new QAction(&effects_menu);
action->setText(node->name());
action->setData(i);
if (!node->description().isEmpty()) {
action->setToolTip(node->description());
}
QMenu* parent = &effects_menu;
if (!node->category().isEmpty()) {
bool found = false;
for (int j=0;j<effects_menu.actions().size();j++) {
QAction* action = effects_menu.actions().at(j);
if (action->menu() != nullptr) {
if (action->menu()->title() == node->category()) {
parent = action->menu();
found = true;
break;
}
}
}
if (!found) {
parent = new Menu(&effects_menu);
parent->setToolTipsVisible(true);
parent->setTitle(node->category());
bool found = false;
for (int i=0;i<effects_menu.actions().size();i++) {
QAction* comp_action = effects_menu.actions().at(i);
if (comp_action->text() > node->category()) {
effects_menu.insertMenu(comp_action, parent);
found = true;
break;
}
}
if (!found) effects_menu.addMenu(parent);
}
}
bool found = false;
for (int i=0;i<parent->actions().size();i++) {
QAction* comp_action = parent->actions().at(i);
if (comp_action->text() > action->text()) {
parent->insertAction(comp_action, action);
found = true;
break;
}
}
if (!found) parent->addAction(action);
}
}
olive::effects_loaded.unlock();
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(EffectMenuAction(QAction*)));
effects_menu.exec(QCursor::pos());
}
void OliveGlobal::undo() {
// workaround to prevent crash (and also users should never need to do this)
if (!Timeline::IsImporting()) {
+135 -120
View File
@@ -34,23 +34,23 @@
* A resource for various global functions used throughout Olive.
*/
class OliveGlobal : public QObject {
Q_OBJECT
Q_OBJECT
public:
/**
/**
* @brief OliveGlobal Constructor
*
* Creates Olive Global object. Also sets some default runtime settings and the application name.
*/
OliveGlobal();
OliveGlobal();
/**
/**
* @brief Returns the file dialog filter used when interfacing with Olive project files.
*
* @return The file filter string used by QFileDialog to limit the files shown to Olive (*.ove) files.
*/
const QString& get_project_file_filter();
const QString& get_project_file_filter();
/**
/**
* @brief Change the current active project filename
*
* Triggered to change the current active project filename. Call this before calling any internal project
@@ -63,18 +63,18 @@ public:
* The URL of the project file to work with. Can be an empty string, in which case Olive will treat the project
* as an unsaved project.
*/
void update_project_filename(const QString& s);
void update_project_filename(const QString& s);
/**
/**
* @brief Check whether an auto-recovery file exists and ask the user if they want to load it.
*
* Usually called on initialization. Checks if an auto-recovery file exists (meaning the last session of Olive
* didn't close correctly). If it finds one, asks the user if they want to load it. If so, loads the auto-recovery
* project.
*/
void check_for_autorecovery_file();
void check_for_autorecovery_file();
/**
/**
* @brief Get whether the project is currently being rendered or not. Useful for determining whether to treat the
* render as online or offline.
*
@@ -82,9 +82,9 @@ public:
*
* TRUE if the project is being exported, FALSE if not.
*/
bool is_exporting();
bool is_exporting();
/**
/**
* @brief Set the application state depending on if the user is exporting a video
*
* Some background functions shouldn't run while Olive is exporting a video. This function will disable/enable them
@@ -100,9 +100,9 @@ public:
*
* **TRUE** if Olive is about to export a video. **FALSE** if Olive has finished exporting.
*/
void set_export_state(bool rendering);
void set_export_state(bool rendering);
/**
/**
* @brief Set the application's "modified" state
*
* Primarily controls whether the application prompts the user to save the project upon closing or not. Also
@@ -113,9 +113,9 @@ public:
*
* TRUE if the project has been modified, FALSE if it has not.
*/
void set_modified(bool modified);
void set_modified(bool modified);
/**
/**
* @brief Get application's current "modified" state
*
* Currently just a wrapper around MainWindow::isWindowModified(), but use this instead in case it changes.
@@ -125,9 +125,9 @@ public:
*
* TRUE if the project has been modified since the last save.
*/
bool is_modified();
bool is_modified();
/**
/**
* @brief Set a project to load just after launching
*
* Called by main() if Olive was called with a project file as a running argument. Sets up Olive to load the
@@ -137,54 +137,54 @@ public:
*
* The URL of the project file to load.
*/
void load_project_on_launch(const QString& s);
void load_project_on_launch(const QString& s);
/**
/**
* @brief Retrieves the URL of the config file containing the autorecovery projects
* @return The URL as a string
*/
QString get_recent_project_list_file();
QString get_recent_project_list_file();
/**
/**
* @brief (Re)load translation file from olive::config
*/
void load_translation_from_config();
void load_translation_from_config();
/**
/**
* @brief Set native UI styling on a given widget
*
* @param w
*
* The widget to set styling on.
*/
static void SetNativeStyling(QWidget* w);
static void SetNativeStyling(QWidget* w);
/**
/**
* @brief Adds a project URL to the recent projects list
*
* @param url
*
* The project URL to add
*/
void add_recent_project(const QString& url);
void add_recent_project(const QString& url);
/**
/**
* @brief Load recent projects from file
*
* Should be called on application startup.
*/
void load_recent_projects();
void load_recent_projects();
/**
/**
* @brief Total count of recent projects
*
* @return
*
* Number of recent projects in the list
*/
int recent_project_count();
int recent_project_count();
/**
/**
* @brief Get the recent project at a given index
*
* @param index
@@ -193,18 +193,18 @@ public:
*
* The recent project at index
*/
const QString& recent_project(int index);
const QString& recent_project(int index);
/**
/**
* @brief Retrieves the filename of the autorecovery file to save to during this session
*
* @return
*
* A URL pointing to the autorecovery file
*/
const QString& get_autorecovery_filename();
const QString& get_autorecovery_filename();
/**
/**
* @brief Returns whether a Sequence is currently active or not, and optionally displays a messagebox if not
*
* Checks whether a Sequence is active and can display a messagebox if not to inform users to make one active in
@@ -214,29 +214,32 @@ public:
*
* TRUE if there is an active Sequence, FALSE if not.
*/
bool CheckForActiveSequence(bool show_msg = true);
bool CheckForActiveSequence(bool show_msg = true);
void ShowEffectMenu(EffectType type, olive::TrackType subtype, const QVector<Clip*> selected_clips);
public slots:
/**
/**
* @brief Undo user's last action
*/
void undo();
void undo();
/**
/**
* @brief Redo user's last action
*/
void redo();
void redo();
/**
/**
* @brief Paste contents of clipboard
*
* Pastes contents of clipboard. Seeing as several types of data can be copied into the clipboard, this
* function will automatically determine what type of data is in the clipboard and paste it in the correct
* location (e.g. clip data will go to the Timeline, effect data will go to Effect Controls).
*/
void paste();
void paste();
/**
/**
* @brief Paste contents of clipboard, making space for it when possible
*
* Pastes contents of clipboard (same as paste()). If the clipboard contains clip data, the clips are cut at the
@@ -244,25 +247,25 @@ public slots:
* semi-non-destructive as a result (as opposed to paste() overwriting clips). If the clipboard contains effect
* data, the functionality is identical to paste().
*/
void paste_insert();
void paste_insert();
/**
/**
* @brief Create new project.
*
* Confirms whether the current project can be closed, and if so, clears all current project data and resets
* program state. Standard `File > New` behavior.
*/
void new_project();
void new_project();
/**
/**
* @brief Open a project from file.
*
* Confirms whether the current project can be closed, and if so, shows an open file dialog to allow the user to
* select a project file and then triggers a project load with it.
*/
void OpenProject();
void OpenProject();
/**
/**
* @brief Import project from file
*
* Imports an Olive project into the current project, effectively merging them.
@@ -271,9 +274,9 @@ public slots:
*
* The filename of the project to import.
*/
void ImportProject(const QString& fn);
void ImportProject(const QString& fn);
/**
/**
* @brief Open recent project from list
*
* Triggers a project load from the internal recent projects list.
@@ -282,9 +285,9 @@ public slots:
*
* Index in the list of the project fille to load
*/
void open_recent(int index);
void open_recent(int index);
/**
/**
* @brief Shows a save file dialog and saves the project as the resulting filename
*
* Shows a save file dialog for the user to save their current project as a different filename from the current
@@ -294,9 +297,9 @@ public slots:
* if a user is closing an unsaved project, clicks "Yes" to save, we know if they actually saved or not and won't
* continue closing the project if they didn't.
*/
bool save_project_as();
bool save_project_as();
/**
/**
* @brief Saves the current project to file
*
* If the project has been saved already, this function will overwrite the project file with the current project
@@ -306,9 +309,9 @@ public slots:
* value of save_project_as(). Useful if the user closing an unsaved project, clicks "Yes" to save, we know if they
* actually saved or not and won't continue closing the project if they didn't.
*/
bool save_project();
bool save_project();
/**
/**
* @brief Determine whether the current project can be closed.
*
* Queried any time the current project is going to be closed (e.g. starting a new project, loading a project,
@@ -320,93 +323,93 @@ public slots:
* returns **TRUE**. If it does and the user clicks YES, this returns the result of save_project(). If the user
* clicks NO, this returns **TRUE**. If the user clicks CANCEL, this returns **FALSE**.
*/
bool can_close_project();
bool can_close_project();
/**
/**
* @brief Opens the NewSequenceDialog to create a new Sequence
*/
void open_new_sequence_dialog();
void open_new_sequence_dialog();
/**
/**
* @brief Open a file dialog for importing files into the project
*/
void open_import_dialog();
void open_import_dialog();
/**
/**
* @brief Open the Export dialog to trigger an export of the current sequence.
*/
void open_export_dialog();
void open_export_dialog();
/**
/**
* @brief Open the About Olive dialog.
*/
void open_about_dialog();
void open_about_dialog();
/**
/**
* @brief Open the Debug Log window.
*/
void open_debug_log();
void open_debug_log();
/**
/**
* @brief Open the Speed/Duration dialog.
*/
void open_speed_dialog();
void open_speed_dialog();
/**
/**
* @brief Open the auto-cut silence dialog.
*/
void open_autocut_silence_dialog();
void open_autocut_silence_dialog();
/**
/**
* @brief Open the Action Search overlay.
*/
void open_action_search();
void open_action_search();
/**
/**
* @brief Clears the current undo stack.
*
* Clears all current commands in the undo stack. Mostly used for debugging.
*/
void clear_undo_stack();
void clear_undo_stack();
/**
/**
* @brief Function called when Olive has finished starting up
*
* Sets up some last things for Olive that must be run after Olive has completed initialization. If a project was
* loaded as a command line argument, it's loaded here.
*/
void finished_initialize();
void finished_initialize();
/**
/**
* @brief Save an auto-recovery file of the current project.
*
* Call this function to save the current state of the project as an auto-recovery project. Called regularly by
* `autorecovery_timer`.
*/
void save_autorecovery_file();
void save_autorecovery_file();
/**
/**
* @brief Opens the Preferences dialog
*/
void open_preferences();
void open_preferences();
/**
/**
* @brief Clear the recent projects list
*
* Also saves the cleared recent projects to the config file making it permanent.
*/
void clear_recent_projects();
void clear_recent_projects();
/**
/**
* @brief Slot for when the primary sequence has changed.
*
* Usually by opening a sequence or bringing a corresponding
* Timeline widget on top.
*/
void PrimarySequenceChanged();
void PrimarySequenceChanged();
private:
/**
/**
* @brief Internal function to handle loading a project from file
*
* Start loading a project. Doesn't check if the current project can be closed, doesn't check if the project exists.
@@ -422,9 +425,9 @@ private:
* beside the original project file so that it does not overwrite the original and so that the user is not working
* on the autorecovery project in Olive's application data directory.
*/
void OpenProjectWorker(QString fn, bool autorecovery);
void OpenProjectWorker(QString fn, bool autorecovery);
/**
/**
* @brief Create a LoadDialog and start a LoadThread to load data from a project
*
* Loads data from an Olive project file creating a LoadDialog to show visual information and a LoadThread to load
@@ -450,49 +453,49 @@ private:
* TRUE if the current project should be closed before opening, FALSE if the project should be imported into the
* currently open one.
*/
void LoadProject(const QString& fn, bool autorecovery);
void LoadProject(const QString& fn, bool autorecovery);
/**
/**
* @brief Indiscriminately clear the project without prompting the user
*
* Will clear the entire project without prompting to save. This is dangerous, use new_project() instead for
* anything initiated by the user.
*/
void ClearProject();
void ClearProject();
/**
/**
* @brief Saves current recent project list to the configuration file
*
* This should be called whenever the recent projects change so the changes can be persistent.
*/
void save_recent_projects();
void save_recent_projects();
/**
/**
* @brief Internal pasting function
*/
void PasteInternal(Sequence* s, bool insert);
void PasteInternal(Sequence* s, bool insert);
/**
/**
* @brief File filter used for any file dialogs relating to Olive project files.
*/
QString project_file_filter;
QString project_file_filter;
/**
/**
* @brief Regular interval to save an auto-recovery project.
*/
QTimer autorecovery_timer;
QTimer autorecovery_timer;
/**
/**
* @brief Internal variable set to **TRUE** by main() if a project file was set as an argument
*/
bool enable_load_project_on_init;
bool enable_load_project_on_init;
/**
/**
* @brief Internal translator object that interfaces with the currently loaded language file
*/
std::unique_ptr<QTranslator> translator;
std::unique_ptr<QTranslator> translator;
/**
/**
* @brief Internal variable for whether the project has changed since the last autorecovery
*
* Set by set_modified(), which should be called alongside any change made to the project file and is "unset" when
@@ -500,45 +503,57 @@ private:
* prevents an autorecovery file saving multiple times if the project hasn't actually changed since the last
* autorecovery, but still hasn't been saved into the original file yet.
*/
bool changed_since_last_autorecovery;
bool changed_since_last_autorecovery;
/**
/**
* @brief Internal variable for rendering state (set by set_rendering_state() and accessed by is_rendering() ).
*/
bool rendering_;
bool rendering_;
/**
/**
* @brief Internal variable for the filename to the autorecovery project file
*/
QString autorecovery_filename;
QString autorecovery_filename;
/**
/**
* @brief Internal list of recent projects
*/
QStringList recent_projects;
QStringList recent_projects;
/**
* @brief Internal array of selected clips that a menu created by ShowEffectMenu will act on
*/
QVector<Clip*> effect_menu_selected_clips;
private slots:
/**
* @brief Receiver for a menu initiated by ShowEffectMenu
*
* Adds the selected effect/node to the clips in
*
* @param q
*/
void EffectMenuAction(QAction* q);
};
namespace olive {
/**
/**
* @brief Object resource for various global functions used throughout Olive
*/
extern std::unique_ptr<OliveGlobal> Global;
extern std::unique_ptr<OliveGlobal> Global;
/**
/**
* @brief Currently active project filename
*
* Filename for the currently active project. Empty means the file has not
* been saved yet.
*/
extern QString ActiveProjectFilename;
extern QString ActiveProjectFilename;
/**
/**
* @brief Current application name
*/
extern QString AppName;
extern QString AppName;
}
#endif // OLIVEGLOBAL_H