/* commandfuncs.cpp * functions invoked by user keypresses * * for Denemo, a gtk+ frontend to GNU Lilypond * (c) 1999-2005 Matthew Hiller, Adam Tee */ #include #include "commandfuncs.h" #include "calculatepositions.h" #include "chordops.h" #include "contexts.h" #include "draw.h" #include "measureops.h" #include "midi.h" #include "objops.h" #include "moveviewport.h" #include "selectops.h" #include "staffops.h" #include "utils.h" #include "tupletops.h" #include "graceops.h" #include "instrumentname.h" #include "file.h" #include "exportmudela.h" #include "exportxml.h" #include "prefops.h" /** * Macro to get the current DenemoObject */ #define declarecurmudelaobj \ DenemoObject *curmudelaobj = \ (DenemoObject *) ( (si->currentobject && si->currentobject->data) ? \ ((((DenemoObject *)si->currentobject->data)->type == TUPCLOSE) ? \ si->currentobject->prev->data : si->currentobject->data) : NULL) /** * Helper function for calculating the * beam and stem direction */ static void beamandstemdirhelper (DenemoScore * si) { calculatebeamsandstemdirs ((objnode *) si->currentmeasure->data, &(si->curmeasureclef), &(si->cursortime1), &(si->cursortime2), &(si->curmeasure_stem_directive)); } /** * Set si->current* variables * */ void setcurrents (DenemoScore * si) { if (((DenemoStaff *) si->currentstaff->data)->nummeasures >= si->currentmeasurenum) { si->currentmeasure = g_list_nth (firstmeasurenode (si->currentstaff), si->currentmeasurenum - 1); } else { #ifdef DEBUG g_print ("Setting measure to %d which is last in Staff\n", ((DenemoStaff *) si->currentstaff->data)->nummeasures); #endif si->currentmeasure = g_list_nth (firstmeasurenode (si->currentstaff), ((DenemoStaff *) si->currentstaff->data)->nummeasures - 1); si->currentmeasurenum = ((DenemoStaff *) si->currentstaff->data)->nummeasures; } si->cursor_x = 0; si->currentobject = (objnode *) si->currentmeasure->data; if (si->currentobject) si->cursor_appending = FALSE; else si->cursor_appending = TRUE; calcmarkboundaries (si); } /** * Push the score to the left off the * displayed portion */ void nudgerightward (DenemoGUI * si) { set_rightmeasurenum (si->si); while (si->si->currentmeasurenum > si->si->rightmeasurenum) { si->si->leftmeasurenum++; set_rightmeasurenum (si->si); } find_leftmost_allcontexts (si->si); update_hscrollbar (si); } /** * Push the score upwards off the displayed * portion */ void nudge_downward (DenemoGUI * gui) { set_bottom_staff (gui); while (gui->si->currentstaffnum > gui->si->bottom_staff) { gui->si->top_staff++; set_bottom_staff (gui); } update_vscrollbar (gui); } /** * Set the width of the working scorearea */ void set_width_to_work_with (DenemoGUI * gui) { gui->si->widthtoworkwith = (gui->scorearea->allocation.width - (RIGHT_MARGIN + KEY_MARGIN + gui->si->maxkeywidth + SPACE_FOR_TIME)); } /** * Change the basic width of each measure */ void adjustmeasurewidth (DenemoScore * si, gint amount) { si->measurewidth += amount; if (si->measurewidth < 10) si->measurewidth = 10; if (si->widthtoworkwith < si->measurewidth + SPACE_FOR_BARLINE) si->measurewidth = si->widthtoworkwith - SPACE_FOR_BARLINE; find_xes_in_all_measures (si); /*nudgerightward (si); */ } /** * Determines whether the closer jump will be up or down */ gint jumpcursor (gint cursor_y, gint fromnote, gint tonote) { int distance; distance = (tonote - fromnote + 7) % 7; if (distance <= 3) /* an upward jump is good */ return cursor_y + distance; else /* jump down */ return cursor_y - 7 + distance; } /** * General function for inserting a DenemoObject * into the score */ void object_insert (DenemoScore * si, DenemoObject * mudela_obj_new) { unre_data *undo = (unre_data *) g_malloc (sizeof (unre_data)); declarecurmudelaobj; /* First, check to see if the operation would add something before an * indicator of a time signature change. This would be bad, so don't * allow it to happen */ if (curmudelaobj && curmudelaobj->type == TIMESIG && !si->cursor_appending) { si->cursor_x++; if (si->currentobject->next) si->currentobject = si->currentobject->next; else si->cursor_appending = TRUE; } si->currentmeasure->data = g_list_insert ((objnode *) si->currentmeasure->data, mudela_obj_new, si->cursor_x); /* update undo information */ undo->position = si->cursor_x; undo->measurenum = si->currentmeasurenum; undo->staffnum = si->currentstaffnum; undo->object = clone_object (mudela_obj_new); undo->action = ACTION_INSERT; si->cursor_x++; if (si->cursor_appending) si->currentobject = g_list_last ((objnode *) si->currentmeasure->data); else si->currentobject = g_list_nth ((objnode *) si->currentmeasure->data, si->cursor_x); update_undo_info (si, undo); si->markstaffnum = 0; } /** * Change the y position of each staff */ void adjuststaffheight (DenemoScore * si, gint amount) { si->staffspace += amount; if (si->staffspace < 2 * STAFF_HEIGHT) si->staffspace = 2 * STAFF_HEIGHT; /*nudge_downward (si); */ } /** * Move an entire measure to the left * */ void measureleft (DenemoGUI * gui) { if (!gui->si->cursor_x && gui->si->currentmeasure->prev) { gui->si->currentmeasurenum--; isoffleftside (gui); } setcurrents (gui->si); } /** * Move an entire measure to the right * */ void measureright (DenemoGUI * gui) { if (gui->si->currentmeasure->next) { gui->si->currentmeasurenum++; isoffrightside (gui); setcurrents (gui->si); } } /** * Move up an entire staff * */ void staffup (DenemoGUI * gui) { if (gui->si->currentstaff && gui->si->currentstaff->prev) { gui->si->currentstaffnum--; gui->si->currentstaff = gui->si->currentstaff->prev; setcurrentprimarystaff (gui->si); setcurrents (gui->si); move_viewport_up (gui); } } /** * Move down an entire staff * */ void staffdown (DenemoGUI * gui) { if (gui->si->currentstaff->next) { gui->si->currentstaffnum++; gui->si->currentstaff = gui->si->currentstaff->next; setcurrentprimarystaff (gui->si); setcurrents (gui->si); move_viewport_down (gui); } } /** * move the cursor one position to the left * */ void cursorleft (DenemoGUI * gui) { DenemoScore *si = gui->si; if (!si->cursor_x) { /* also the only situation where si->currentobject == NULL */ if (si->currentmeasure->prev) { /* Go to end of preceding measure */ si->cursor_appending = TRUE; si->currentmeasure = si->currentmeasure->prev; si->currentmeasurenum--; isoffleftside (gui); si->currentobject = g_list_last ((objnode *) si->currentmeasure->data); /* The preceding statement will set currentobject to * NULL if appropriate */ si->cursor_x = g_list_length ((objnode *) si->currentmeasure->data); /* Despite appearances, there is not an off-by-one error in the * preceding command */ } } else if (si->cursor_appending) { /* Can back off from appending */ si->cursor_appending = FALSE; si->cursor_x--; } else { /* Can go back in the measure */ if (si->currentobject && si->currentobject->prev) { si->currentobject = si->currentobject->prev; si->cursor_x--; } } calcmarkboundaries (si); } /** * move the cursor one position to the right * */ void cursorright (DenemoGUI * gui) { DenemoScore *si = gui->si; if (si->cursor_appending && si->currentmeasure->next) { /* Go to the next measure */ si->currentmeasure = si->currentmeasure->next; si->currentmeasurenum++; isoffrightside (gui); si->currentobject = (objnode *) si->currentmeasure->data; si->cursor_x = 0; if (si->currentobject) si->cursor_appending = FALSE; } else if (si->currentobject) { /* See if we should go to appending position. If not, go to the * next note (if possible) */ if (!si->cursor_appending && !si->currentobject->next) { /* Go to appending position */ si->cursor_appending = TRUE; si->cursor_x++; } else if (si->currentobject->next) { si->currentobject = si->currentobject->next; si->cursor_x++; } } calcmarkboundaries (si); } /** * Move the cursor up one position */ void cursorup (DenemoGUI * gui) { gui->si->cursor_y++; gui->si->staffletter_y = (gui->si->staffletter_y + 1) % 7; g_print ("Cursor Y Position %d\n", gui->si->cursor_y); } /** * Move the cursor down one position */ void cursordown (DenemoGUI * gui) { gui->si->cursor_y--; gui->si->staffletter_y = (gui->si->staffletter_y + 6) % 7; g_print ("Cursor Y Position %d\n", gui->si->cursor_y); } /** * Move the cursor to a given note value * */ void shiftcursor (DenemoScore * si, gint note_value) { gint oldstaffletter_y = si->staffletter_y; si->staffletter_y = note_value; si->cursor_y = jumpcursor (si->cursor_y, oldstaffletter_y, si->staffletter_y); } /** * Goto the next measure * Goto the next measure in the score. A new measure will * be created if required * @param si pointer to the scoreinfo structure * @param all apply to all staffs or not */ void nextmeasure (DenemoScore * si, gboolean all /*=TRUE */ ) { gboolean next_measure; /* First, check to see if the insertion'll cause the cursor to * jump to the next measure. (Denemo will implicitly create it * if it doesn't exist already.) */ next_measure = si->cursoroffend && si->cursor_appending && (!si->currentmeasure->next || !si->currentmeasure->next->data); if (next_measure) { if (!si->currentmeasure->next) { #ifdef DEBUG g_print ("Appending a new measure\n"); #endif /* Add a measure and make it currentmeasure */ // object_insert( si, newbarline( ORDINARY_BARLINE)); si->currentmeasure = addmeasures (si, si->currentmeasurenum, 1, all); } else si->currentmeasure = si->currentmeasure->next; /* Now the stuff that needs to be done for each case */ si->currentmeasurenum++; si->currentobject = (objnode *) si->currentmeasure->data; si->cursor_x = 0; memcpy (si->cursoraccs, si->nextmeasureaccs, SEVENGINTS); memcpy (si->curmeasureaccs, si->nextmeasureaccs, SEVENGINTS); si->curmeasureclef = si->cursorclef; } } /** * Insert a chord into the score * @param si pointer to the scoreinfo structure * @param duration the duration of the chord to insert * @param mode the current input mode * @param rest specifies a note is a rest */ void dnm_insertchord (DenemoScore * si, gint duration, input_mode mode, gboolean rest) { DenemoObject *mudela_obj_new; int prognum; DenemoStaff *curstaffstruct; /* First, check to see if the insertion'll cause the cursor to * jump to the next measure. (Denemo will implicitly create it * if it doesn't exist already.) */ nextmeasure (si, FALSE); /* Now actually create the chord */ mudela_obj_new = newchord (duration, 0, 0); if (mode == INPUTBLANK && (rest != TRUE)) { addtone (mudela_obj_new, si->cursor_y, si->cursoraccs[si->staffletter_y], si->cursorclef); mudela_obj_new->isinvisible = TRUE; } else if (mode == INPUTNORMAL && (rest != TRUE)) addtone (mudela_obj_new, si->cursor_y, si->cursoraccs[si->staffletter_y], si->cursorclef); if (si->is_grace_mode) ((chord *) mudela_obj_new->object)->is_grace = TRUE; /* Insert the new note into the score. Note that while we may have added a measure above, object_insert will invoke nudgerightward, which will in turn invoke update_hscrollbar, so we don't need to invoke that here. */ object_insert (si, mudela_obj_new); curstaffstruct = (DenemoStaff *) si->currentstaff->data; prognum = select_program (curstaffstruct->midi_instrument->str); /*playnotes (si->prefs->immediateplayback, *(chord *) mudela_obj_new->object, prognum); */ } /** * Insert tuplet into the score * @param si pointer to the scoreinfo structure * @param type the type of tuplet to insert */ void dnm_inserttuplet (DenemoScore * si, tuplet_type type) { DenemoObject *mudela_obj_new; nextmeasure (si, FALSE); switch (type) { case 0: mudela_obj_new = newtupopen (3, 2); break; case 1: mudela_obj_new = newtupopen (2, 3); break; case 2: mudela_obj_new = newtupopen (3, 4); break; case 3: mudela_obj_new = newtupopen (4, 5); break; case 4: mudela_obj_new = newtupopen (4, 6); break; case 5: mudela_obj_new = newtupopen (4, 7); break; default: mudela_obj_new = newtupopen (2, 3); break; } g_print ("Cursor pos %d (Before tup open)\n", si->cursor_x); object_insert (si, mudela_obj_new); g_print ("Cursor pos %d (After tup open, before tup close)\n", si->cursor_x); /* Add the closing bracket */ object_insert (si, newtupclose ()); g_print ("Cursor pos %d (After tup close)\n", si->cursor_x); si->cursor_x--; g_print ("Cursor pos %d( After move back)\n", si->cursor_x); si->currentobject = si->currentobject->prev; si->cursor_appending = FALSE; } /** * Insert grace note into the score * @param si pointer to the scoreinfo structure */ void insertgrace (DenemoScore * si) { DenemoObject *mudela_obj_new; nextmeasure (si, FALSE); mudela_obj_new = newgracestart (); object_insert (si, mudela_obj_new); object_insert (si, newgraceend ()); si->cursor_x--; si->currentobject = g_list_nth ((objnode *) si->currentmeasure->data, si->cursor_x); si->cursor_appending = FALSE; si->is_grace_mode = TRUE; } /** * Change the duration of the current note/rest * @param si pointer to the scoreinfo structure * @param duration the duration to change the current CHORD * object to */ void changeduration (DenemoScore * si, gint duration) { declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { changedur (curmudelaobj, duration, 0); } } /** * Change a tone either in a chord or individual note * alternatively remove it from a chord * * @param si pointer to the scoreinfo structure * @param remove whether to remove tone or not */ void tonechange (DenemoScore * si, gboolean remove) { declarecurmudelaobj; int prognum; DenemoStaff *curstaffstruct; if (curmudelaobj && curmudelaobj->type == CHORD) { if (remove == TRUE) removetone (curmudelaobj, si->cursor_y, si->cursorclef); else addtone (curmudelaobj, si->cursor_y, si->cursoraccs[si->staffletter_y], si->cursorclef); if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } curstaffstruct = (DenemoStaff *) si->currentstaff->data; prognum = select_program (curstaffstruct->midi_instrument->str); /*playnotes (si->prefs->immediateplayback, *(chord *) curmudelaobj->object, prognum);*/ } } /** * Helper function that contains calls to all the display * update functions * * @param gui pointer to the DenemoGUI structure */ void displayhelper (DenemoGUI * gui) { DenemoScore *si = gui->si; beamandstemdirhelper (si); showwhichaccidentals ((objnode *) si->currentmeasure->data, si->curmeasurekey, si->curmeasureaccs); find_xes_in_measure (si, si->currentmeasurenum, si->cursortime1, si->cursortime2); nudgerightward (gui); si->haschanged = TRUE; gtk_widget_draw (gui->scorearea, NULL); } /** * Change the enharmonic shift of the tone closest to the cursor. The * function double-checks to be sure that it's passed a chord, though * at the moment (28 July 2000), it probably doesn't strictly need to * * @param si pointer to the DenemoScore structure * @param amount enharmonic shifts distance */ void changeenshift (DenemoScore * si, gint amount) { declarecurmudelaobj; int prognum; DenemoStaff *curstaffstruct; if (curmudelaobj && curmudelaobj->type == CHORD) { shiftpitch (curmudelaobj, si->cursor_y, amount == 1); showwhichaccidentals ((objnode *) si->currentmeasure->data, si->curmeasurekey, si->curmeasureaccs); find_xes_in_measure (si, si->currentmeasurenum, si->cursortime1, si->cursortime2); if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } curstaffstruct = (DenemoStaff *) si->currentstaff->data; prognum = select_program (curstaffstruct->midi_instrument->str); /* playnotes (si->prefs->immediateplayback, *(chord *) curmudelaobj->object, prognum);*/ } unre_data *data = (unre_data *) g_malloc (sizeof (unre_data)); data->object = curmudelaobj; data->position = si->cursor_x; data->measurenum = si->currentmeasurenum; data->staffnum = si->currentstaffnum; data->action = ACTION_CHANGE; update_undo_info (si, data); } /** * Change the stemdirection of the current chord object * by a given amount * @param si pointer to the scoreinfo structure * @param amount the stem direction change to make */ void change_stem_directive (DenemoScore * si, enum stemdirections amount) { declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == STEMDIRECTIVE) { switch (amount) { case DENEMO_STEMDOWN: ((stemdirective *) curmudelaobj->object)->type = DENEMO_STEMDOWN; break; case DENEMO_STEMUP: ((stemdirective *) curmudelaobj->object)->type = DENEMO_STEMUP; break; default: ((stemdirective *) curmudelaobj->object)->type = DENEMO_STEMBOTH; break; } if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Change the number of dots on the current chord * * @param si pointer to the scoreinfo structure * @param amount the number of dots to add/remove */ void changedots (DenemoScore * si, gint amount) { declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { changenumdots (curmudelaobj, amount); if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Insert measure into the score at the current position * * @param si pointer to the scoreinfo structure * @param number of measures to insert */ void dnm_insertmeasures (DenemoScore * si, gint number) { si->currentmeasure = addmeasures (si, si->currentmeasurenum - 1, number, 1); si->cursor_x = 0; si->cursor_appending = TRUE; si->currentobject = NULL; set_rightmeasurenum (si); si->haschanged = TRUE; si->markstaffnum = 0; calcmarkboundaries (si); /* update_hscrollbar (si); */ } /** * Add measure to the end of the score * * @param si pointer to the scoreinfo structure * @param number the number of measures to append */ void appendmeasures (DenemoScore * si, gint number) { addmeasures (si, g_list_length (firstmeasurenode (si->currentstaff)), number, FALSE); /* Reset these two variables because si->currentmeasure and * si->currentobject may now be pointing to dead data */ si->currentmeasure = g_list_nth (firstmeasurenode (si->currentstaff), si->currentmeasurenum - 1); si->currentobject = g_list_nth ((objnode *) si->currentmeasure->data, si->cursor_x - (si->cursor_appending == TRUE)); set_rightmeasurenum (si); si->haschanged = TRUE; /*update_hscrollbar (si); */ } void appendmeasurestoentirescore (DenemoScore * si, gint number) { addmeasures (si, g_list_length (firstmeasurenode (si->currentstaff)), number, TRUE); /* Reset these two variables because si->currentmeasure and * si->currentobject may now be pointing to dead data */ si->currentmeasure = g_list_nth (firstmeasurenode (si->currentstaff), si->currentmeasurenum - 1); si->currentobject = g_list_nth ((objnode *) si->currentmeasure->data, si->cursor_x - (si->cursor_appending == TRUE)); set_rightmeasurenum (si); si->haschanged = TRUE; /* update_hscrollbar (si); */ } /** * Delete staff wrapper to delete the preceding staff * * @param action pointer to the GtkAction event * @param gui pointer to the DenemoGUI structure */ void delete_staff_before (GtkAction * action, DenemoGUI * gui) { delete_staff (gui->si, BEFORE); displayhelper (gui); } /** * Delete staff wrapper to delete the next staff * * @param action pointer to the GtkAction event * @param gui pointer to the DenemoGUI structure */ void delete_staff_after (GtkAction * action, DenemoGUI * gui) { delete_staff (gui->si, AFTER); displayhelper (gui); } /** * Delete staff wrapper to delete current staff * * @param action pointer to the GtkAction event * @param gui pointer to the DenemoGUI structure */ void delete_staff_current (GtkAction * action, DenemoGUI * gui) { delete_staff (gui->si, 9); displayhelper (gui); } /** * Delete specific staff defined by callback * * @param si pointer to the DenemoScore structure * @param callback_action position of the staff to delete */ void delete_staff (DenemoScore * si, guint callback_action) { g_print ("Current staff num %d, callback_action %d", si->currentstaffnum, callback_action); switch (callback_action) { case BEFORE: if (si->currentstaffnum != 1) deletestaff (si, si->currentstaffnum - 2); break; case AFTER: deletestaff (si, si->currentstaffnum + 1); break; default: deletestaff (si, si->currentstaffnum - 1); break; } /* displayhelper(si);*/ } /** * Delete staff from the score * @param si pointer to the scoreinfo structure * @param pos the position in the staff list * @return none */ void deletestaff (DenemoScore * si, gint pos) { if (g_list_length (si->thescore) > 1) { removestaff (si, pos, 1); setcurrents (si); find_xes_in_all_measures (si); si->haschanged = TRUE; si->markstaffnum = 0; } } /** * Delete mesasure from score * @param gui pointer to the DenemoGUI structure * @return none * * This is only a wrapper for the real dnm_deletemeasure * function. */ void deletemeasure(DenemoGUI * gui) { dnm_deletemeasure(gui->si); isoffleftside (gui); } /** * Delete measure from the score * * TODO remove measure from current staff * rather than the entire score * @param gui pointer to the DenemoGUI structure * @return none */ void dnm_deletemeasure (DenemoScore * si) { si->currentmeasure = removemeasures (si, si->currentmeasurenum - 1, 1, FALSE); /* In case that was the last measure we just deleted, which'd cause * the current measure to be the left of what's displayed */ setcurrents (si); si->haschanged = TRUE; si->markstaffnum = 0; } /** * Remove current object from the score *@param cur_measure pointer to the current measure * @param cur_objnode pointer to the current object * @return none */ static void remove_object (measurenode * cur_measure, objnode * cur_objnode) { cur_measure->data = g_list_remove_link ((objnode *) cur_measure->data, cur_objnode); freeobject ((DenemoObject *) cur_objnode->data); g_list_free_1 (cur_objnode); } /** * Reset the cursor stats * @param si pointer to the scoreinfo structure * @return none */ static void reset_cursor_stats (DenemoScore * si) { si->currentobject = g_list_nth ((objnode *) si->currentmeasure->data, si->cursor_x); if (!si->currentobject) { si->currentobject = g_list_last ((objnode *) si->currentmeasure->data); si->cursor_appending = TRUE; } } /** * Helper to remove the current object an reset cursor stats * @param si pointer to the scoreinfo structure * @return none */ static void delete_object_helper (DenemoScore * si) { remove_object (si->currentmeasure, si->currentobject); reset_cursor_stats (si); } /** * Helper to remove a object from the score * @param gui pointer to the DenemoGUI structure * @return none. * */ void deleteobject(DenemoGUI *gui) { dnm_deleteobject(gui->si); } /** * Function to delete object from the score * @param gui - pointer to the DenemoGUI structure * @return none */ void dnm_deleteobject (DenemoScore * si) { declarecurmudelaobj; staffnode *curstaff; measurenode *curmeasure; g_print ("dnm_deleteobject undo/redo mode %d\n", si->undo_redo_mode); if (si->undo_redo_mode == UNDO) { unre_data *undo = (unre_data *) g_malloc (sizeof (unre_data)); undo->staffnum = si->currentstaffnum; undo->measurenum = si->currentmeasurenum; undo->position = si->cursor_x; undo->object = clone_object (curmudelaobj); undo->action = ACTION_DELETE; update_undo_info (si, undo); } if (!si->cursor_appending) { switch (curmudelaobj->type) { case CHORD: delete_object_helper (si); break; case TUPOPEN: case TUPCLOSE: /* TODO - add code that will automatically delete a tupbracket's * corresponding bracket */ delete_object_helper (si); break; case CLEF: delete_object_helper (si); fixnoteheights ((DenemoStaff *) si->currentstaff->data); beamsandstemdirswholestaff ((DenemoStaff *) si->currentstaff->data); find_xes_in_all_measures (si); break; case KEYSIG: /* Doesn't automatically delete sibling key signatures, though * I probably will have it do so soon */ delete_object_helper (si); beamsandstemdirswholestaff ((DenemoStaff *) si->currentstaff->data); showwhichaccidentalswholestaff ((DenemoStaff *) si->currentstaff-> data); find_xes_in_all_measures (si); break; case TIMESIG: /* For time signatures, deletion is linked to all * the staffs on the score */ for (curstaff = si->thescore; curstaff; curstaff = curstaff->next) { curmeasure = g_list_nth (firstmeasurenode (curstaff), si->currentmeasurenum - 1); remove_object (curmeasure, (objnode *) curmeasure->data); beamsandstemdirswholestaff ((DenemoStaff *) curstaff->data); } reset_cursor_stats (si); find_xes_in_all_measures (si); break; case STEMDIRECTIVE: delete_object_helper (si); beamsandstemdirswholestaff ((DenemoStaff *) si->currentstaff->data); find_xes_in_all_measures (si); break; case DYNAMIC: delete_object_helper (si); break; // case LILYDIRECTIVE: // delete_object_helper (si); // displayhelper (si); // break; case GRACE_START: case GRACE_END: delete_object_helper (si); break; case LYRIC: case FIGURE: delete_object_helper (si); break; case BARLINE: // case COMMENT: case MEASUREBREAK: break; } si->haschanged = TRUE; si->markstaffnum = 0; } } /** * Insert cloned chordobject into the * score * @param si - pointer to the scoreinfo structure * @return none */ void insertclone (DenemoScore * si) { declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) object_insert (si, clone_object (curmudelaobj)); } /** * Move cursor to the end of the score * @param action - Gtk Action event * @param gui - pointer to the DenemoGUI structure * @return none */ void toend (GtkAction * action, DenemoGUI * gui) { gui->si->currentmeasurenum = gui->si->leftmeasurenum = gui->si->rightmeasurenum = g_list_length (((DenemoStaff *) gui->si->currentstaff->data)->measures); setcurrents (gui->si); find_leftmost_allcontexts (gui->si); update_hscrollbar (gui); displayhelper (gui); } /** * Move the cursor to the beginning of the score * @param action - Gtk Action event * @param gui - pointer to the DenemoGUI structure * @return none */ void tohome (GtkAction * action, DenemoGUI * gui) { gui->si->currentmeasurenum = gui->si->leftmeasurenum = 1; set_rightmeasurenum (gui->si); setcurrents (gui->si); find_leftmost_allcontexts (gui->si); update_hscrollbar (gui); gtk_widget_draw (gui->scorearea, NULL); } /** * Move to the next score block for lilypond mode * @param action - Gtk Action event * @param gui - pointer to the DenemoGUI structure * @return none */ void tonextscore (GtkAction * action, DenemoGUI * gui) { GList *g = gui->si->scoreblocks; if (g == NULL) return; /* copy the si to the last in the list si->next, then copy the first to si, and then move the first to the last */ memcpy (g_list_last (g)->data, gui->si, sizeof (DenemoScore)); memcpy (gui->si, g->data, sizeof (DenemoScore)); g = g_list_append (g, g->data); /* put it on the end */ #if GTK_MAJOR_VERSION > 1 g = g_list_delete_link (g, g); /* and remove it from the beginning */ #else g = g->next; #endif gui->si->scoreblocks = g; updatescoreinfo (gui->si); } /** * Insert stem directive, absolute stemdirection for the * entire staff or until a new stem directive in added * * @param action Gtk Action event * @param gui pointer to the DenemoGUI structure * @return none */ void stem_directive_insert (GtkAction * action, DenemoGUI * gui) { object_insert (gui->si, stem_directive_new (DENEMO_STEMBOTH)); /* This sets beams and stem directions in the measure, but that's * not sufficient */ displayhelper (gui); } /** * Toggle start_slur flag for the current chord * * @param si pointer to the DenemoScore structure * @return none */ void toggle_begin_slur (DenemoScore * si) { declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { ((chord *) curmudelaobj->object)->slur_begin_p = !((chord *) curmudelaobj->object)->slur_begin_p; si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Force a cautionary accidental * @param si pointer to the scoreinfo structure * @return none */ void caution (DenemoScore * si) { declarecurmudelaobj; forceaccidentals (curmudelaobj); find_xes_in_measure (si, si->currentmeasurenum, si->cursortime1, si->cursortime2); if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } si->haschanged = TRUE; } /** * Toggle end_slur flag for the current chord * @param si pointer to the scoreinfo structure * @return none */ void toggle_end_slur (DenemoScore * si) { declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { ((chord *) curmudelaobj->object)->slur_end_p = !((chord *) curmudelaobj->object)->slur_end_p; si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Toggle start crescendo flag for current chord * @param si pointer to the scoreinfo structure * @return none */ void toggle_start_crescendo (DenemoGUI * gui) { DenemoScore *si = (DenemoScore *) gui->si; declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { ((chord *) curmudelaobj->object)->crescendo_begin_p = !((chord *) curmudelaobj->object)->crescendo_begin_p; si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Toggle end crescendo flag for current chord * @param si pointer to the scoreinfo structure * @return none */ void toggle_end_crescendo (DenemoGUI *gui) { DenemoScore *si = (DenemoScore *) gui->si; declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { ((chord *) curmudelaobj->object)->crescendo_end_p = !((chord *) curmudelaobj->object)->crescendo_end_p; si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Toggle start diminuendo flag for current chord * @param si pointer to the scoreinfo structure * @return none */ void toggle_start_diminuendo (DenemoGUI *gui) { DenemoScore *si = (DenemoScore *) gui->si; declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { ((chord *) curmudelaobj->object)->diminuendo_begin_p = !((chord *) curmudelaobj->object)->diminuendo_begin_p; si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Toggle end diminuendo flag for current chord * @param si pointer to the scoreinfo structure * @return none */ void toggle_end_diminuendo (DenemoGUI *gui) { DenemoScore *si = (DenemoScore *) gui->si; declarecurmudelaobj; if (curmudelaobj && curmudelaobj->type == CHORD) { ((chord *) curmudelaobj->object)->diminuendo_end_p = !((chord *) curmudelaobj->object)->diminuendo_end_p; si->haschanged = TRUE; if (curmudelaobj->user_string) { g_free (curmudelaobj->user_string); curmudelaobj->user_string = NULL; } } } /** * Autosave timeout function - saves the current score after the current * timeout has expired * @param si pointer to the scoreinfo structure * @return none */ gboolean auto_save_document_timeout (DenemoScore * si) { gchar *dir = locatedotdenemo (); g_print ("Autosaving\n"); if (!si->autosavename) { g_warning ("si->autosavename not set\n"); si->autosavename = g_string_new (dir); if (si->lily_file) si->autosavename = g_string_append (si->autosavename, "/autosave.ly"); else si->autosavename = g_string_append (si->autosavename, "/autosave.denemo"); } g_print ("Auto save file name %s\n", si->autosavename->str); if (si->lily_file) { exportmudela (si->autosavename->str, si, 0, 0); } else { exportXML (si->autosavename->str, si, 0, 0); } return TRUE; }