summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse2/ChangeLog3
-rw-r--r--muse2/muse/functions.cpp65
-rw-r--r--muse2/muse/functions.h6
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp142
-rw-r--r--muse2/muse/midiedit/scoreedit.h32
5 files changed, 231 insertions, 17 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index 9f7d2e07..fae1936d 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,3 +1,6 @@
+30.05.2011:
+ - implemented cut,copy'n'paste and the "select foo" entries in the score editor (flo93)
+ - added select_foo() functions to functions.cpp (flo93)
29.05.2011:
- moved cut,copy'n'paste to functions.cpp, removed unneccessary duplication (flo93)
- changed behaviour of paste: now the pasted, not the original notes are selected (flo93)
diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp
index 94b7a52d..8b17bd8d 100644
--- a/muse2/muse/functions.cpp
+++ b/muse2/muse/functions.cpp
@@ -709,7 +709,7 @@ void paste_at(Part* dest_part, const QString& pt, int pos)
{
case Xml::Error:
case Xml::End:
- return;
+ goto end_of_paste_at;
case Xml::TagStart:
if (tag == "eventlist")
@@ -726,7 +726,7 @@ void paste_at(Part* dest_part, const QString& pt, int pos)
{
printf("ERROR: trying to add event before current part!\n");
song->endUndo(SC_EVENT_INSERTED);
- return;
+ goto end_of_paste_at;
}
e.setTick(tick);
@@ -745,7 +745,7 @@ void paste_at(Part* dest_part, const QString& pt, int pos)
audio->msgAddEvent(e, dest_part, false, false, false);
}
song->endUndo(modified);
- return;
+ goto end_of_paste_at;
}
else
xml.unknown("pasteAt");
@@ -757,8 +757,67 @@ void paste_at(Part* dest_part, const QString& pt, int pos)
break;
}
}
+
+ end_of_paste_at:
+ song->update(SC_SELECTION);
+}
+
+void select_all(const std::set<Part*>& parts)
+{
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(true);
+ }
+ song->update(SC_SELECTION);
}
+void select_none(const std::set<Part*>& parts)
+{
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(false);
+ }
+ song->update(SC_SELECTION);
+}
+
+void select_invert(const std::set<Part*>& parts)
+{
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(!event.selected());
+ }
+ song->update(SC_SELECTION);
+}
+
+void select_in_loop(const std::set<Part*>& parts)
+{
+ select_none(parts);
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected((event.tick()>=song->lpos() && event.endTick()<=song->rpos()));
+ }
+ song->update(SC_SELECTION);
+}
+
+void select_not_in_loop(const std::set<Part*>& parts)
+{
+ select_none(parts);
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(!(event.tick()>=song->lpos() && event.endTick()<=song->rpos()));
+ }
+ song->update(SC_SELECTION);
+}
void read_function_dialog_config(Xml& xml)
diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h
index b08c2c39..6826a9b7 100644
--- a/muse2/muse/functions.h
+++ b/muse2/muse/functions.h
@@ -76,6 +76,12 @@ void paste_notes(Part* dest_part);
QMimeData* selected_events_to_mime(const std::set<Part*>& parts, int range);
void paste_at(Part* dest_part, const QString& pt, int pos);
+//functions for selections
+void select_all(const std::set<Part*>& parts);
+void select_none(const std::set<Part*>& parts);
+void select_invert(const std::set<Part*>& parts);
+void select_in_loop(const std::set<Part*>& parts);
+void select_not_in_loop(const std::set<Part*>& parts);
//functions for reading and writing default values
class Xml;
diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp
index e0fe6491..7bb4737f 100644
--- a/muse2/muse/midiedit/scoreedit.cpp
+++ b/muse2/muse/midiedit/scoreedit.cpp
@@ -55,9 +55,9 @@ using namespace std;
#include "cmd.h"
#include "sig.h"
#include "song.h"
+#include "shortcuts.h"
//#include "../ctrl/ctrledit.h"
-//#include "shortcuts.h"
string IntToStr(int i);
@@ -340,9 +340,59 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
quant_toolbar->addWidget(px_per_whole_spinbox);
px_per_whole_spinbox->setValue(300);
+ QMenu* edit_menu = menuBar()->addMenu(tr("&Edit"));
+
+ edit_menu->addActions(undoRedo->actions());
+ edit_menu->addSeparator();
+
+ cut_action = edit_menu->addAction(QIcon(*editcutIconSet), tr("C&ut"));
+ menu_mapper->setMapping(cut_action, CMD_CUT);
+ connect(cut_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ copy_action = edit_menu->addAction(QIcon(*editcopyIconSet), tr("&Copy"));
+ menu_mapper->setMapping(copy_action, CMD_COPY);
+ connect(copy_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ paste_action = edit_menu->addAction(QIcon(*editpasteIconSet), tr("&Paste"));
+ menu_mapper->setMapping(paste_action, CMD_PASTE);
+ connect(paste_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ edit_menu->addSeparator();
+
+ del_action = edit_menu->addAction(tr("Delete &Events"));
+ menu_mapper->setMapping(del_action, CMD_ERASE);
+ connect(del_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ edit_menu->addSeparator();
+
+ QMenu* select_menu = edit_menu->addMenu(QIcon(*selectIcon), tr("&Select"));
+
+ select_all_action = select_menu->addAction(QIcon(*select_allIcon), tr("Select &All"));
+ menu_mapper->setMapping(select_all_action, CMD_SELECT_ALL);
+ connect(select_all_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_none_action = select_menu->addAction(QIcon(*select_deselect_allIcon), tr("&Deselect All"));
+ menu_mapper->setMapping(select_none_action, CMD_SELECT_NONE);
+ connect(select_none_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_invert_action = select_menu->addAction(QIcon(*select_invert_selectionIcon), tr("Invert &Selection"));
+ menu_mapper->setMapping(select_invert_action, CMD_SELECT_INVERT);
+ connect(select_invert_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_menu->addSeparator();
+
+ select_iloop_action = select_menu->addAction(QIcon(*select_inside_loopIcon), tr("&Inside Loop"));
+ menu_mapper->setMapping(select_iloop_action, CMD_SELECT_ILOOP);
+ connect(select_iloop_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_oloop_action = select_menu->addAction(QIcon(*select_outside_loopIcon), tr("&Outside Loop"));
+ menu_mapper->setMapping(select_oloop_action, CMD_SELECT_OLOOP);
+ connect(select_oloop_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+
QMenu* settings_menu = menuBar()->addMenu(tr("&Settings"));
- QMenu* color_menu = settings_menu->addMenu(tr("Note head &colors"));
+ color_menu = settings_menu->addMenu(tr("Note head &colors"));
color_actions = new QActionGroup(this);
color_black_action = color_menu->addAction(tr("&Black"), menu_mapper, SLOT(map()));
color_velo_action = color_menu->addAction(tr("&Velocity"), menu_mapper, SLOT(map()));
@@ -378,16 +428,16 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
QMenu* functions_menu = menuBar()->addMenu(tr("&Functions"));
- QAction* func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map()));
- QAction* func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map()));
- QAction* func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map()));
- QAction* func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map()));
- QAction* func_transpose_action = functions_menu->addAction(tr("Transpose"), menu_mapper, SLOT(map()));
- QAction* func_erase_action = functions_menu->addAction(tr("Erase Events"), menu_mapper, SLOT(map()));
- QAction* func_move_action = functions_menu->addAction(tr("Move Notes"), menu_mapper, SLOT(map()));
- QAction* func_fixed_len_action = functions_menu->addAction(tr("Set Fixed Length"), menu_mapper, SLOT(map()));
- QAction* func_del_overlaps_action = functions_menu->addAction(tr("Delete Overlaps"), menu_mapper, SLOT(map()));
- QAction* func_legato_action = functions_menu->addAction(tr("Legato"), menu_mapper, SLOT(map()));
+ func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map()));
+ func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map()));
+ func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map()));
+ func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map()));
+ func_transpose_action = functions_menu->addAction(tr("Transpose"), menu_mapper, SLOT(map()));
+ func_erase_action = functions_menu->addAction(tr("Erase Events"), menu_mapper, SLOT(map()));
+ func_move_action = functions_menu->addAction(tr("Move Notes"), menu_mapper, SLOT(map()));
+ func_fixed_len_action = functions_menu->addAction(tr("Set Fixed Length"), menu_mapper, SLOT(map()));
+ func_del_overlaps_action = functions_menu->addAction(tr("Delete Overlaps"), menu_mapper, SLOT(map()));
+ func_legato_action = functions_menu->addAction(tr("Legato"), menu_mapper, SLOT(map()));
menu_mapper->setMapping(func_quantize_action, CMD_QUANTIZE);
menu_mapper->setMapping(func_notelen_action, CMD_NOTELEN);
menu_mapper->setMapping(func_velocity_action, CMD_VELOCITY);
@@ -398,7 +448,16 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
menu_mapper->setMapping(func_fixed_len_action, CMD_FIXED_LEN);
menu_mapper->setMapping(func_del_overlaps_action, CMD_DELETE_OVERLAPS);
menu_mapper->setMapping(func_legato_action, CMD_LEGATO);
+
+ init_shortcuts();
+
+ connect(muse, SIGNAL(configChanged()), SLOT(init_shortcuts()));
+ QClipboard* cb = QApplication::clipboard();
+ connect(cb, SIGNAL(dataChanged()), SLOT(clipboard_changed()));
+
+ clipboard_changed();
+ selection_changed();
if (!default_toolbar_state.isEmpty())
restoreState(default_toolbar_state);
@@ -417,6 +476,32 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
apply_velo=true;
}
+void ScoreEdit::init_shortcuts()
+{
+ cut_action->setShortcut(shortcuts[SHRT_CUT].key);
+ copy_action->setShortcut(shortcuts[SHRT_COPY].key);
+ paste_action->setShortcut(shortcuts[SHRT_PASTE].key);
+ del_action->setShortcut(shortcuts[SHRT_DELETE].key);
+
+ select_all_action->setShortcut(shortcuts[SHRT_SELECT_ALL].key);
+ select_none_action->setShortcut(shortcuts[SHRT_SELECT_NONE].key);
+ select_invert_action->setShortcut(shortcuts[SHRT_SELECT_INVERT].key);
+ select_iloop_action->setShortcut(shortcuts[SHRT_SELECT_ILOOP].key);
+ select_oloop_action->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key);
+
+ color_menu->menuAction()->setShortcut(shortcuts[SHRT_EVENT_COLOR].key);
+
+ func_quantize_action->setShortcut(shortcuts[SHRT_QUANTIZE].key);
+ func_notelen_action->setShortcut(shortcuts[SHRT_MODIFY_GATE_TIME].key);
+ func_velocity_action->setShortcut(shortcuts[SHRT_MODIFY_VELOCITY].key);
+ func_transpose_action->setShortcut(shortcuts[SHRT_TRANSPOSE].key);
+ func_erase_action->setShortcut(shortcuts[SHRT_ERASE_EVENT].key);
+ func_move_action->setShortcut(shortcuts[SHRT_NOTE_SHIFT].key);
+ func_fixed_len_action->setShortcut(shortcuts[SHRT_FIXED_LEN].key);
+ func_del_overlaps_action->setShortcut(shortcuts[SHRT_DELETE_OVERLAPS].key);
+}
+
+
void ScoreEdit::add_parts(PartList* pl, bool all_in_one)
{
score_canvas->add_staves(pl, all_in_one);
@@ -522,6 +607,9 @@ void ScoreEdit::song_changed(int flags)
if (velo_off>=0) velo_off_spinbox->setValue(velo_off);
}
}
+
+ if (flags & SC_SELECTION)
+ selection_changed();
}
void ScoreEdit::canvas_width_changed(int width)
@@ -607,6 +695,21 @@ void ScoreEdit::menu_command(int cmd)
}
break;
+ case CMD_SELECT_ALL: select_all(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_NONE: select_none(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_INVERT: select_invert(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_ILOOP: select_in_loop(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_OLOOP: select_not_in_loop(score_canvas->get_all_parts()); break;
+
+ case CMD_CUT:
+ copy_notes(score_canvas->get_all_parts(), 1);
+ erase_notes(score_canvas->get_all_parts(), 1);
+ break;
+ case CMD_COPY: copy_notes(score_canvas->get_all_parts(), 1); break;
+ case CMD_PASTE:
+ menu_command(CMD_SELECT_NONE);
+ paste_notes(score_canvas->get_selected_part());
+ break;
case CMD_QUANTIZE: quantize_notes(score_canvas->get_all_parts()); break;
case CMD_VELOCITY: modify_velocity(score_canvas->get_all_parts()); break;
case CMD_CRESCENDO: crescendo(score_canvas->get_all_parts()); break;
@@ -623,6 +726,19 @@ void ScoreEdit::menu_command(int cmd)
}
}
+void ScoreEdit::clipboard_changed()
+{
+ paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist")));
+}
+
+void ScoreEdit::selection_changed()
+{
+ bool flag = !get_events(score_canvas->get_all_parts(),1).empty();
+ cut_action->setEnabled(flag);
+ copy_action->setEnabled(flag);
+ del_action->setEnabled(flag);
+}
+
//duplicated from songfile.cpp's MusE::readPart(); the only differences:
//"none" is supported and tag_name is settable
@@ -4117,6 +4233,7 @@ void ScoreCanvas::menu_command(int cmd)
case CMD_NOTELEN_16: new_len=TICKS_PER_WHOLE/16; break;
case CMD_NOTELEN_32: new_len=TICKS_PER_WHOLE/32; break;
case CMD_NOTELEN_LAST: new_len=-1; break;
+
default:
cerr << "ERROR: ILLEGAL FUNCTION CALL: ScoreCanvas::menu_command called with unknown command ("<<cmd<<")"<<endl;
}
@@ -4375,7 +4492,6 @@ void staff_t::update_part_indices()
* between, for example, when a cis is tied to a des
*
* CURRENT TODO
- * o when pasting, the pasted, not the previously selected should be selected
* o allow batch-movements in score editor
* o in main win: make "Ch" column editable with a line edit
* o either remove these "hidden notes", or deal with them in the score editor
diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h
index 3fd321b9..603c1c12 100644
--- a/muse2/muse/midiedit/scoreedit.h
+++ b/muse2/muse/midiedit/scoreedit.h
@@ -63,7 +63,10 @@ enum {CMD_COLOR_BLACK, CMD_COLOR_VELO, CMD_COLOR_PART,
CMD_NOTELEN_16, CMD_NOTELEN_32, CMD_NOTELEN_LAST,
CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN, CMD_TRANSPOSE,
- CMD_ERASE, CMD_MOVE, CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO };
+ CMD_ERASE, CMD_MOVE, CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO,
+ CMD_CUT, CMD_COPY, CMD_PASTE,
+ CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT,
+ CMD_SELECT_ILOOP, CMD_SELECT_OLOOP};
class ScoreCanvas;
@@ -112,6 +115,30 @@ class ScoreEdit : public TopWin
QAction* color_velo_action;
QAction* color_part_action;
+ QMenu* color_menu;
+
+ QAction* cut_action;
+ QAction* copy_action;
+ QAction* paste_action;
+ QAction* del_action;
+
+ QAction* select_all_action;
+ QAction* select_none_action;
+ QAction* select_invert_action;
+ QAction* select_iloop_action;
+ QAction* select_oloop_action;
+
+ QAction* func_quantize_action;
+ QAction* func_notelen_action;
+ QAction* func_velocity_action;
+ QAction* func_cresc_action;
+ QAction* func_transpose_action;
+ QAction* func_erase_action;
+ QAction* func_move_action;
+ QAction* func_fixed_len_action;
+ QAction* func_del_overlaps_action;
+ QAction* func_legato_action;
+
QToolButton* srec;
QToolButton* midiin;
@@ -138,6 +165,9 @@ class ScoreEdit : public TopWin
void velo_box_changed();
void velo_off_box_changed();
void set_steprec(bool);
+ void init_shortcuts();
+ void selection_changed();
+ void clipboard_changed();
signals:
void deleted(unsigned long);