From 125173107bf3c7f45866242a836a3e7053b6677c Mon Sep 17 00:00:00 2001 From: ansstuff Date: Sat, 17 Mar 2012 15:59:35 +0000 Subject: [PATCH] * Taseditor: set/pick Markers by doubleclick, throw Markers away * Taseditor: clicks on Input don't change Selection * Taseditor: selection by dragging from Frame# * Taseditor: better way to check doubletap for Shift and Ctrl keys * Taseditor: no more "allow keys in Piano Roll"; new accelerators: Ctrl + arrows, Shift + arrows, Home/End/Page Up/Page Down, Ctrl + Home/End, Shift + Home/End * Taseditor: showing row_last_clicked when Shift or Alt is held --- src/drivers/win/config.cpp | 2 - src/drivers/win/main.cpp | 6 - src/drivers/win/res.rc | 33 +- src/drivers/win/resource.h | 20 +- src/drivers/win/taseditor.cpp | 112 +-- src/drivers/win/taseditor.h | 1 - src/drivers/win/taseditor/bookmarks.cpp | 4 +- src/drivers/win/taseditor/editor.cpp | 386 ++++++++ src/drivers/win/taseditor/editor.h | 29 + src/drivers/win/taseditor/history.cpp | 12 +- src/drivers/win/taseditor/history.h | 4 +- src/drivers/win/taseditor/piano_roll.cpp | 928 ++++++++---------- src/drivers/win/taseditor/piano_roll.h | 42 +- src/drivers/win/taseditor/recorder.cpp | 10 +- src/drivers/win/taseditor/selection.cpp | 113 ++- src/drivers/win/taseditor/selection.h | 12 +- src/drivers/win/taseditor/splicer.cpp | 8 +- .../win/taseditor/taseditor_config.cpp | 2 - src/drivers/win/taseditor/taseditor_config.h | 2 - src/drivers/win/taseditor/taseditor_lua.cpp | 8 +- src/drivers/win/taseditor/taseditor_lua.h | 2 +- src/drivers/win/taseditor/taseditor_project.h | 1 + .../win/taseditor/taseditor_window.cpp | 184 ++-- src/drivers/win/taseditor/taseditor_window.h | 6 - src/lua-engine.cpp | 8 +- vc/vc10_fceux.vcxproj | 2 + vc/vc10_fceux.vcxproj.filters | 6 + 27 files changed, 1166 insertions(+), 777 deletions(-) create mode 100644 src/drivers/win/taseditor/editor.cpp create mode 100644 src/drivers/win/taseditor/editor.h diff --git a/src/drivers/win/config.cpp b/src/drivers/win/config.cpp index 74f8c33c..f53d41d1 100644 --- a/src/drivers/win/config.cpp +++ b/src/drivers/win/config.cpp @@ -321,7 +321,6 @@ static CFGSTRUCT fceuconfig[] = { AC(taseditor_config.combine_consecutive_rec), AC(taseditor_config.use_1p_rec), AC(taseditor_config.columnset_by_keys), - AC(taseditor_config.keyboard_for_piano_roll), AC(taseditor_config.superimpose_affects_paste), AC(taseditor_config.branch_full_movie), AC(taseditor_config.branch_only_when_rec), @@ -348,7 +347,6 @@ static CFGSTRUCT fceuconfig[] = { AC(taseditor_config.findnote_matchcase), AC(taseditor_config.findnote_search_up), AC(taseditor_config.deselect_on_doubleclick), - AC(taseditor_config.doubleclick_affects_playback), AC(taseditor_config.draw_input), AC(taseditor_config.silent_autosave), AC(taseditor_config.tooltips), diff --git a/src/drivers/win/main.cpp b/src/drivers/win/main.cpp index 0a189cdd..9d82a706 100644 --- a/src/drivers/win/main.cpp +++ b/src/drivers/win/main.cpp @@ -71,10 +71,8 @@ #include "utils/xstring.h" #include #include "taseditor/taseditor_window.h" -#include "taseditor/piano_roll.h" extern TASEDITOR_WINDOW taseditor_window; -extern PIANO_ROLL piano_roll; //--------------------------- //mbg merge 6/29/06 - new aboutbox @@ -342,11 +340,7 @@ int BlockingCheck() if(!handled && taseditor_window.hwndTasEditor) { if(IsChild(taseditor_window.hwndTasEditor, msg.hwnd)) - { handled = TranslateAccelerator(taseditor_window.hwndTasEditor, fceu_hAccel, &msg); - if (handled) - piano_roll.AcceleratorDispatched(); - } } if(!handled && taseditor_window.hwndFindNote) { diff --git a/src/drivers/win/res.rc b/src/drivers/win/res.rc index 443adbe5..e22c7e7a 100644 --- a/src/drivers/win/res.rc +++ b/src/drivers/win/res.rc @@ -284,15 +284,13 @@ BEGIN MENUITEM "Bind Markers to Input", ID_CONFIG_BINDMARKERSTOINPUT,MFT_STRING,MFS_ENABLED MENUITEM "Empty new Marker Notes", ID_CONFIG_EMPTYNEWMARKERNOTES,MFT_STRING,MFS_ENABLED MENUITEM MFT_SEPARATOR - MENUITEM "Combine consecutive Recordings", ID_CONFIG_COMBINECONSECUTIVERECORDINGS,MFT_STRING,MFS_ENABLED + MENUITEM "Combine consecutive Recordings/Draws", ID_CONFIG_COMBINECONSECUTIVERECORDINGS,MFT_STRING,MFS_ENABLED MENUITEM "Use 1P keys for all single Recordings", ID_CONFIG_USE1PFORRECORDING,MFT_STRING,MFS_ENABLED MENUITEM "Use Input keys for Column Set", ID_CONFIG_USEINPUTKEYSFORCOLUMNSET,MFT_STRING,MFS_ENABLED - MENUITEM "Allow keyboard controls in Piano Roll", ID_CONFIG_KEYBOARDCONTROLSINPIANOROLL,MFT_STRING,MFS_ENABLED MENUITEM "Superimpose affects copy/paste", ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE,MFT_STRING,MFS_ENABLED MENUITEM MFT_SEPARATOR MENUITEM "Autofire Pattern skips Lag", ID_CONFIG_COLUMNSETPATTERNSKIPSLAG,MFT_STRING,MFS_ENABLED MENUITEM "Deselect on doubleclick", ID_CONFIG_DESELECTONDOUBLECLICK,MFT_STRING,MFS_ENABLED - MENUITEM "Doubleclick on Frame# affects Playback", ID_CONFIG_DOUBLECLICKONFRAME,MFT_STRING,MFS_ENABLED MENUITEM "Draw Input by dragging", ID_CONFIG_DRAWINPUTBYDRAGGING,MFT_STRING,MFS_ENABLED MENUITEM MFT_SEPARATOR MENUITEM "Silent Autosave", ID_CONFIG_SILENTAUTOSAVE,MFT_STRING,MFS_ENABLED @@ -383,17 +381,10 @@ END TASEDITORCONTEXTMENUS MENU BEGIN - POPUP "Stray" - BEGIN - MENUITEM "Unpause emulator", ID_STRAY_UNPAUSE - MENUITEM SEPARATOR - MENUITEM "Insert # of Frames", MENU_CONTEXT_STRAY_INSERTFRAMES - MENUITEM "Truncate movie", ID_STRAY_TRUNCATE - END POPUP "Selected" BEGIN - MENUITEM "Set Marker", ID_SELECTED_SETMARKER - MENUITEM "Remove Marker", ID_SELECTED_REMOVEMARKER + MENUITEM "Set Markers", ID_SELECTED_SETMARKER + MENUITEM "Remove Markers", ID_SELECTED_REMOVEMARKER MENUITEM SEPARATOR MENUITEM "Deselect", ID_SELECTED_DESELECT MENUITEM "Select between Markers", ID_SELECTED_SELECTMIDMARKERS @@ -2193,29 +2184,45 @@ END // Accelerator // -IDR_ACCELERATOR1 ACCELERATORS +IDR_TASEDITOR_ACCELERATORS ACCELERATORS BEGIN "A", ACCEL_CTRL_A, VIRTKEY, CONTROL, NOINVERT "B", ACCEL_CTRL_B, VIRTKEY, CONTROL, NOINVERT "C", ACCEL_CTRL_C, VIRTKEY, CONTROL, NOINVERT VK_DELETE, ACCEL_CTRL_DELETE, VIRTKEY, CONTROL, NOINVERT + VK_DOWN, ACCEL_CTRL_DOWN, VIRTKEY, CONTROL, NOINVERT "F", ACCEL_CTRL_F, VIRTKEY, CONTROL, NOINVERT VK_INSERT, ACCEL_CTRL_INSERT, VIRTKEY, CONTROL, NOINVERT + VK_LEFT, ACCEL_CTRL_LEFT, VIRTKEY, CONTROL, NOINVERT VK_NEXT, ACCEL_CTRL_PGDN, VIRTKEY, CONTROL, NOINVERT VK_PRIOR, ACCEL_CTRL_PGUP, VIRTKEY, CONTROL, NOINVERT "Q", ACCEL_CTRL_Q, VIRTKEY, CONTROL, NOINVERT + VK_RIGHT, ACCEL_CTRL_RIGHT, VIRTKEY, CONTROL, NOINVERT "S", ACCEL_CTRL_S, VIRTKEY, CONTROL, NOINVERT + VK_UP, ACCEL_CTRL_UP, VIRTKEY, CONTROL, NOINVERT "V", ACCEL_CTRL_V, VIRTKEY, CONTROL, NOINVERT "W", ACCEL_CTRL_W, VIRTKEY, CONTROL, NOINVERT "X", ACCEL_CTRL_X, VIRTKEY, CONTROL, NOINVERT "Y", ACCEL_CTRL_Y, VIRTKEY, CONTROL, NOINVERT "Z", ACCEL_CTRL_Z, VIRTKEY, CONTROL, NOINVERT VK_DELETE, ACCEL_DEL, VIRTKEY, NOINVERT + VK_END, ACCEL_END, VIRTKEY, NOINVERT + VK_HOME, ACCEL_HOME, VIRTKEY, NOINVERT VK_INSERT, ACCEL_INS, VIRTKEY, NOINVERT + VK_NEXT, ACCEL_PGDN, VIRTKEY, NOINVERT + VK_PRIOR, ACCEL_PGUP, VIRTKEY, NOINVERT VK_INSERT, ACCEL_SHIFT_INS, VIRTKEY, SHIFT, NOINVERT VK_NEXT, ACCEL_SHIFT_PGDN, VIRTKEY, SHIFT, NOINVERT VK_PRIOR, ACCEL_SHIFT_PGUP, VIRTKEY, SHIFT, NOINVERT "V", ACCEL_SHIFT_V, VIRTKEY, SHIFT, NOINVERT + VK_HOME, ACCEL_CTRL_HOME, VIRTKEY, CONTROL, NOINVERT + VK_END, ACCEL_CTRL_END, VIRTKEY, CONTROL, NOINVERT + VK_HOME, ACCEL_SHIFT_HOME, VIRTKEY, SHIFT, NOINVERT + VK_END, ACCEL_SHIFT_END, VIRTKEY, SHIFT, NOINVERT + VK_UP, ACCEL_SHIFT_UP, VIRTKEY, SHIFT, NOINVERT + VK_DOWN, ACCEL_SHIFT_DOWN, VIRTKEY, SHIFT, NOINVERT + VK_LEFT, ACCEL_SHIFT_LEFT, VIRTKEY, SHIFT, NOINVERT + VK_RIGHT, ACCEL_SHIFT_RIGHT, VIRTKEY, SHIFT, NOINVERT END IDR_RWACCELERATOR ACCELERATORS diff --git a/src/drivers/win/resource.h b/src/drivers/win/resource.h index cddc2f74..e59f343b 100644 --- a/src/drivers/win/resource.h +++ b/src/drivers/win/resource.h @@ -98,6 +98,7 @@ #define BTN_CDLOGGER_SAVE_STRIPPED 108 #define IDC_CHEAT_VAL_NE_BY 108 #define IDC_DEBUGGER_SEEK_PC 108 +#define IDR_TASEDITOR_ACCELERATORS 108 #define IDC_CHEAT_VAL_GT_BY 109 #define IDC_DEBUGGER_SEEK_TO 109 #define IDC_ROMPATCHER_PATCH_DATA 109 @@ -997,6 +998,23 @@ #define ID_CONFIG_DESELECTONDOUBLECLICK 40538 #define ID_CONFIG_DRAWINPUTBYDRAGGING 40539 #define ID_CONFIG_DOUBLECLICKONFRAME 40540 +#define ACCEL_CTRL_UP 40541 +#define ACCEL_CTRL_DOWN 40542 +#define ACCEL_CTRL_LEFT 40543 +#define ACCEL_CTRL_RIGHT 40544 +#define ACCEL_HOME 40545 +#define ACCEL_END 40546 +#define ACCEL_PGUP 40547 +#define ACCEL_PGDN 40548 +#define ACCEL_CTRL_HOME 40550 +#define ACCEL_CTRL_END 40551 +#define ACCEL_SHIFT_HOME 40552 +#define ACCEL_SHIFT_END 40553 +#define ACCEL_SHIFT_UP 40554 +#define ACCEL_SHIFT_DOWN 40555 +#define ACCEL_SHIFT_LEFT 40556 +#define ID_ACCELERATOR40557 40557 +#define ACCEL_SHIFT_RIGHT 40557 #define IDC_DEBUGGER_ICONTRAY 55535 #define MW_ValueLabel2 65423 #define MW_ValueLabel1 65426 @@ -1006,7 +1024,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 206 -#define _APS_NEXT_COMMAND_VALUE 40541 +#define _APS_NEXT_COMMAND_VALUE 40559 #define _APS_NEXT_CONTROL_VALUE 1281 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/src/drivers/win/taseditor.cpp b/src/drivers/win/taseditor.cpp index af6cd67d..19c7bde6 100644 --- a/src/drivers/win/taseditor.cpp +++ b/src/drivers/win/taseditor.cpp @@ -14,8 +14,6 @@ Main - Logical center of the program * the point of quitting from TAS Editor * regularly (at the end of every frame) updates all modules that need regular update * implements operations of the "File" menu: creating New project, opening a file, saving, compact saving, import, export -* stores Autofire Patterns data and their loading/generating code -* stores resources: patterns filename, id of buttonpresses in patterns ------------------------------------------------------------------------------------ */ #include @@ -30,8 +28,6 @@ using namespace std; bool emulator_must_run_taseditor = false; bool Taseditor_rewind_now = false; bool must_call_manual_lua_function = false; -std::vector autofire_patterns_names; -std::vector> autofire_patterns; // all Taseditor functional modules TASEDITOR_CONFIG taseditor_config; @@ -48,6 +44,7 @@ PIANO_ROLL piano_roll; TASEDITOR_LUA taseditor_lua; SELECTION selection; SPLICER splicer; +EDITOR editor; extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES]; extern bool turbo; @@ -62,87 +59,12 @@ extern void UpdateCheckedMenuItems(); extern void TaseditorAutoFunction(); extern void TaseditorManualFunction(); -// resources -char patternsFilename[] = "\\taseditor_patterns.txt"; -char autofire_patterns_flagpress = 49; // "1" - bool EnterTasEditor() { if(!FCEU_IsValidUI(FCEUI_TASEDITOR)) return false; if(!taseditor_window.hwndTasEditor) { // start TAS Editor - - // init/load autofire_patterns - int total_patterns = 0; - autofire_patterns.resize(total_patterns); - autofire_patterns_names.resize(total_patterns); - char nameo[2048]; - strncpy(nameo, FCEU_GetPath(FCEUMKF_TASEDITOR).c_str(), 2047); - strncat(nameo, patternsFilename, 2047 - strlen(nameo)); - EMUFILE_FILE ifs(nameo, "rb"); - if(!ifs.fail()) - { - std::string tempstr1, tempstr2; - while (ReadString(&ifs, tempstr1)) - { - if (ReadString(&ifs, tempstr2)) - { - total_patterns++; - // save the name - autofire_patterns_names.push_back(tempstr1); - // parse 2nd string to sequence of 1s and 0s - autofire_patterns.resize(total_patterns); - autofire_patterns[total_patterns - 1].resize(tempstr2.size()); - for (int i = tempstr2.size() - 1; i >= 0; i--) - { - if (tempstr2[i] == autofire_patterns_flagpress) - autofire_patterns[total_patterns - 1][i] = 1; - else - autofire_patterns[total_patterns - 1][i] = 0; - } - } - } - } else - { - FCEU_printf("Could not load tools\\taseditor_patterns.txt!\n"); - } - if (autofire_patterns.size() == 0) - { - FCEU_printf("Will be using default set of patterns...\n"); - autofire_patterns.resize(4); - autofire_patterns_names.resize(4); - // Default Pattern 0: Alternating (1010...) - autofire_patterns_names[0] = "Alternating (1010...)"; - autofire_patterns[0].resize(2); - autofire_patterns[0][0] = 1; - autofire_patterns[0][1] = 0; - // Default Pattern 1: Alternating at 30FPS (11001100...) - autofire_patterns_names[1] = "Alternating at 30FPS (11001100...)"; - autofire_patterns[1].resize(4); - autofire_patterns[1][0] = 1; - autofire_patterns[1][1] = 1; - autofire_patterns[1][2] = 0; - autofire_patterns[1][3] = 0; - // Default Pattern 2: One Quarter (10001000...) - autofire_patterns_names[2] = "One Quarter (10001000...)"; - autofire_patterns[2].resize(4); - autofire_patterns[2][0] = 1; - autofire_patterns[2][1] = 0; - autofire_patterns[2][2] = 0; - autofire_patterns[2][3] = 0; - // Default Pattern 3: Tap'n'Hold (1011111111111111111111111111111111111...) - autofire_patterns_names[3] = "Tap'n'Hold (101111111...)"; - autofire_patterns[3].resize(1000); - autofire_patterns[3][0] = 1; - autofire_patterns[3][1] = 0; - for (int i = 2; i < 1000; ++i) - autofire_patterns[3][i] = 1; - } - // reset current_pattern if it's outside the range - if (taseditor_config.current_pattern < 0 || taseditor_config.current_pattern >= (int)autofire_patterns.size()) - taseditor_config.current_pattern = 0; - // create window taseditor_window.init(); if(taseditor_window.hwndTasEditor) @@ -162,6 +84,7 @@ bool EnterTasEditor() UpdateCheckedMenuItems(); // init modules + editor.init(); piano_roll.init(); selection.init(); splicer.init(); @@ -214,40 +137,15 @@ bool EnterTasEditor() } else return false; } else return true; } -// returns false if couldn't real a string containing at least one char -bool ReadString(EMUFILE *is, std::string& dest) -{ - dest.resize(0); - int c; - while (true) - { - c = is->fgetc(); - if (c < 0) break; - if (c == 10 || c == 13) // end of line - { - if (dest.size()) - break; // already collected at least one char - else - continue; // skip the char and continue searching - } else - { - dest.push_back(c); - } - } - return dest.size() != 0; -} bool ExitTasEditor() { if (!AskSaveProject()) return false; - // free autofire_patterns - autofire_patterns.resize(0); - autofire_patterns_names.resize(0); - // destroy window taseditor_window.exit(); // release memory + editor.free(); piano_roll.free(); markers_manager.free(); greenzone.free(); @@ -422,6 +320,7 @@ void NewProject() history.reset(); piano_roll.reset(); selection.reset(); + editor.reset(); splicer.reset(); recorder.reset(); popup_display.reset(); @@ -851,4 +750,5 @@ bool TaseditorIsRecording() if (movie_readonly || playback.pause_frame > currFrameCounter) return false; // replay return true; // record -} \ No newline at end of file +} + diff --git a/src/drivers/win/taseditor.h b/src/drivers/win/taseditor.h index 735d4e56..6b88ed4e 100644 --- a/src/drivers/win/taseditor.h +++ b/src/drivers/win/taseditor.h @@ -9,7 +9,6 @@ struct NewProjectParameters }; bool EnterTasEditor(); -bool ReadString(EMUFILE *is, std::string& dest); bool ExitTasEditor(); void UpdateTasEditor(); diff --git a/src/drivers/win/taseditor/bookmarks.cpp b/src/drivers/win/taseditor/bookmarks.cpp index 4120d00c..851346e9 100644 --- a/src/drivers/win/taseditor/bookmarks.cpp +++ b/src/drivers/win/taseditor/bookmarks.cpp @@ -516,7 +516,7 @@ void BOOKMARKS::deploy(int slot) { // restore entire movie bookmarks_array[slot].snapshot.toMovie(currMovieData, first_change); - piano_roll.update(); + piano_roll.UpdateItemCount(); selection.must_find_current_marker = playback.must_find_current_marker = true; history.RegisterBranching(MODTYPE_BRANCH_0 + slot, first_change, slot); greenzone.Invalidate(first_change); @@ -551,7 +551,7 @@ void BOOKMARKS::deploy(int slot) // restore movie up to and not including bookmarked frame (imitating old TASing method) if (currMovieData.getNumRecords() <= jump_frame) currMovieData.records.resize(jump_frame+1); // but if old movie is shorter, include last frame as blank frame bookmarks_array[slot].snapshot.toMovie(currMovieData, first_change, jump_frame-1); - piano_roll.update(); + piano_roll.UpdateItemCount(); selection.must_find_current_marker = playback.must_find_current_marker = true; history.RegisterBranching(MODTYPE_BRANCH_0 + slot, first_change, slot); greenzone.Invalidate(first_change); diff --git a/src/drivers/win/taseditor/editor.cpp b/src/drivers/win/taseditor/editor.cpp new file mode 100644 index 00000000..5277bbfc --- /dev/null +++ b/src/drivers/win/taseditor/editor.cpp @@ -0,0 +1,386 @@ +/* --------------------------------------------------------------------------------- +Implementation file of EDITOR class +Copyright (c) 2011-2012 AnS + +(The MIT License) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------------ +Editor - Interface for editing Input and Markers +[Singleton] + +* implements operations of changing Input: +* implements operations of changing Markers: + + +* stores Autofire Patterns data and their loading/generating code +* stores resources: patterns filename, id of buttonpresses in patterns + +------------------------------------------------------------------------------------ */ + +#include "taseditor_project.h" + +extern TASEDITOR_WINDOW taseditor_window; +extern TASEDITOR_CONFIG taseditor_config; +extern HISTORY history; +extern MARKERS_MANAGER markers_manager; +extern PLAYBACK playback; +extern GREENZONE greenzone; +extern PIANO_ROLL piano_roll; +extern SELECTION selection; + +extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES]; +extern int GetInputType(MovieData& md); + +// resources +char patternsFilename[] = "\\taseditor_patterns.txt"; +char autofire_patterns_flagpress = 49; // "1" + +EDITOR::EDITOR() +{ +} + +void EDITOR::init() +{ + free(); + // load autofire_patterns + int total_patterns = 0; + char nameo[2048]; + strncpy(nameo, FCEU_GetPath(FCEUMKF_TASEDITOR).c_str(), 2047); + strncat(nameo, patternsFilename, 2047 - strlen(nameo)); + EMUFILE_FILE ifs(nameo, "rb"); + if(!ifs.fail()) + { + std::string tempstr1, tempstr2; + while (ReadString(&ifs, tempstr1)) + { + if (ReadString(&ifs, tempstr2)) + { + total_patterns++; + // save the name + autofire_patterns_names.push_back(tempstr1); + // parse 2nd string to sequence of 1s and 0s + autofire_patterns.resize(total_patterns); + autofire_patterns[total_patterns - 1].resize(tempstr2.size()); + for (int i = tempstr2.size() - 1; i >= 0; i--) + { + if (tempstr2[i] == autofire_patterns_flagpress) + autofire_patterns[total_patterns - 1][i] = 1; + else + autofire_patterns[total_patterns - 1][i] = 0; + } + } + } + } else + { + FCEU_printf("Could not load tools\\taseditor_patterns.txt!\n"); + } + if (autofire_patterns.size() == 0) + { + FCEU_printf("Will be using default set of patterns...\n"); + autofire_patterns.resize(4); + autofire_patterns_names.resize(4); + // Default Pattern 0: Alternating (1010...) + autofire_patterns_names[0] = "Alternating (1010...)"; + autofire_patterns[0].resize(2); + autofire_patterns[0][0] = 1; + autofire_patterns[0][1] = 0; + // Default Pattern 1: Alternating at 30FPS (11001100...) + autofire_patterns_names[1] = "Alternating at 30FPS (11001100...)"; + autofire_patterns[1].resize(4); + autofire_patterns[1][0] = 1; + autofire_patterns[1][1] = 1; + autofire_patterns[1][2] = 0; + autofire_patterns[1][3] = 0; + // Default Pattern 2: One Quarter (10001000...) + autofire_patterns_names[2] = "One Quarter (10001000...)"; + autofire_patterns[2].resize(4); + autofire_patterns[2][0] = 1; + autofire_patterns[2][1] = 0; + autofire_patterns[2][2] = 0; + autofire_patterns[2][3] = 0; + // Default Pattern 3: Tap'n'Hold (1011111111111111111111111111111111111...) + autofire_patterns_names[3] = "Tap'n'Hold (101111111...)"; + autofire_patterns[3].resize(1000); + autofire_patterns[3][0] = 1; + autofire_patterns[3][1] = 0; + for (int i = 2; i < 1000; ++i) + autofire_patterns[3][i] = 1; + } + // reset current_pattern if it's outside the range + if (taseditor_config.current_pattern < 0 || taseditor_config.current_pattern >= (int)autofire_patterns.size()) + taseditor_config.current_pattern = 0; + taseditor_window.UpdatePatternsMenu(); + + reset(); +} +void EDITOR::free() +{ + autofire_patterns.resize(0); + autofire_patterns_names.resize(0); +} +void EDITOR::reset() +{ + +} +void EDITOR::update() +{ + + + +} +// ---------------------------------------------------------------------------------------------- +// returns false if couldn't real a string containing at least one char +bool EDITOR::ReadString(EMUFILE *is, std::string& dest) +{ + dest.resize(0); + int charr; + while (true) + { + charr = is->fgetc(); + if (charr < 0) break; + if (charr == 10 || charr == 13) // end of line + { + if (dest.size()) + break; // already collected at least one char + else + continue; // skip the char and continue searching + } else + { + dest.push_back(charr); + } + } + return dest.size() != 0; +} +// ---------------------------------------------------------------------------------------------- +// following functions use function parameters to determine range of frames +void EDITOR::InputToggle(int start, int end, int joy, int button) +{ + if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return; + + int check_frame = end; + if (start > end) + { + // swap + int temp_start = start; + start = end; + end = temp_start; + } + if (start < 0) start = end; + if (end >= currMovieData.getNumRecords()) + return; + + if (currMovieData.records[check_frame].checkBit(joy, button)) + { + // clear range + for (int i = start; i <= end; ++i) + currMovieData.records[i].clearBit(joy, button); + greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, start, end)); + } else + { + // set range + for (int i = start; i <= end; ++i) + currMovieData.records[i].setBit(joy, button); + greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, start, end)); + } +} +void EDITOR::InputSetPattern(int start, int end, int joy, int button) +{ + if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return; + + if (start > end) + { + // swap + int temp_start = start; + start = end; + end = temp_start; + } + if (start < 0) start = end; + if (end >= currMovieData.getNumRecords()) + return; + + int pattern_offset = 0, current_pattern = taseditor_config.current_pattern; + + for (int i = start; i <= end; ++i) + { + // skip lag frames + if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(i)) + continue; + currMovieData.records[i].setBitValue(joy, button, autofire_patterns[current_pattern][pattern_offset] != 0); + pattern_offset++; + if (pattern_offset >= (int)autofire_patterns[current_pattern].size()) + pattern_offset -= autofire_patterns[current_pattern].size(); + } + greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_PATTERN, start, end, autofire_patterns_names[current_pattern].c_str())); +} + +// following functions use current Selection to determine range of frames +bool EDITOR::FrameColumnSet() +{ + SelectionFrames* current_selection = selection.MakeStrobe(); + if (current_selection->size() == 0) return false; + SelectionFrames::iterator current_selection_begin(current_selection->begin()); + SelectionFrames::iterator current_selection_end(current_selection->end()); + + // inspect the selected frames, if they are all set, then unset all, else set all + bool unset_found = false, changes_made = false; + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + { + if(!markers_manager.GetMarker(*it)) + { + unset_found = true; + break; + } + } + if (unset_found) + { + // set all + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + { + if(!markers_manager.GetMarker(*it)) + { + if (markers_manager.SetMarker(*it)) + { + changes_made = true; + piano_roll.RedrawRow(*it); + } + } + } + if (changes_made) + history.RegisterMarkersChange(MODTYPE_MARKER_SET, *current_selection_begin, *current_selection->rbegin()); + } else + { + // unset all + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + { + if(markers_manager.GetMarker(*it)) + { + markers_manager.ClearMarker(*it); + changes_made = true; + piano_roll.RedrawRow(*it); + } + } + if (changes_made) + history.RegisterMarkersChange(MODTYPE_MARKER_REMOVE, *current_selection_begin, *current_selection->rbegin()); + } + if (changes_made) + selection.must_find_current_marker = playback.must_find_current_marker = true; + return changes_made; +} +bool EDITOR::FrameColumnSetPattern() +{ + SelectionFrames* current_selection = selection.MakeStrobe(); + if (current_selection->size() == 0) return false; + SelectionFrames::iterator current_selection_begin(current_selection->begin()); + SelectionFrames::iterator current_selection_end(current_selection->end()); + int pattern_offset = 0, current_pattern = taseditor_config.current_pattern; + bool changes_made = false; + + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + { + // skip lag frames + if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(*it)) + continue; + if (autofire_patterns[current_pattern][pattern_offset]) + { + if(!markers_manager.GetMarker(*it)) + { + if (markers_manager.SetMarker(*it)) + { + changes_made = true; + piano_roll.RedrawRow(*it); + } + } + } else + { + if(markers_manager.GetMarker(*it)) + { + markers_manager.ClearMarker(*it); + changes_made = true; + piano_roll.RedrawRow(*it); + } + } + pattern_offset++; + if (pattern_offset >= (int)autofire_patterns[current_pattern].size()) + pattern_offset -= autofire_patterns[current_pattern].size(); + } + if (changes_made) + { + history.RegisterMarkersChange(MODTYPE_MARKER_PATTERN, *current_selection_begin, *current_selection->rbegin(), autofire_patterns_names[current_pattern].c_str()); + selection.must_find_current_marker = playback.must_find_current_marker = true; + return true; + } else + return false; +} + +bool EDITOR::InputColumnSet(int joy, int button) +{ + if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return false; + + SelectionFrames* current_selection = selection.MakeStrobe(); + if (current_selection->size() == 0) return false; + SelectionFrames::iterator current_selection_begin(current_selection->begin()); + SelectionFrames::iterator current_selection_end(current_selection->end()); + + //inspect the selected frames, if they are all set, then unset all, else set all + bool newValue = false; + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + { + if(!(currMovieData.records[*it].checkBit(joy,button))) + { + newValue = true; + break; + } + } + // apply newValue + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + currMovieData.records[*it].setBitValue(joy,button,newValue); + + int first_changes; + if (newValue) + { + first_changes = history.RegisterChanges(MODTYPE_SET, *current_selection_begin, *current_selection->rbegin()); + } else + { + first_changes = history.RegisterChanges(MODTYPE_UNSET, *current_selection_begin, *current_selection->rbegin()); + } + if (first_changes >= 0) + { + greenzone.InvalidateAndCheck(first_changes); + return true; + } else + return false; +} +bool EDITOR::InputColumnSetPattern(int joy, int button) +{ + if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return false; + + SelectionFrames* current_selection = selection.MakeStrobe(); + if (current_selection->size() == 0) return false; + SelectionFrames::iterator current_selection_begin(current_selection->begin()); + SelectionFrames::iterator current_selection_end(current_selection->end()); + int pattern_offset = 0, current_pattern = taseditor_config.current_pattern; + + for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) + { + // skip lag frames + if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(*it)) + continue; + currMovieData.records[*it].setBitValue(joy, button, autofire_patterns[current_pattern][pattern_offset] != 0); + pattern_offset++; + if (pattern_offset >= (int)autofire_patterns[current_pattern].size()) + pattern_offset -= autofire_patterns[current_pattern].size(); + } + int first_changes = history.RegisterChanges(MODTYPE_PATTERN, *current_selection_begin, *current_selection->rbegin(), autofire_patterns_names[current_pattern].c_str()); + if (first_changes >= 0) + { + greenzone.InvalidateAndCheck(first_changes); + return true; + } else + return false; +} +// ---------------------------------------------------------------------------------------------- + + + diff --git a/src/drivers/win/taseditor/editor.h b/src/drivers/win/taseditor/editor.h new file mode 100644 index 00000000..779cf573 --- /dev/null +++ b/src/drivers/win/taseditor/editor.h @@ -0,0 +1,29 @@ +// Specification file for EDITOR class + +class EDITOR +{ +public: + EDITOR(); + void init(); + void free(); + void reset(); + void update(); + + void InputToggle(int start, int end, int joy, int button); + void InputSetPattern(int start, int end, int joy, int button); + + bool FrameColumnSet(); + bool FrameColumnSetPattern(); + bool InputColumnSet(int joy, int button); + bool InputColumnSetPattern(int joy, int button); + + + + std::vector autofire_patterns_names; + std::vector> autofire_patterns; + + +private: + bool ReadString(EMUFILE *is, std::string& dest); + +}; diff --git a/src/drivers/win/taseditor/history.cpp b/src/drivers/win/taseditor/history.cpp index f7479ede..6543975b 100644 --- a/src/drivers/win/taseditor/history.cpp +++ b/src/drivers/win/taseditor/history.cpp @@ -80,14 +80,14 @@ char modCaptions[MODTYPES_TOTAL][20] = {" Init Project", " Marker Branch8 to ", " Marker Branch9 to ", " Marker Set", - " Marker Unset", + " Marker Remove", " Marker Pattern", " Marker Rename", " Marker Drag", " Marker Swap", " Marker Shift", " LUA Marker Set", - " LUA Marker Unset", + " LUA Marker Remove", " LUA Marker Rename", " LUA Change" }; char LuaCaptionPrefix[6] = " LUA "; @@ -247,7 +247,7 @@ void HISTORY::undo() int result = jump(history_cursor_pos - 1); if (result >= 0) { - piano_roll.update(); + piano_roll.UpdateItemCount(); piano_roll.FollowUndo(); greenzone.InvalidateAndCheck(result); } @@ -258,7 +258,7 @@ void HISTORY::redo() int result = jump(history_cursor_pos + 1); if (result >= 0) { - piano_roll.update(); + piano_roll.UpdateItemCount(); piano_roll.FollowUndo(); greenzone.InvalidateAndCheck(result); } @@ -600,7 +600,7 @@ void HISTORY::RegisterImport(MovieData& md, char* filename) } AddSnapshotToHistory(inp); inp.toMovie(currMovieData); - piano_roll.update(); + piano_roll.UpdateItemCount(); bookmarks.ChangesMadeSinceBranch(); project.SetProjectChanged(); greenzone.InvalidateAndCheck(first_changes); @@ -794,7 +794,7 @@ void HISTORY::Click(int row_index) int result = jump(row_index); if (result >= 0) { - piano_roll.update(); + piano_roll.UpdateItemCount(); piano_roll.FollowUndo(); greenzone.InvalidateAndCheck(result); return; diff --git a/src/drivers/win/taseditor/history.h b/src/drivers/win/taseditor/history.h index ed346042..7228b640 100644 --- a/src/drivers/win/taseditor/history.h +++ b/src/drivers/win/taseditor/history.h @@ -41,14 +41,14 @@ enum MODTYPE_BRANCH_MARKERS_8, MODTYPE_BRANCH_MARKERS_9, MODTYPE_MARKER_SET, - MODTYPE_MARKER_UNSET, + MODTYPE_MARKER_REMOVE, MODTYPE_MARKER_PATTERN, MODTYPE_MARKER_RENAME, MODTYPE_MARKER_DRAG, MODTYPE_MARKER_SWAP, MODTYPE_MARKER_SHIFT, MODTYPE_LUA_MARKER_SET, - MODTYPE_LUA_MARKER_UNSET, + MODTYPE_LUA_MARKER_REMOVE, MODTYPE_LUA_MARKER_RENAME, MODTYPE_LUA_CHANGE, diff --git a/src/drivers/win/taseditor/piano_roll.cpp b/src/drivers/win/taseditor/piano_roll.cpp index 72224822..dc8eb6bf 100644 --- a/src/drivers/win/taseditor/piano_roll.cpp +++ b/src/drivers/win/taseditor/piano_roll.cpp @@ -31,9 +31,6 @@ Piano Roll - Piano Roll interface extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES]; extern char buttonNames[NUM_JOYPAD_BUTTONS][2]; -extern std::vector autofire_patterns_names; -extern std::vector> autofire_patterns; - extern TASEDITOR_CONFIG taseditor_config; extern TASEDITOR_WINDOW taseditor_window; extern BOOKMARKS bookmarks; @@ -43,6 +40,7 @@ extern GREENZONE greenzone; extern HISTORY history; extern MARKERS_MANAGER markers_manager; extern SELECTION selection; +extern EDITOR editor; extern int GetInputType(MovieData& md); @@ -58,6 +56,7 @@ char piano_roll_skipsave_id[PIANO_ROLL_ID_LEN] = "PIANO_ROLX"; COLORREF hot_changes_colors[16] = { 0x0, 0x5c4c44, 0x854604, 0xab2500, 0xc20006, 0xd6006f, 0xd40091, 0xba00a4, 0x9500ba, 0x7a00cc, 0x5800d4, 0x0045e2, 0x0063ea, 0x0079f4, 0x0092fa, 0x00aaff }; //COLORREF hot_changes_colors[16] = { 0x0, 0x661212, 0x842B4E, 0x652C73, 0x48247D, 0x383596, 0x2947AE, 0x1E53C1, 0x135DD2, 0x116EDA, 0x107EE3, 0x0F8EEB, 0x209FF4, 0x3DB1FD, 0x51C2FF, 0x4DCDFF }; COLORREF header_lights_colors[11] = { 0x0, 0x007313, 0x009100, 0x1daf00, 0x42c700, 0x65d900, 0x91e500, 0xb0f000, 0xdaf700, 0xf0fc7c, 0xfcffba }; + char markerDragBoxClassName[] = "MarkerDragBox"; PIANO_ROLL::PIANO_ROLL() @@ -294,7 +293,9 @@ void PIANO_ROLL::free() void PIANO_ROLL::reset() { must_check_item_under_mouse = true; - vk_shift_release_time = vk_control_release_time = 0; + row_last_clicked = 0; + shift_held = ctrl_held = alt_held = false; + shift_timer = ctrl_timer = shift_count = ctrl_count = 0; next_header_update_time = header_item_under_mouse = 0; // delete all columns except 0th while (ListView_DeleteColumn(hwndList, 1)) {} @@ -329,11 +330,117 @@ void PIANO_ROLL::reset() } void PIANO_ROLL::update() { - //update the number of items in the list - int currLVItemCount = ListView_GetItemCount(hwndList); - int movie_size = currMovieData.getNumRecords(); - if(currLVItemCount != movie_size) - ListView_SetItemCountEx(hwndList, movie_size, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL); + UpdateItemCount(); + + if (must_check_item_under_mouse) + { + // find row and column + POINT p; + if (GetCursorPos(&p)) + { + ScreenToClient(hwndList, &p); + // perform hit test + LVHITTESTINFO info; + info.pt.x = p.x; + info.pt.y = p.y; + ListView_SubItemHitTest(hwndList, &info); + row_under_mouse = info.iItem; + real_row_under_mouse = row_under_mouse; + if (real_row_under_mouse < 0) + { + real_row_under_mouse = ListView_GetTopIndex(hwndList) + (p.y - list_row_top) / list_row_height; + if (real_row_under_mouse < 0) real_row_under_mouse--; + } + column_under_mouse = info.iSubItem; + } + // change mouse cursor depending on what it points at + LPCSTR cursor_icon = IDC_ARROW; + switch (drag_mode) + { + case DRAG_MODE_NONE: + { + // normal mouseover + if (row_under_mouse >= 0 + && (column_under_mouse == COLUMN_FRAMENUM || column_under_mouse == COLUMN_FRAMENUM2) + && markers_manager.GetMarker(row_under_mouse)) + cursor_icon = IDC_SIZEALL; + break; + } + case DRAG_MODE_PLAYBACK: + { + // dragging Playback cursor - show either normal arrow or arrow+wait + if (playback.pause_frame) + cursor_icon = IDC_APPSTARTING; + break; + } + case DRAG_MODE_MARKER: + case DRAG_MODE_OBSERVE: + case DRAG_MODE_SET: + case DRAG_MODE_UNSET: + case DRAG_MODE_SELECTION: + // show normal arrow + break; + } + SetCursor(LoadCursor(0, cursor_icon)); + // and don't check until mouse moves or Piano Roll scrolls + must_check_item_under_mouse = false; + } + + // update state of Shift/Ctrl/Alt holding + bool last_shift_held = shift_held, last_ctrl_held = ctrl_held, last_alt_held = alt_held; + shift_held = (GetAsyncKeyState(VK_SHIFT) < 0); + ctrl_held = (GetAsyncKeyState(VK_CONTROL) < 0); + alt_held = (GetAsyncKeyState(VK_MENU) < 0); + // check doubletap of Shift/Ctrl + if (last_shift_held != shift_held) + { + if ((int)(shift_timer + GetDoubleClickTime()) > clock()) + { + shift_count++; + if (shift_count >= DOUBLETAP_COUNT) + { + FollowPlayback(); + shift_count = ctrl_count = 0; + } + } else + { + shift_count = 0; + } + shift_timer = clock(); + } + if (last_ctrl_held != ctrl_held) + { + if ((int)(ctrl_timer + GetDoubleClickTime()) > clock()) + { + ctrl_count++; + if (ctrl_count >= DOUBLETAP_COUNT) + { + FollowSelection(); + ctrl_count = shift_count = 0; + } + } else + { + ctrl_count = 0; + } + ctrl_timer = clock(); + } + // show/hide "focused" rectangle on row_last_clicked + if (shift_held || alt_held) + { + if ((shift_held && !last_shift_held) || (alt_held && !last_alt_held)) + row_last_clicked_blinking_phase_shift = ROW_LAST_CLICKED_BLINKING_PERIOD + (clock() % (2 * ROW_LAST_CLICKED_BLINKING_PERIOD)); + bool show_row_last_clicked = (((clock() - row_last_clicked_blinking_phase_shift) / ROW_LAST_CLICKED_BLINKING_PERIOD) & 1) != 0; + if (show_row_last_clicked) + { + ListView_SetItemState(hwndList, row_last_clicked, LVIS_FOCUSED, LVIS_FOCUSED); + } else + { + ListView_SetItemState(hwndList, row_last_clicked, 0, LVIS_FOCUSED); + } + } else if (last_shift_held || last_alt_held) + { + ListView_SetItemState(hwndList, row_last_clicked, 0, LVIS_FOCUSED); + } // update dragging if (drag_mode != DRAG_MODE_NONE) @@ -358,14 +465,17 @@ void PIANO_ROLL::update() RECT wrect; GetClientRect(hwndList, &wrect); int scroll_dx = 0, scroll_dy = 0; - if (p.x < SCROLLING_BORDER_SIZE) - scroll_dx = p.x - SCROLLING_BORDER_SIZE; - else if (p.x > (wrect.right - wrect.left - SCROLLING_BORDER_SIZE)) - scroll_dx = p.x - (wrect.right - wrect.left - SCROLLING_BORDER_SIZE); - if (p.y < (list_header_height + SCROLLING_BORDER_SIZE)) - scroll_dy = p.y - (list_header_height + SCROLLING_BORDER_SIZE); - else if (p.y > (wrect.bottom - wrect.top - SCROLLING_BORDER_SIZE)) - scroll_dy = p.y - (wrect.bottom - wrect.top - SCROLLING_BORDER_SIZE); + if (drag_mode != DRAG_MODE_MARKER) // in DRAG_MODE_MARKER user can't scroll Piano Roll horizontally + { + if (p.x < DRAG_SCROLLING_BORDER_SIZE) + scroll_dx = p.x - DRAG_SCROLLING_BORDER_SIZE; + else if (p.x > (wrect.right - wrect.left - DRAG_SCROLLING_BORDER_SIZE)) + scroll_dx = p.x - (wrect.right - wrect.left - DRAG_SCROLLING_BORDER_SIZE); + } + if (p.y < (list_header_height + DRAG_SCROLLING_BORDER_SIZE)) + scroll_dy = p.y - (list_header_height + DRAG_SCROLLING_BORDER_SIZE); + else if (p.y > (wrect.bottom - wrect.top - DRAG_SCROLLING_BORDER_SIZE)) + scroll_dy = p.y - (wrect.bottom - wrect.top - DRAG_SCROLLING_BORDER_SIZE); if (scroll_dx || scroll_dy) ListView_Scroll(hwndList, scroll_dx, scroll_dy); } @@ -399,21 +509,18 @@ void PIANO_ROLL::update() // when dragging, always show semi-transparent yellow rectangle under mouse POINT p = {0, 0}; GetCursorPos(&p); - int window_x = p.x - marker_drag_box_dx; - int window_y = p.y - marker_drag_box_dy; + marker_drag_box_x = p.x - marker_drag_box_dx; + marker_drag_box_y = p.y - marker_drag_box_dy; if (!hwndMarkerDragBox) { - hwndMarkerDragBox = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, markerDragBoxClassName, markerDragBoxClassName, WS_POPUP, window_x, window_y, COLUMN_FRAMENUM_WIDTH, list_row_height, taseditor_window.hwndTasEditor, NULL, fceu_hInstance, NULL); + hwndMarkerDragBox = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, markerDragBoxClassName, markerDragBoxClassName, WS_POPUP, marker_drag_box_x, marker_drag_box_y, COLUMN_FRAMENUM_WIDTH, list_row_height, taseditor_window.hwndTasEditor, NULL, fceu_hInstance, NULL); ShowWindow(hwndMarkerDragBox, SW_SHOWNA); - SetLayeredWindowAttributes(hwndMarkerDragBox, 0, MARKER_DRAG_BOX_ALPHA, LWA_ALPHA); - UpdateLayeredWindow(hwndMarkerDragBox, 0, 0, 0, 0, 0, 0, &blend, ULW_ALPHA); } else { - SetWindowPos(hwndMarkerDragBox, 0, window_x, window_y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + SetWindowPos(hwndMarkerDragBox, 0, marker_drag_box_x, marker_drag_box_y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); } - // force dragging cursor icon - SetCursor(LoadCursor(0, IDC_ARROW)); - must_check_item_under_mouse = false; + SetLayeredWindowAttributes(hwndMarkerDragBox, 0, MARKER_DRAG_BOX_ALPHA, LWA_ALPHA); + UpdateLayeredWindow(hwndMarkerDragBox, 0, 0, 0, 0, 0, 0, &blend, ULW_ALPHA); break; } case DRAG_MODE_SET: @@ -478,7 +585,68 @@ void PIANO_ROLL::update() } break; } + case DRAG_MODE_SELECTION: + { + int new_drag_selection_ending_frame = row_under_mouse; + // if trying to select above Piano Roll, select from frame 0 + if (new_drag_selection_ending_frame < 0 && real_row_under_mouse < 0) + new_drag_selection_ending_frame = 0; + if (new_drag_selection_ending_frame >= 0 && new_drag_selection_ending_frame != drag_selection_ending_frame) + { + // change selection shape + if (new_drag_selection_ending_frame >= drag_selection_starting_frame) + { + // selecting from upper to lower + if (drag_selection_ending_frame < drag_selection_starting_frame) + { + selection.ClearRegionSelection(drag_selection_ending_frame, drag_selection_starting_frame); + selection.SetRegionSelection(drag_selection_starting_frame, new_drag_selection_ending_frame + 1); + } else // both ending_frame and new_ending_frame are >= starting_frame + { + if (drag_selection_ending_frame > new_drag_selection_ending_frame) + selection.ClearRegionSelection(new_drag_selection_ending_frame + 1, drag_selection_ending_frame + 1); + else + selection.SetRegionSelection(drag_selection_ending_frame + 1, new_drag_selection_ending_frame + 1); + } + } else + { + // selecting from lower to upper + if (drag_selection_ending_frame > drag_selection_starting_frame) + { + selection.ClearRegionSelection(drag_selection_starting_frame + 1, drag_selection_ending_frame + 1); + selection.SetRegionSelection(new_drag_selection_ending_frame, drag_selection_starting_frame); + } else // both ending_frame and new_ending_frame are <= starting_frame + { + if (drag_selection_ending_frame < new_drag_selection_ending_frame) + selection.ClearRegionSelection(drag_selection_ending_frame, new_drag_selection_ending_frame); + else + selection.SetRegionSelection(new_drag_selection_ending_frame, drag_selection_ending_frame); + } + } + drag_selection_ending_frame = new_drag_selection_ending_frame; + } + break; + } } + // update MarkerDragBox when it's flying away + if (hwndMarkerDragBox && drag_mode != DRAG_MODE_MARKER) + { + marker_drag_countdown--; + if (marker_drag_countdown > 0) + { + marker_drag_box_dy += MARKER_DRAG_GRAVITY; + marker_drag_box_x += marker_drag_box_dx; + marker_drag_box_y += marker_drag_box_dy; + SetWindowPos(hwndMarkerDragBox, 0, marker_drag_box_x, marker_drag_box_y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + SetLayeredWindowAttributes(hwndMarkerDragBox, 0, marker_drag_countdown * MARKER_DRAG_ALPHA_PER_TICK, LWA_ALPHA); + UpdateLayeredWindow(hwndMarkerDragBox, 0, 0, 0, 0, 0, 0, &blend, ULW_ALPHA); + } else + { + DestroyWindow(hwndMarkerDragBox); + hwndMarkerDragBox = 0; + } + } + // once per 40 milliseconds update colors alpha in the Header if (clock() > next_header_update_time) { @@ -486,9 +654,8 @@ void PIANO_ROLL::update() bool changes_made = false; int light_value = 0; // 1 - update Frame# columns' heads - if (GetAsyncKeyState(VK_MENU) & 0x8000) - light_value = HEADER_LIGHT_HOLD; - else if (drag_mode == DRAG_MODE_NONE && (header_item_under_mouse == COLUMN_FRAMENUM || header_item_under_mouse == COLUMN_FRAMENUM2)) + //if (GetAsyncKeyState(VK_MENU) & 0x8000) light_value = HEADER_LIGHT_HOLD; else + if (drag_mode == DRAG_MODE_NONE && (header_item_under_mouse == COLUMN_FRAMENUM || header_item_under_mouse == COLUMN_FRAMENUM2)) light_value = (selection.GetCurrentSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER; if (header_colors[COLUMN_FRAMENUM] < light_value) { @@ -525,55 +692,6 @@ void PIANO_ROLL::update() RedrawHeader(); } - // change mouse cursor depending on what it points at - if (must_check_item_under_mouse) - { - LPCSTR cursor_icon = IDC_ARROW; - switch (drag_mode) - { - case DRAG_MODE_NONE: - { - // normal mouseover - POINT p; - if (GetCursorPos(&p)) - { - ScreenToClient(hwndList, &p); - RECT wrect; - GetClientRect(hwndList, &wrect); - if (p.x >= 0 && p.y >= list_header_height && p.x < (wrect.right - wrect.left) && p.y < (wrect.bottom - wrect.top)) - { - // perform hit test - LVHITTESTINFO info; - info.pt.x = p.x; - info.pt.y = p.y; - ListView_SubItemHitTest(hwndList, &info); - int row_index = info.iItem; - int column_index = info.iSubItem; - if (row_index >= 0 - && (column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2) - && markers_manager.GetMarker(row_index)) - cursor_icon = IDC_SIZEALL; - } - } - break; - } - case DRAG_MODE_PLAYBACK: - { - // dragging Playback cursor - show either normal arrow or arrow+wait - if (playback.pause_frame) - cursor_icon = IDC_APPSTARTING; - break; - } - case DRAG_MODE_MARKER: - case DRAG_MODE_OBSERVE: - case DRAG_MODE_SET: - case DRAG_MODE_UNSET: - // show normal arrow - break; - } - SetCursor(LoadCursor(0, cursor_icon)); - must_check_item_under_mouse = false; - } } void PIANO_ROLL::save(EMUFILE *os, bool really_save) @@ -637,6 +755,14 @@ void PIANO_ROLL::RedrawHeader() } // ------------------------------------------------------------------------- +void PIANO_ROLL::UpdateItemCount() +{ + // update the number of items in the list + int currLVItemCount = ListView_GetItemCount(hwndList); + int movie_size = currMovieData.getNumRecords(); + if(currLVItemCount != movie_size) + ListView_SetItemCountEx(hwndList, movie_size, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL); +} bool PIANO_ROLL::CheckItemVisible(int frame) { int top = ListView_GetTopIndex(hwndList); @@ -726,6 +852,37 @@ void PIANO_ROLL::FollowMarker(int marker_id) } } +void PIANO_ROLL::ColumnSet(int column, bool alt_pressed) +{ + if (column == COLUMN_FRAMENUM || column == COLUMN_FRAMENUM2) + { + // user clicked on "Frame#" - apply ColumnSet to Markers + if (alt_pressed) + { + if (editor.FrameColumnSetPattern()) + SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); + } else + { + if (editor.FrameColumnSet()) + SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); + } + } else + { + // user clicked on Input column - apply ColumnSet to Input + int joy = (column - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS; + int button = (column - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS; + if (alt_pressed) + { + if (editor.InputColumnSetPattern(joy, button)) + SetHeaderColumnLight(column, HEADER_LIGHT_MAX); + } else + { + if (editor.InputColumnSet(joy, button)) + SetHeaderColumnLight(column, HEADER_LIGHT_MAX); + } + } +} + void PIANO_ROLL::SetHeaderColumnLight(int column, int level) { if (column < COLUMN_FRAMENUM || column >= num_columns || level < 0 || level > HEADER_LIGHT_MAX) @@ -749,31 +906,52 @@ void PIANO_ROLL::StartDraggingPlaybackCursor() DragPlaybackCursor(); } } +void PIANO_ROLL::StartDraggingMarker(int mouse_x, int mouse_y, int row_index, int column_index) +{ + if (drag_mode == DRAG_MODE_NONE) + { + // start dragging the Marker + drag_mode = DRAG_MODE_MARKER; + marker_drag_framenum = row_index; + marker_drag_countdown = MARKER_DRAG_COUNTDOWN_MAX; + RECT temp_rect; + if (ListView_GetSubItemRect(hwndList, row_index, column_index, LVIR_BOUNDS, &temp_rect)) + { + marker_drag_box_dx = mouse_x - temp_rect.left; + marker_drag_box_dy = mouse_y - temp_rect.top; + } else + { + marker_drag_box_dx = 0; + marker_drag_box_dy = 0; + } + // redraw the row to show that Marker was lifted + RedrawRow(row_index); + } +} +void PIANO_ROLL::StartSelectingDrag(int start_frame) +{ + if (drag_mode == DRAG_MODE_NONE) + { + drag_mode = DRAG_MODE_SELECTION; + drag_selection_starting_frame = start_frame; + drag_selection_ending_frame = drag_selection_starting_frame; // assuming that start_frame is already selected + } +} + void PIANO_ROLL::DragPlaybackCursor() { - POINT p; - if (GetCursorPos(&p)) + int target_frame = real_row_under_mouse; + if (target_frame < 0) + target_frame = 0; + if (currFrameCounter != target_frame) { - ScreenToClient(hwndList, &p); - // perform hit test - LVHITTESTINFO info; - info.pt.x = p.x; - info.pt.y = p.y; - ListView_SubItemHitTest(hwndList, &info); - int row_index = info.iItem; - if (row_index < 0) - row_index = ListView_GetTopIndex(hwndList) + (p.y - list_row_top) / list_row_height; - // send Playback there - if (currFrameCounter != row_index) + int lastCursor = currFrameCounter; + playback.jump(target_frame); + if (lastCursor != currFrameCounter) { - int lastCursor = currFrameCounter; - playback.jump(row_index); - if (lastCursor != currFrameCounter) - { - // redraw row where Playback cursor was (in case there's two or more drags before playback.update()) - RedrawRow(lastCursor); - bookmarks.RedrawChangedBookmarks(lastCursor); - } + // redraw row where Playback cursor was (in case there's two or more drags before playback.update()) + RedrawRow(lastCursor); + bookmarks.RedrawChangedBookmarks(lastCursor); } } } @@ -787,23 +965,43 @@ void PIANO_ROLL::FinishDrag() // place Marker here if (markers_manager.GetMarker(marker_drag_framenum)) { - POINT p; - if (GetCursorPos(&p)) + POINT p = {0, 0}; + GetCursorPos(&p); + int mouse_x = p.x, mouse_y = p.y; + ScreenToClient(hwndList, &p); + RECT wrect; + GetClientRect(hwndList, &wrect); + if (p.x < 0 || p.x > (wrect.right - wrect.left) || p.y < 0 || p.y > (wrect.bottom - wrect.top)) { - ScreenToClient(hwndList, &p); - // perform hit test - LVHITTESTINFO info; - info.pt.x = p.x; - info.pt.y = p.y; - ListView_SubItemHitTest(hwndList, &info); - int row_index = info.iItem; - int column_index = info.iSubItem; - if (row_index >= 0 && row_index != marker_drag_framenum && (column_index <= COLUMN_FRAMENUM || column_index >= COLUMN_FRAMENUM2)) + // user threw the Marker away + markers_manager.ClearMarker(marker_drag_framenum); + RedrawRow(marker_drag_framenum); + history.RegisterMarkersChange(MODTYPE_MARKER_REMOVE, marker_drag_framenum); + selection.must_find_current_marker = playback.must_find_current_marker = true; + // calculate vector of movement + POINT p = {0, 0}; + GetCursorPos(&p); + marker_drag_box_dx = (mouse_x - marker_drag_box_dx) - marker_drag_box_x; + marker_drag_box_dy = (mouse_y - marker_drag_box_dy) - marker_drag_box_y; + if (marker_drag_box_dx || marker_drag_box_dy) { - if (markers_manager.GetMarker(row_index)) + // limit max speed + double marker_drag_box_speed = sqrt((double)(marker_drag_box_dx * marker_drag_box_dx + marker_drag_box_dy * marker_drag_box_dy)); + if (marker_drag_box_speed > MARKER_DRAG_MAX_SPEED) + { + marker_drag_box_dx *= MARKER_DRAG_MAX_SPEED / marker_drag_box_speed; + marker_drag_box_dy *= MARKER_DRAG_MAX_SPEED / marker_drag_box_speed; + } + } + marker_drag_countdown = MARKER_DRAG_COUNTDOWN_MAX; + } else + { + if (row_under_mouse >= 0 && row_under_mouse != marker_drag_framenum && (column_under_mouse <= COLUMN_FRAMENUM || column_under_mouse >= COLUMN_FRAMENUM2)) + { + if (markers_manager.GetMarker(row_under_mouse)) { int dragged_marker_id = markers_manager.GetMarker(marker_drag_framenum); - int destination_marker_id = markers_manager.GetMarker(row_index); + int destination_marker_id = markers_manager.GetMarker(row_under_mouse); // swap Notes of these Markers char dragged_marker_note[MAX_NOTE_LEN]; strcpy(dragged_marker_note, markers_manager.GetNote(dragged_marker_id).c_str()); @@ -812,34 +1010,41 @@ void PIANO_ROLL::FinishDrag() // notes are different, swap them markers_manager.SetNote(dragged_marker_id, markers_manager.GetNote(destination_marker_id).c_str()); markers_manager.SetNote(destination_marker_id, dragged_marker_note); - history.RegisterMarkersChange(MODTYPE_MARKER_SWAP, marker_drag_framenum, row_index); + history.RegisterMarkersChange(MODTYPE_MARKER_SWAP, marker_drag_framenum, row_under_mouse); selection.must_find_current_marker = playback.must_find_current_marker = true; SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); } } else { // move Marker - int new_marker_id = markers_manager.SetMarker(row_index); + int new_marker_id = markers_manager.SetMarker(row_under_mouse); if (new_marker_id) { markers_manager.SetNote(new_marker_id, markers_manager.GetNote(markers_manager.GetMarker(marker_drag_framenum)).c_str()); // and delete it from old frame markers_manager.ClearMarker(marker_drag_framenum); - RedrawRow(marker_drag_framenum); - RedrawRow(row_index); - history.RegisterMarkersChange(MODTYPE_MARKER_DRAG, marker_drag_framenum, row_index, markers_manager.GetNote(markers_manager.GetMarker(row_index)).c_str()); + history.RegisterMarkersChange(MODTYPE_MARKER_DRAG, marker_drag_framenum, row_under_mouse, markers_manager.GetNote(markers_manager.GetMarker(row_under_mouse)).c_str()); selection.must_find_current_marker = playback.must_find_current_marker = true; SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); + RedrawRow(row_under_mouse); } } } + RedrawRow(marker_drag_framenum); + if (hwndMarkerDragBox) + { + DestroyWindow(hwndMarkerDragBox); + hwndMarkerDragBox = 0; + } } - } - - if (hwndMarkerDragBox) + } else { - DestroyWindow(hwndMarkerDragBox); - hwndMarkerDragBox = 0; + // abort drag + if (hwndMarkerDragBox) + { + DestroyWindow(hwndMarkerDragBox); + hwndMarkerDragBox = 0; + } } break; } @@ -848,12 +1053,6 @@ void PIANO_ROLL::FinishDrag() must_check_item_under_mouse = true; } -void PIANO_ROLL::AcceleratorDispatched() -{ - // hack for tapping Ctrl twice - if first was accelerator, then it won't count as first tap - vk_control_release_time = -1; -} - void PIANO_ROLL::GetDispInfo(NMLVDISPINFO* nmlvDispInfo) { LVITEM& item = nmlvDispInfo->item; @@ -945,7 +1144,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg) if (cell_y == history.GetUndoHint()) { // undo hint here - if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y)) + if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y) && (drag_mode != DRAG_MODE_MARKER || marker_drag_framenum != cell_y)) { msg->clrTextBk = (taseditor_config.bind_markers) ? BINDMARKED_UNDOHINT_FRAMENUM_COLOR : MARKED_UNDOHINT_FRAMENUM_COLOR; } else @@ -955,14 +1154,14 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg) } else if (cell_y == currFrameCounter || cell_y == (playback.GetFlashingPauseFrame() - 1)) { // current frame - if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y)) + if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y) && (drag_mode != DRAG_MODE_MARKER || marker_drag_framenum != cell_y)) { msg->clrTextBk = (taseditor_config.bind_markers) ? CUR_BINDMARKED_FRAMENUM_COLOR : CUR_MARKED_FRAMENUM_COLOR; } else { msg->clrTextBk = CUR_FRAMENUM_COLOR; } - } else if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y)) + } else if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y) && (drag_mode != DRAG_MODE_MARKER || marker_drag_framenum != cell_y)) { // marked frame msg->clrTextBk = (taseditor_config.bind_markers) ? BINDMARKED_FRAMENUM_COLOR : MARKED_FRAMENUM_COLOR; @@ -1095,266 +1294,14 @@ LONG PIANO_ROLL::HeaderCustomDraw(NMLVCUSTOMDRAW* msg) } } -void PIANO_ROLL::ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags) -{ - int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS; - int bit = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS; - if (KeyFlags & (MK_SHIFT|MK_CONTROL)) - { - // update multiple rows, using last row index as a flag to decide operation - SelectionFrames* current_selection = selection.MakeStrobe(); - SelectionFrames::iterator current_selection_end(current_selection->end()); - if (current_selection->size()) - { - if (currMovieData.records[row_index].checkBit(joy, bit)) - { - // clear range - for(SelectionFrames::iterator it(current_selection->begin()); it != current_selection_end; it++) - { - currMovieData.records[*it].clearBit(joy, bit); - } - greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, *current_selection->begin(), *current_selection->rbegin())); - } else - { - // set range - for(SelectionFrames::iterator it(current_selection->begin()); it != current_selection_end; it++) - { - currMovieData.records[*it].setBit(joy, bit); - } - greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, *current_selection->begin(), *current_selection->rbegin())); - } - } - } else - { - // update one row - currMovieData.records[row_index].toggleBit(joy, bit); - if (currMovieData.records[row_index].checkBit(joy, bit)) - greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, row_index, row_index)); - else - greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, row_index, row_index)); - } - -} - -void PIANO_ROLL::ColumnSet(int column, bool alt_pressed) -{ - if (column == COLUMN_FRAMENUM || column == COLUMN_FRAMENUM2) - { - // user clicked on "Frame#" - apply ColumnSet to Markers - if (alt_pressed) - { - if (FrameColumnSetPattern()) - SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); - } else - { - if (FrameColumnSet()) - SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); - } - } else - { - // user clicked on Input column - apply ColumnSet to Input - int joy = (column - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS; - int button = (column - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS; - if (alt_pressed) - { - if (InputColumnSetPattern(joy, button)) - SetHeaderColumnLight(column, HEADER_LIGHT_MAX); - } else - { - if (InputColumnSet(joy, button)) - SetHeaderColumnLight(column, HEADER_LIGHT_MAX); - } - } -} - -bool PIANO_ROLL::FrameColumnSetPattern() -{ - SelectionFrames* current_selection = selection.MakeStrobe(); - if (current_selection->size() == 0) return false; - SelectionFrames::iterator current_selection_begin(current_selection->begin()); - SelectionFrames::iterator current_selection_end(current_selection->end()); - int pattern_offset = 0, current_pattern = taseditor_config.current_pattern; - bool changes_made = false; - - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - { - // skip lag frames - if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(*it)) - continue; - if (autofire_patterns[current_pattern][pattern_offset]) - { - if(!markers_manager.GetMarker(*it)) - { - if (markers_manager.SetMarker(*it)) - { - changes_made = true; - RedrawRow(*it); - } - } - } else - { - if(markers_manager.GetMarker(*it)) - { - markers_manager.ClearMarker(*it); - changes_made = true; - RedrawRow(*it); - } - } - pattern_offset++; - if (pattern_offset >= (int)autofire_patterns[current_pattern].size()) - pattern_offset -= autofire_patterns[current_pattern].size(); - } - if (changes_made) - { - history.RegisterMarkersChange(MODTYPE_MARKER_PATTERN, *current_selection_begin, *current_selection->rbegin(), autofire_patterns_names[current_pattern].c_str()); - selection.must_find_current_marker = playback.must_find_current_marker = true; - return true; - } else - return false; -} -bool PIANO_ROLL::FrameColumnSet() -{ - SelectionFrames* current_selection = selection.MakeStrobe(); - if (current_selection->size() == 0) return false; - SelectionFrames::iterator current_selection_begin(current_selection->begin()); - SelectionFrames::iterator current_selection_end(current_selection->end()); - - // inspect the selected frames, if they are all set, then unset all, else set all - bool unset_found = false, changes_made = false; - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - { - if(!markers_manager.GetMarker(*it)) - { - unset_found = true; - break; - } - } - if (unset_found) - { - // set all - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - { - if(!markers_manager.GetMarker(*it)) - { - if (markers_manager.SetMarker(*it)) - { - changes_made = true; - RedrawRow(*it); - } - } - } - if (changes_made) - history.RegisterMarkersChange(MODTYPE_MARKER_SET, *current_selection_begin, *current_selection->rbegin()); - } else - { - // unset all - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - { - if(markers_manager.GetMarker(*it)) - { - markers_manager.ClearMarker(*it); - changes_made = true; - RedrawRow(*it); - } - } - if (changes_made) - history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, *current_selection_begin, *current_selection->rbegin()); - } - if (changes_made) - selection.must_find_current_marker = playback.must_find_current_marker = true; - return changes_made; -} -bool PIANO_ROLL::InputColumnSetPattern(int joy, int button) -{ - if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return false; - - SelectionFrames* current_selection = selection.MakeStrobe(); - if (current_selection->size() == 0) return false; - SelectionFrames::iterator current_selection_begin(current_selection->begin()); - SelectionFrames::iterator current_selection_end(current_selection->end()); - int pattern_offset = 0, current_pattern = taseditor_config.current_pattern; - - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - { - // skip lag frames - if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(*it)) - continue; - currMovieData.records[*it].setBitValue(joy, button, autofire_patterns[current_pattern][pattern_offset] != 0); - pattern_offset++; - if (pattern_offset >= (int)autofire_patterns[current_pattern].size()) - pattern_offset -= autofire_patterns[current_pattern].size(); - } - int first_changes = history.RegisterChanges(MODTYPE_PATTERN, *current_selection_begin, *current_selection->rbegin(), autofire_patterns_names[current_pattern].c_str()); - if (first_changes >= 0) - { - greenzone.InvalidateAndCheck(first_changes); - return true; - } else - return false; -} -bool PIANO_ROLL::InputColumnSet(int joy, int button) -{ - if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return false; - - SelectionFrames* current_selection = selection.MakeStrobe(); - if (current_selection->size() == 0) return false; - SelectionFrames::iterator current_selection_begin(current_selection->begin()); - SelectionFrames::iterator current_selection_end(current_selection->end()); - - //inspect the selected frames, if they are all set, then unset all, else set all - bool newValue = false; - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - { - if(!(currMovieData.records[*it].checkBit(joy,button))) - { - newValue = true; - break; - } - } - // apply newValue - for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++) - currMovieData.records[*it].setBitValue(joy,button,newValue); - - int first_changes; - if (newValue) - { - first_changes = history.RegisterChanges(MODTYPE_SET, *current_selection_begin, *current_selection->rbegin()); - } else - { - first_changes = history.RegisterChanges(MODTYPE_UNSET, *current_selection_begin, *current_selection->rbegin()); - } - if (first_changes >= 0) - { - greenzone.InvalidateAndCheck(first_changes); - return true; - } else - return false; -} // ---------------------------------------------------- void PIANO_ROLL::RightClick(LVHITTESTINFO& info) -{ - int index = info.iItem; - if(index == -1) - StrayClickMenu(info); - else - RightClickMenu(info); -} -void PIANO_ROLL::StrayClickMenu(LVHITTESTINFO& info) -{ - POINT pt = info.pt; - ClientToScreen(hwndList, &pt); - HMENU sub = GetSubMenu(hrmenu, CONTEXTMENU_STRAY); - TrackPopupMenu(sub, 0, pt.x, pt.y, 0, taseditor_window.hwndTasEditor, 0); -} -void PIANO_ROLL::RightClickMenu(LVHITTESTINFO& info) { SelectionFrames* current_selection = selection.MakeStrobe(); if (current_selection->size() == 0) - { - StrayClickMenu(info); return; - } - HMENU sub = GetSubMenu(hrmenu, CONTEXTMENU_SELECTED); + + HMENU sub = GetSubMenu(hrmenu, 0); // inspect current selection and disable inappropriate menu items SelectionFrames::iterator current_selection_begin(current_selection->begin()); SelectionFrames::iterator current_selection_end(current_selection->end()); @@ -1391,7 +1338,7 @@ LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam return true; case WM_MOUSEMOVE: { - // perform hit test + // perform hit test on header items HD_HITTESTINFO info; info.pt.x = GET_X_LPARAM(lParam) + HEADER_DX_FIX; info.pt.y = GET_Y_LPARAM(lParam); @@ -1411,7 +1358,7 @@ LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam { if (selection.GetCurrentSelectionSize()) { - // perform hit test + // perform hit test on header items HD_HITTESTINFO info; info.pt.x = GET_X_LPARAM(lParam) + HEADER_DX_FIX; info.pt.y = GET_Y_LPARAM(lParam); @@ -1462,63 +1409,16 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) } break; } - case WM_KEYUP: - { - if (wParam == VK_SHIFT) - { - if (piano_roll.vk_shift_release_time >= 0) - piano_roll.vk_shift_release_time = clock(); - else // this was accelerator - piano_roll.vk_shift_release_time = 0; - } else if (wParam == VK_CONTROL) - { - if (piano_roll.vk_control_release_time >= 0) - piano_roll.vk_control_release_time = clock(); - else // this was accelerator - piano_roll.vk_control_release_time = 0; - } - break; - } case WM_KEYDOWN: - { - if (wParam == VK_SHIFT) - { - // double-tap of Shift key - if ((int)(piano_roll.vk_shift_release_time + GetDoubleClickTime()) > clock()) - piano_roll.FollowPlayback(); - } else if (wParam == VK_CONTROL) - { - // double-tap of Ctrl key - if ((int)(piano_roll.vk_control_release_time + GetDoubleClickTime()) > clock()) - piano_roll.FollowSelection(); - } - if (taseditor_config.keyboard_for_piano_roll) - { - // only allow 8 keys, and change behaviour of Right and Left keys - if (wParam == VK_LEFT) - { - // faster speed of horizontal scrolling, and don't scroll vertically to the selection - ListView_Scroll(piano_roll.hwndList, -COLUMN_BUTTON_WIDTH, 0); - } else if (wParam == VK_RIGHT) - { - ListView_Scroll(piano_roll.hwndList, COLUMN_BUTTON_WIDTH, 0); - } else if (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_END || wParam == VK_HOME || wParam == VK_PRIOR || wParam == VK_NEXT) - { - // these 6 keys will be handled by hwndList_oldWndProc - piano_roll.must_check_item_under_mouse = true; - break; - } - } return 0; - } case WM_TIMER: // disable timer of entering edit mode (there's no edit mode anyway) return 0; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: { - bool alt_pressed = (GetKeyState(VK_MENU) < 0); int fwKeys = GET_KEYSTATE_WPARAM(wParam); + bool alt_pressed = (GetKeyState(VK_MENU) < 0); // perform hit test LVHITTESTINFO info; info.pt.x = GET_X_LPARAM(lParam); @@ -1526,100 +1426,94 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) ListView_SubItemHitTest(hWnd, &info); int row_index = info.iItem; int column_index = info.iSubItem; - if(column_index == COLUMN_ICONS) + if (column_index == COLUMN_ICONS) { - // click on the "icons" column + // clicked on the "icons" column piano_roll.StartDraggingPlaybackCursor(); } else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2) { // clicked on the "Frame#" column - if (msg == WM_LBUTTONDBLCLK && !alt_pressed) - { - // doubleclick - jump to the frame - if (taseditor_config.deselect_on_doubleclick) - selection.ClearSelection(); - if (taseditor_config.doubleclick_affects_playback) - piano_roll.StartDraggingPlaybackCursor(); - } else - { - if (row_index >= 0) - { - // set marker if clicked with Alt - if (alt_pressed) - { - markers_manager.ToggleMarker(row_index); - selection.must_find_current_marker = playback.must_find_current_marker = true; - if (markers_manager.GetMarker(row_index)) - history.RegisterMarkersChange(MODTYPE_MARKER_SET, row_index); - else - history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, row_index); - piano_roll.RedrawRow(row_index); - } else if (piano_roll.drag_mode == DRAG_MODE_NONE) - { - // check if user clicked on a Marker - if (markers_manager.GetMarker(row_index)) - { - // start dragging the Marker - RECT temp_rect; - if (ListView_GetSubItemRect(piano_roll.hwndList, row_index, column_index, LVIR_BOUNDS, &temp_rect)) - { - piano_roll.marker_drag_box_dx = GET_X_LPARAM(lParam) - temp_rect.left; - piano_roll.marker_drag_box_dy = GET_Y_LPARAM(lParam) - temp_rect.top; - } else - { - piano_roll.marker_drag_box_dx = 0; - piano_roll.marker_drag_box_dy = 0; - } - piano_roll.drag_mode = DRAG_MODE_MARKER; - piano_roll.marker_drag_framenum = row_index; - } else - { - piano_roll.drag_mode = DRAG_MODE_OBSERVE; - } - } - // also select the row by calling hwndList_oldWndProc - PostMessage(hWnd, WM_LBUTTONUP, 0, 0); // ensure that oldWndProc will exit its modal message loop immediately - CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam); - } - } - } else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R) - { - // clicked on input if (row_index >= 0) { - // first call old wndproc to set selection on the row - if (alt_pressed) - wParam |= MK_SHIFT; // Alt should select region, just like Shift - if (msg == WM_LBUTTONDOWN) - PostMessage(hWnd, WM_LBUTTONUP, 0, 0); // ensure that oldWndProc will exit its modal message loop immediately - CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam); - if (alt_pressed) + if (msg == WM_LBUTTONDBLCLK) { - int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS; - int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS; - piano_roll.InputColumnSetPattern(joy, button); - } else - { - piano_roll.ToggleJoypadBit(column_index, row_index, GET_KEYSTATE_WPARAM(wParam)); - if (piano_roll.drag_mode == DRAG_MODE_NONE) + // doubleclick - set Marker and start dragging it + if (!markers_manager.GetMarker(row_index)) { - if (taseditor_config.draw_input) + if (markers_manager.SetMarker(row_index)) { - // if clicked on empty cell - start drawing, else start erasing - int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS; - int bit = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS; - if (currMovieData.records[row_index].checkBit(joy, bit)) - piano_roll.drag_mode = DRAG_MODE_SET; - else - piano_roll.drag_mode = DRAG_MODE_UNSET; - piano_roll.drawing_last_x = GET_X_LPARAM(lParam) + GetScrollPos(piano_roll.hwndList, SB_HORZ); - piano_roll.drawing_last_y = GET_Y_LPARAM(lParam) + GetScrollPos(piano_roll.hwndList, SB_VERT) * piano_roll.list_row_height; - } else - { - piano_roll.drag_mode = DRAG_MODE_OBSERVE; + selection.must_find_current_marker = playback.must_find_current_marker = true; + history.RegisterMarkersChange(MODTYPE_MARKER_SET, row_index); + piano_roll.RedrawRow(row_index); } } - + piano_roll.StartDraggingMarker(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), row_index, column_index); + // also clear selection + if (taseditor_config.deselect_on_doubleclick) + selection.ClearSelection(); + } else + { + if (fwKeys & MK_SHIFT) + { + // select region from row_last_clicked to row_index + if (piano_roll.row_last_clicked < row_index) + selection.SetRegionSelection(piano_roll.row_last_clicked, row_index + 1); + else + selection.SetRegionSelection(row_index, piano_roll.row_last_clicked + 1); + } else if (alt_pressed) + { + // make selection by Pattern + if (piano_roll.row_last_clicked < row_index) + selection.SetRegionSelectionPattern(piano_roll.row_last_clicked, row_index); + else + selection.SetRegionSelectionPattern(row_index, piano_roll.row_last_clicked); + } else if (fwKeys & MK_CONTROL) + { + if (selection.GetRowSelection(row_index)) + selection.ClearRowSelection(row_index); + else + selection.SetRowSelection(row_index); + piano_roll.row_last_clicked = row_index; + } else // just click + { + selection.ClearSelection(); + selection.SetRowSelection(row_index); + piano_roll.row_last_clicked = row_index; + } + piano_roll.StartSelectingDrag(row_index); + } + } + } else if (column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R) + { + // clicked on Input + if (row_index >= 0) + { + if (!alt_pressed && !(fwKeys & MK_SHIFT)) + // clicked without Shift/Alt - set "row_last_clicked" here + piano_roll.row_last_clicked = row_index; + // toggle input + int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS; + int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS; + if (alt_pressed) + editor.InputSetPattern(piano_roll.row_last_clicked, row_index, joy, button); + else + editor.InputToggle(piano_roll.row_last_clicked, row_index, joy, button); + // and start dragging/drawing + if (piano_roll.drag_mode == DRAG_MODE_NONE) + { + if (taseditor_config.draw_input) + { + // if clicked this click created buttonpress, then start painting, else start erasing + if (currMovieData.records[row_index].checkBit(joy, button)) + piano_roll.drag_mode = DRAG_MODE_SET; + else + piano_roll.drag_mode = DRAG_MODE_UNSET; + piano_roll.drawing_last_x = GET_X_LPARAM(lParam) + GetScrollPos(piano_roll.hwndList, SB_HORZ); + piano_roll.drawing_last_y = GET_Y_LPARAM(lParam) + GetScrollPos(piano_roll.hwndList, SB_VERT) * piano_roll.list_row_height; + } else + { + piano_roll.drag_mode = DRAG_MODE_OBSERVE; + } } } } diff --git a/src/drivers/win/taseditor/piano_roll.h b/src/drivers/win/taseditor/piano_roll.h index c1b2bf32..42e8a439 100644 --- a/src/drivers/win/taseditor/piano_roll.h +++ b/src/drivers/win/taseditor/piano_roll.h @@ -21,10 +21,17 @@ #define BOOST_WHEN_BOTH_RIGHTBUTTON_AND_ALT_PRESSED 4 #define MARKER_DRAG_BOX_ALPHA 175 +#define MARKER_DRAG_COUNTDOWN_MAX 14 +#define MARKER_DRAG_ALPHA_PER_TICK 13 +#define MARKER_DRAG_MAX_SPEED 70 +#define MARKER_DRAG_GRAVITY 2 + #define DRAWING_MIN_LINE_LEN 14 // = min(list_row_width, list_row_height) in pixels -#define SCROLLING_BORDER_SIZE 8 // in pixels +#define DRAG_SCROLLING_BORDER_SIZE 10 // in pixels +#define DOUBLETAP_COUNT 3 // 1:quick press, 2 - quick release, 3 - quick press +#define ROW_LAST_CLICKED_BLINKING_PERIOD 200 enum { @@ -75,6 +82,7 @@ enum DRAG_MODES DRAG_MODE_MARKER, DRAG_MODE_SET, DRAG_MODE_UNSET, + DRAG_MODE_SELECTION, }; // when there's too many button columns, there's need for 2nd Frame# column at the end @@ -145,6 +153,7 @@ public: void RedrawRow(int index); void RedrawHeader(); + void UpdateItemCount(); bool CheckItemVisible(int frame); void FollowPlayback(); @@ -154,43 +163,46 @@ public: void FollowPauseframe(); void FollowMarker(int marker_id); + void ColumnSet(int column, bool alt_pressed); + void SetHeaderColumnLight(int column, int level); void StartDraggingPlaybackCursor(); - - void AcceleratorDispatched(); + void StartDraggingMarker(int mouse_x, int mouse_y, int row_index, int column_index); + void StartSelectingDrag(int start_frame); void GetDispInfo(NMLVDISPINFO* nmlvDispInfo); LONG CustomDraw(NMLVCUSTOMDRAW* msg); LONG HeaderCustomDraw(NMLVCUSTOMDRAW* msg); void RightClick(LVHITTESTINFO& info); - void StrayClickMenu(LVHITTESTINFO& info); - void RightClickMenu(LVHITTESTINFO& info); - - void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags); - void ColumnSet(int column, bool alt_pressed); - bool FrameColumnSetPattern(); - bool FrameColumnSet(); - bool InputColumnSetPattern(int joy, int button); - bool InputColumnSet(int joy, int button); int header_item_under_mouse; HWND hwndList, hwndHeader; TRACKMOUSEEVENT tme; int list_row_top, list_row_height, list_header_height; + + bool must_check_item_under_mouse; + int row_under_mouse, real_row_under_mouse, column_under_mouse; + unsigned int drag_mode; bool rbutton_drag_mode; bool can_drag_when_seeking; int marker_drag_box_dx, marker_drag_box_dy; + int marker_drag_box_x, marker_drag_box_y; + int marker_drag_countdown; int marker_drag_framenum; int drawing_last_x, drawing_last_y; + int drag_selection_starting_frame; + int drag_selection_ending_frame; - bool must_check_item_under_mouse; + int row_last_clicked; + int row_last_clicked_blinking_phase_shift; - int vk_shift_release_time; - int vk_control_release_time; + bool shift_held, ctrl_held, alt_held; + int shift_timer, ctrl_timer; + int shift_count, ctrl_count; HWND hwndMarkerDragBox, hwndMarkerDragBoxText; // GDI stuff diff --git a/src/drivers/win/taseditor/recorder.cpp b/src/drivers/win/taseditor/recorder.cpp index 94229585..31ad46b9 100644 --- a/src/drivers/win/taseditor/recorder.cpp +++ b/src/drivers/win/taseditor/recorder.cpp @@ -23,7 +23,6 @@ extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES]; extern uint32 GetGamepadPressedImmediate(); extern int GetInputType(MovieData& md); -extern std::vector> autofire_patterns; extern char lagFlag; extern TASEDITOR_CONFIG taseditor_config; @@ -32,6 +31,7 @@ extern BOOKMARKS bookmarks; extern HISTORY history; extern GREENZONE greenzone; extern PIANO_ROLL piano_roll; +extern EDITOR editor; // resources const char recordingCheckbox[10] = "Recording"; @@ -132,8 +132,8 @@ void RECORDER::update() if (!taseditor_config.pattern_skips_lag || lagFlag == 0) { pattern_offset++; - if (pattern_offset >= (int)autofire_patterns[old_current_pattern].size()) - pattern_offset -= autofire_patterns[old_current_pattern].size(); + if (pattern_offset >= (int)editor.autofire_patterns[old_current_pattern].size()) + pattern_offset -= editor.autofire_patterns[old_current_pattern].size(); } } // update "Recording" checkbox text if something changed in pattern @@ -141,7 +141,7 @@ void RECORDER::update() { old_current_pattern = taseditor_config.current_pattern; old_pattern_offset = pattern_offset; - if (!taseditor_config.pattern_recording || autofire_patterns[old_current_pattern][pattern_offset]) + if (!taseditor_config.pattern_recording || editor.autofire_patterns[old_current_pattern][pattern_offset]) // either not using Patterns or current pattern has 1 in current offset SetWindowText(hwndRecCheckbox, recordingCheckbox); else @@ -238,7 +238,7 @@ void RECORDER::InputChanged() for (int i = 0; i < num_joys; ++i) { old_joy[i] = history.GetCurrentSnapshot().GetJoystickInfo(currFrameCounter, i); - if (!taseditor_config.pattern_recording || autofire_patterns[old_current_pattern][pattern_offset]) + if (!taseditor_config.pattern_recording || editor.autofire_patterns[old_current_pattern][pattern_offset]) new_joy[i] = currMovieData.records[currFrameCounter].joysticks[i]; else new_joy[i] = 0; // blank diff --git a/src/drivers/win/taseditor/selection.cpp b/src/drivers/win/taseditor/selection.cpp index 68f164a4..bf2341b6 100644 --- a/src/drivers/win/taseditor/selection.cpp +++ b/src/drivers/win/taseditor/selection.cpp @@ -29,6 +29,8 @@ extern TASEDITOR_WINDOW taseditor_window; extern MARKERS_MANAGER markers_manager; extern PIANO_ROLL piano_roll; extern SPLICER splicer; +extern EDITOR editor; +extern GREENZONE greenzone; extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES]; @@ -441,39 +443,59 @@ void SELECTION::redo() jump(history_cursor_pos + 1); } // ---------------------------------------------------------- +bool SELECTION::GetRowSelection(int index) +{ + return ListView_GetItemState(piano_roll.hwndList, index, LVIS_SELECTED) != 0; +} + void SELECTION::ClearSelection() { - ListView_SetItemState(piano_roll.hwndList, -1, 0, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, -1, 0, LVIS_SELECTED); } void SELECTION::ClearRowSelection(int index) { - ListView_SetItemState(piano_roll.hwndList, index, 0, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, index, 0, LVIS_SELECTED); +} +void SELECTION::ClearRegionSelection(int start, int end) +{ + for (int i = start; i < end; ++i) + ListView_SetItemState(piano_roll.hwndList, i, 0, LVIS_SELECTED); } -void SELECTION::EnforceSelectionToList() -{ - track_selection_changes = false; - ClearSelection(); - for(SelectionFrames::reverse_iterator it(CurrentSelection().rbegin()); it != CurrentSelection().rend(); it++) - { - ListView_SetItemState(piano_roll.hwndList, *it, LVIS_SELECTED, LVIS_SELECTED); - } - track_selection_changes = true; -} - void SELECTION::SelectAll() { // select all, but remove "focused" from all - ListView_SetItemState(piano_roll.hwndList, -1, LVIS_FOCUSED|LVIS_SELECTED, LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, -1, LVIS_SELECTED, LVIS_SELECTED); } void SELECTION::SetRowSelection(int index) { - ListView_SetItemState(piano_roll.hwndList, index, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, index, LVIS_SELECTED, LVIS_SELECTED); } void SELECTION::SetRegionSelection(int start, int end) { for (int i = start; i < end; ++i) - ListView_SetItemState(piano_roll.hwndList, i, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); +} + +void SELECTION::SetRegionSelectionPattern(int start, int end) +{ + int pattern_offset = 0, current_pattern = taseditor_config.current_pattern; + for (int i = start; i <= end; ++i) + { + // skip lag frames + if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(i)) + continue; + if (editor.autofire_patterns[current_pattern][pattern_offset]) + { + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); + } else + { + ListView_SetItemState(piano_roll.hwndList, i, 0, LVIS_SELECTED); + } + pattern_offset++; + if (pattern_offset >= (int)editor.autofire_patterns[current_pattern].size()) + pattern_offset -= editor.autofire_patterns[current_pattern].size(); + } } void SELECTION::SelectBetweenMarkers() { @@ -511,7 +533,7 @@ void SELECTION::SelectBetweenMarkers() // default: select all between markers for (int i = upper_marker+1; i < lower_marker; ++i) { - ListView_SetItemState(piano_roll.hwndList, i, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); } } else if (upper_border == upper_marker+1 && lower_border == lower_marker-1) { @@ -520,14 +542,14 @@ void SELECTION::SelectBetweenMarkers() if (lower_marker >= movie_size) lower_marker = movie_size - 1; for (int i = upper_marker; i <= lower_marker; ++i) { - ListView_SetItemState(piano_roll.hwndList, i, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); } } else if (upper_border <= upper_marker && lower_border >= lower_marker) { // selected all between markers and both markers selected too - now deselect lower marker for (int i = upper_marker; i < lower_marker; ++i) { - ListView_SetItemState(piano_roll.hwndList, i, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); } } else if (upper_border == upper_marker && lower_border == lower_marker-1) { @@ -535,14 +557,14 @@ void SELECTION::SelectBetweenMarkers() if (lower_marker >= movie_size) lower_marker = movie_size - 1; for (int i = upper_marker+1; i <= lower_marker; ++i) { - ListView_SetItemState(piano_roll.hwndList, i, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); } } else if (upper_border == upper_marker+1 && lower_border == lower_marker) { // selected all between markers and lower marker selected too - now deselect lower marker (return to "selected all between markers") for (int i = upper_marker + 1; i < lower_marker; ++i) { - ListView_SetItemState(piano_roll.hwndList, i, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED); + ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED); } } } @@ -558,6 +580,48 @@ void SELECTION::ReselectClipboard() update(); } +void SELECTION::Transpose(int shift) +{ + if (!shift) return; + SelectionFrames* current_selection = MakeStrobe(); + if (current_selection->size()) + { + ClearSelection(); + int pos; + if (shift > 0) + { + int movie_size = currMovieData.getNumRecords(); + SelectionFrames::reverse_iterator current_selection_rend(current_selection->rend()); + for(SelectionFrames::reverse_iterator it(current_selection->rbegin()); it != current_selection_rend; it++) + { + pos = (*it) + shift; + if (pos < movie_size) + ListView_SetItemState(piano_roll.hwndList, pos, LVIS_SELECTED, LVIS_SELECTED); + } + } else + { + SelectionFrames::iterator current_selection_end(current_selection->end()); + for(SelectionFrames::iterator it(current_selection->begin()); it != current_selection_end; it++) + { + pos = (*it) + shift; + if (pos >= 0) + ListView_SetItemState(piano_roll.hwndList, pos, LVIS_SELECTED, LVIS_SELECTED); + } + } + } +} + +void SELECTION::EnforceSelectionToList() +{ + track_selection_changes = false; + ClearSelection(); + for(SelectionFrames::reverse_iterator it(CurrentSelection().rbegin()); it != CurrentSelection().rend(); it++) + { + ListView_SetItemState(piano_roll.hwndList, *it, LVIS_SELECTED, LVIS_SELECTED); + } + track_selection_changes = true; +} + // getters int SELECTION::GetCurrentSelectionSize() { @@ -570,6 +634,13 @@ int SELECTION::GetCurrentSelectionBeginning() else return -1; } +int SELECTION::GetCurrentSelectionEnd() +{ + if (selections_history[(history_start_pos + history_cursor_pos) % history_size].size()) + return *selections_history[(history_start_pos + history_cursor_pos) % history_size].rbegin(); + else + return -1; +} bool SELECTION::CheckFrameSelected(int frame) { if(CurrentSelection().find(frame) == CurrentSelection().end()) diff --git a/src/drivers/win/taseditor/selection.h b/src/drivers/win/taseditor/selection.h index 1479ee9c..1d5c9017 100644 --- a/src/drivers/win/taseditor/selection.h +++ b/src/drivers/win/taseditor/selection.h @@ -33,17 +33,24 @@ public: void undo(); void redo(); + bool GetRowSelection(int index); + void ClearSelection(); void ClearRowSelection(int index); - - void EnforceSelectionToList(); + void ClearRegionSelection(int start, int end); void SelectAll(); void SetRowSelection(int index); void SetRegionSelection(int start, int end); + + void SetRegionSelectionPattern(int start, int end); void SelectBetweenMarkers(); void ReselectClipboard(); + void Transpose(int shift); + + void EnforceSelectionToList(); + void JumpPrevMarker(int speed = 1); void JumpNextMarker(int speed = 1); void JumpToFrame(int frame); @@ -51,6 +58,7 @@ public: // getters int GetCurrentSelectionSize(); int GetCurrentSelectionBeginning(); + int GetCurrentSelectionEnd(); bool CheckFrameSelected(int frame); SelectionFrames* MakeStrobe(); SelectionFrames& GetStrobedSelection(); diff --git a/src/drivers/win/taseditor/splicer.cpp b/src/drivers/win/taseditor/splicer.cpp index 4ad530d4..89447e81 100644 --- a/src/drivers/win/taseditor/splicer.cpp +++ b/src/drivers/win/taseditor/splicer.cpp @@ -226,7 +226,7 @@ void SPLICER::InsertNumFrames() if (current_selection->size()) { // shift selection down, so that same frames are selected - piano_roll.update(); + piano_roll.UpdateItemCount(); selection.ClearSelection(); SelectionFrames::iterator current_selection_end = current_selection->end(); for(SelectionFrames::iterator it(current_selection->begin()); it != current_selection_end; it++) @@ -273,7 +273,7 @@ void SPLICER::DeleteFrames() if (!currMovieData.getNumRecords()) playback.StartFromZero(); // reduce Piano Roll - piano_roll.update(); + piano_roll.UpdateItemCount(); // check and register changes int result = history.RegisterChanges(MODTYPE_DELETE, start_index); if (result >= 0) @@ -331,7 +331,7 @@ void SPLICER::Truncate() selection.must_find_current_marker = playback.must_find_current_marker = true; } } - piano_roll.update(); + piano_roll.UpdateItemCount(); int result = history.RegisterChanges(MODTYPE_TRUNCATE, frame+1); if (result >= 0) { @@ -344,7 +344,7 @@ void SPLICER::Truncate() else piano_roll.RedrawList(); if (markers_changed) - history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, frame+1, last_frame_was); + history.RegisterMarkersChange(MODTYPE_MARKER_REMOVE, frame+1, last_frame_was); } } } diff --git a/src/drivers/win/taseditor/taseditor_config.cpp b/src/drivers/win/taseditor/taseditor_config.cpp index 7717b815..cfb3ee72 100644 --- a/src/drivers/win/taseditor/taseditor_config.cpp +++ b/src/drivers/win/taseditor/taseditor_config.cpp @@ -47,7 +47,6 @@ TASEDITOR_CONFIG::TASEDITOR_CONFIG() combine_consecutive_rec = true; use_1p_rec = true; columnset_by_keys = false; - keyboard_for_piano_roll = true; superimpose = 0; // SUPERIMPOSE_UNCHECKED superimpose_affects_paste = true; branch_full_movie = true; @@ -71,7 +70,6 @@ TASEDITOR_CONFIG::TASEDITOR_CONFIG() findnote_search_up = false; enable_auto_function = true; deselect_on_doubleclick = true; - doubleclick_affects_playback = false; draw_input = true; silent_autosave = true; tooltips = true; diff --git a/src/drivers/win/taseditor/taseditor_config.h b/src/drivers/win/taseditor/taseditor_config.h index 3fe8b795..8958c50b 100644 --- a/src/drivers/win/taseditor/taseditor_config.h +++ b/src/drivers/win/taseditor/taseditor_config.h @@ -45,7 +45,6 @@ public: bool combine_consecutive_rec; bool use_1p_rec; bool columnset_by_keys; - bool keyboard_for_piano_roll; int superimpose; bool superimpose_affects_paste; bool branch_full_movie; @@ -69,7 +68,6 @@ public: bool findnote_search_up; bool enable_auto_function; bool deselect_on_doubleclick; - bool doubleclick_affects_playback; bool draw_input; bool silent_autosave; bool tooltips; diff --git a/src/drivers/win/taseditor/taseditor_lua.cpp b/src/drivers/win/taseditor/taseditor_lua.cpp index 0e11ef39..523d90e3 100644 --- a/src/drivers/win/taseditor/taseditor_lua.cpp +++ b/src/drivers/win/taseditor/taseditor_lua.cpp @@ -142,8 +142,8 @@ int TASEDITOR_LUA::setmarker(int frame) return -1; } -// taseditor.clearmarker(int frame) -void TASEDITOR_LUA::clearmarker(int frame) +// taseditor.removemarker(int frame) +void TASEDITOR_LUA::removemarker(int frame) { if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { @@ -151,7 +151,7 @@ void TASEDITOR_LUA::clearmarker(int frame) { markers_manager.ClearMarker(frame); // marker was deleted - register changes in TAS Editor - history.RegisterMarkersChange(MODTYPE_LUA_MARKER_UNSET, frame); + history.RegisterMarkersChange(MODTYPE_LUA_MARKER_REMOVE, frame); selection.must_find_current_marker = playback.must_find_current_marker = true; piano_roll.RedrawRow(frame); piano_roll.SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX); @@ -429,7 +429,7 @@ int TASEDITOR_LUA::applyinputchanges(const char* name) if (!currMovieData.getNumRecords()) playback.StartFromZero(); // reduce Piano Roll - piano_roll.update(); + piano_roll.UpdateItemCount(); // check actual changes int result = history.RegisterLuaChanges(name, start_index, InsertionDeletion_was_made); if (result >= 0) diff --git a/src/drivers/win/taseditor/taseditor_lua.h b/src/drivers/win/taseditor/taseditor_lua.h index 9ee2b240..b45b80b2 100644 --- a/src/drivers/win/taseditor/taseditor_lua.h +++ b/src/drivers/win/taseditor/taseditor_lua.h @@ -44,7 +44,7 @@ public: bool markedframe(int frame); int getmarker(int frame); int setmarker(int frame); - void clearmarker(int frame); + void removemarker(int frame); const char* getnote(int index); void setnote(int index, const char* newtext); int getcurrentbranch(); diff --git a/src/drivers/win/taseditor/taseditor_project.h b/src/drivers/win/taseditor/taseditor_project.h index 70355b59..3339806a 100644 --- a/src/drivers/win/taseditor/taseditor_project.h +++ b/src/drivers/win/taseditor/taseditor_project.h @@ -16,6 +16,7 @@ #include "piano_roll.h" #include "taseditor_lua.h" #include "splicer.h" +#include "editor.h" #include "popup_display.h" #define AUTOSAVE_PERIOD_SCALE 60000 // = 1 minute in milliseconds diff --git a/src/drivers/win/taseditor/taseditor_window.cpp b/src/drivers/win/taseditor/taseditor_window.cpp index 8732a236..be43fda8 100644 --- a/src/drivers/win/taseditor/taseditor_window.cpp +++ b/src/drivers/win/taseditor/taseditor_window.cpp @@ -12,7 +12,6 @@ Window - User Interface * implements all operations with TAS Editor window: creating, redrawing, resizing, moving, tooltips, clicks * processes OS messages and sends signals from user to TAS Editor modules (also implements some minor commands on-site, like Greenzone capacity dialog and such) -* regularly checks if Shift or Ctrl key is held and sets keyboard focus to Piano Roll * switches off/on emulator's keyboard input when the window loses/gains focus * on demand: updates the window caption * updates all checkboxes and menu items when some settings change @@ -36,6 +35,7 @@ extern RECORDER recorder; extern TASEDITOR_PROJECT project; extern PIANO_ROLL piano_roll; extern SELECTION selection; +extern EDITOR editor; extern SPLICER splicer; extern MARKERS_MANAGER markers_manager; extern BOOKMARKS bookmarks; @@ -45,8 +45,6 @@ extern POPUP_DISPLAY popup_display; extern bool turbo; extern bool muteTurbo; extern bool must_call_manual_lua_function; -extern std::vector autofire_patterns_names; -extern std::vector> autofire_patterns; extern char* GetKeyComboName(int c); @@ -141,8 +139,8 @@ void TASEDITOR_WINDOW::init() ShowWindow(hwndTasEditor, SW_SHOWMAXIMIZED); // menus and checked items hmenu = GetMenu(hwndTasEditor); - patterns_menu = GetSubMenu(hmenu, PATTERNS_MENU_POS); UpdateCheckedItems(); + patterns_menu = GetSubMenu(hmenu, PATTERNS_MENU_POS); // tooltips int x = 0; for (int i = 0; i < TASEDITOR_WINDOW_TOTAL_ITEMS; ++i) @@ -204,8 +202,6 @@ void TASEDITOR_WINDOW::init() // create "Recent" submenu recent_projects_menu = CreateMenu(); UpdateRecentProjectsMenu(); - // create "Patterns" menu - UpdatePatternsMenu(); SetTaseditorInput(); reset(); @@ -244,14 +240,6 @@ void TASEDITOR_WINDOW::reset() } void TASEDITOR_WINDOW::update() { - if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_NONE) - { - HWND cur_focus = GetFocus(); - if (cur_focus != piano_roll.hwndList && cur_focus != hwndFindNote) - // set focus to Piano Roll when Shift or Ctrl are held - if ((GetAsyncKeyState(VK_CONTROL) < 0) || (GetAsyncKeyState(VK_SHIFT) < 0)) - SetFocus(piano_roll.hwndList); - } } // -------------------------------------------------------------------------------- void TASEDITOR_WINDOW::CalculateItems() @@ -446,11 +434,9 @@ void TASEDITOR_WINDOW::UpdateCheckedItems() CheckMenuItem(hmenu, ID_CONFIG_COMBINECONSECUTIVERECORDINGS, taseditor_config.combine_consecutive_rec?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_USE1PFORRECORDING, taseditor_config.use_1p_rec?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_USEINPUTKEYSFORCOLUMNSET, taseditor_config.columnset_by_keys?MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu, ID_CONFIG_KEYBOARDCONTROLSINPIANOROLL, taseditor_config.keyboard_for_piano_roll?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE, taseditor_config.superimpose_affects_paste?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_COLUMNSETPATTERNSKIPSLAG, taseditor_config.pattern_skips_lag?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_DESELECTONDOUBLECLICK, taseditor_config.deselect_on_doubleclick?MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu, ID_CONFIG_DOUBLECLICKONFRAME, taseditor_config.doubleclick_affects_playback?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_DRAWINPUTBYDRAGGING, taseditor_config.draw_input?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_SILENTAUTOSAVE, taseditor_config.silent_autosave?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_MUTETURBO, muteTurbo?MF_CHECKED : MF_UNCHECKED); @@ -593,12 +579,12 @@ void TASEDITOR_WINDOW::UpdatePatternsMenu() for(x = GetMenuItemCount(patterns_menu); x > 0 ; x--) RemoveMenu(patterns_menu, 0, MF_BYPOSITION); // Fill the menu - for(x = autofire_patterns.size() - 1; x >= 0; x--) + for(x = editor.autofire_patterns.size() - 1; x >= 0; x--) { moo.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE; moo.fType = 0; moo.wID = MENU_FIRST_PATTERN + x; - std::string tmp = autofire_patterns_names[x]; + std::string tmp = editor.autofire_patterns_names[x]; // clamp this string to 50 chars if(tmp.size() > PATTERNS_MAX_VISIBLE_NAME) tmp = tmp.substr(0, PATTERNS_MAX_VISIBLE_NAME); @@ -621,7 +607,7 @@ void TASEDITOR_WINDOW::RecheckPatternsMenu() int x; x = GetMenuItemInfo(hmenu, PATTERNS_MENU_POS, true, &moo); std::string tmp = patterns_menu_prefix; - tmp += autofire_patterns_names[taseditor_config.current_pattern]; + tmp += editor.autofire_patterns_names[taseditor_config.current_pattern]; // clamp this string if(tmp.size() > PATTERNMENU_MAX_VISIBLE_NAME) tmp = tmp.substr(0, PATTERNMENU_MAX_VISIBLE_NAME); @@ -774,7 +760,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara break; } // then check clicking Patterns menu item - if (loword_wparam >= MENU_FIRST_PATTERN && loword_wparam < MENU_FIRST_PATTERN + autofire_patterns.size()) + if (loword_wparam >= MENU_FIRST_PATTERN && loword_wparam < MENU_FIRST_PATTERN + editor.autofire_patterns.size()) { taseditor_config.current_pattern = loword_wparam - MENU_FIRST_PATTERN; recorder.pattern_offset = 0; @@ -811,14 +797,15 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara break; case ID_EDIT_DESELECT: case ID_SELECTED_DESELECT: - selection.ClearSelection(); + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + selection.ClearSelection(); break; case ID_EDIT_SELECTALL: if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER) SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETSEL, 0, -1); else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER) SendMessage(selection.hwndSelectionMarkerEdit, EM_SETSEL, 0, -1); - else + else if (piano_roll.drag_mode != DRAG_MODE_SELECTION) selection.SelectAll(); break; case ACCEL_CTRL_X: @@ -1054,10 +1041,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara taseditor_config.columnset_by_keys ^= 1; taseditor_window.UpdateCheckedItems(); break; - case ID_CONFIG_KEYBOARDCONTROLSINPIANOROLL: - taseditor_config.keyboard_for_piano_roll ^= 1; - taseditor_window.UpdateCheckedItems(); - break; case ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE: taseditor_config.superimpose_affects_paste ^= 1; taseditor_window.UpdateCheckedItems(); @@ -1070,10 +1053,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara taseditor_config.deselect_on_doubleclick ^= 1; taseditor_window.UpdateCheckedItems(); break; - case ID_CONFIG_DOUBLECLICKONFRAME: - taseditor_config.doubleclick_affects_playback ^= 1; - taseditor_window.UpdateCheckedItems(); - break; case ID_CONFIG_DRAWINPUTBYDRAGGING: taseditor_config.draw_input ^= 1; taseditor_window.UpdateCheckedItems(); @@ -1132,12 +1111,13 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETSEL, 0, -1); else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER) SendMessage(selection.hwndSelectionMarkerEdit, EM_SETSEL, 0, -1); - else + else if (piano_roll.drag_mode != DRAG_MODE_SELECTION) selection.SelectBetweenMarkers(); break; case ID_EDIT_SELECTMIDMARKERS: case ID_SELECTED_SELECTMIDMARKERS: - selection.SelectBetweenMarkers(); + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + selection.SelectBetweenMarkers(); break; case ACCEL_CTRL_INSERT: case ID_EDIT_CLONEFRAMES: @@ -1168,22 +1148,31 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara case ID_EDIT_SELECTIONUNDO: case ACCEL_CTRL_Q: { - selection.undo(); - piano_roll.FollowSelection(); + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + selection.undo(); + piano_roll.FollowSelection(); + } break; } case ID_EDIT_SELECTIONREDO: case ACCEL_CTRL_W: { - selection.redo(); - piano_roll.FollowSelection(); + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + selection.redo(); + piano_roll.FollowSelection(); + } break; } case ID_EDIT_RESELECTCLIPBOARD: case ACCEL_CTRL_B: { - selection.ReselectClipboard(); - piano_roll.FollowSelection(); + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + selection.ReselectClipboard(); + piano_roll.FollowSelection(); + } break; } case IDC_JUMP_PLAYBACK_BUTTON: @@ -1193,7 +1182,8 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } case IDC_JUMP_SELECTION_BUTTON: { - piano_roll.FollowSelection(); + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + piano_roll.FollowSelection(); break; } case ID_SELECTED_SETMARKER: @@ -1243,23 +1233,11 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara if (changes_made) { selection.must_find_current_marker = playback.must_find_current_marker = true; - history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, *current_selection_begin, *current_selection->rbegin()); + history.RegisterMarkersChange(MODTYPE_MARKER_REMOVE, *current_selection_begin, *current_selection->rbegin()); } } break; } - case ACCEL_SHIFT_PGUP: - playback.RewindFull(); - break; - case ACCEL_SHIFT_PGDN: - playback.ForwardFull(); - break; - case ACCEL_CTRL_PGUP: - selection.JumpPrevMarker(); - break; - case ACCEL_CTRL_PGDN: - selection.JumpNextMarker(); - break; case ACCEL_CTRL_F: case ID_VIEW_FINDNOTE: { @@ -1298,10 +1276,106 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara case ID_HELP_ABOUT: DialogBox(fceu_hInstance, MAKEINTRESOURCE(IDD_TASEDITOR_ABOUT), taseditor_window.hwndTasEditor, AboutProc); break; - case ID_STRAY_UNPAUSE: - playback.UnpauseEmulation(); + case ACCEL_HOME: + // scroll Piano Roll to the beginning + ListView_Scroll(piano_roll.hwndList, 0, -piano_roll.list_row_height * ListView_GetTopIndex(piano_roll.hwndList)); + break; + case ACCEL_END: + // scroll Piano Roll to the end + ListView_Scroll(piano_roll.hwndList, 0, piano_roll.list_row_height * currMovieData.getNumRecords()); + break; + case ACCEL_PGUP: + // scroll Piano Roll 1 page up + ListView_Scroll(piano_roll.hwndList, 0, -piano_roll.list_row_height * ListView_GetCountPerPage(piano_roll.hwndList)); + break; + case ACCEL_PGDN: + // scroll Piano Roll 1 page up + ListView_Scroll(piano_roll.hwndList, 0, piano_roll.list_row_height * ListView_GetCountPerPage(piano_roll.hwndList)); + break; + case ACCEL_CTRL_HOME: + { + // transpose Selection to the beginning and scroll to it + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + int selection_beginning = selection.GetCurrentSelectionBeginning(); + if (selection_beginning >= 0) + { + selection.Transpose(-selection_beginning); + piano_roll.FollowSelection(); + } + } + break; + } + case ACCEL_CTRL_END: + { + // transpose Selection to the end and scroll to it + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + int selection_end = selection.GetCurrentSelectionEnd(); + if (selection_end >= 0) + { + selection.Transpose(currMovieData.getNumRecords() - 1 - selection_end); + piano_roll.FollowSelection(); + } + } + break; + } + case ACCEL_CTRL_PGUP: + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + selection.JumpPrevMarker(); + break; + case ACCEL_CTRL_PGDN: + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + selection.JumpNextMarker(); + break; + case ACCEL_CTRL_UP: + // transpose Selection 1 frame up and scroll to it + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + selection.Transpose(-1); + piano_roll.FollowSelection(); + } + break; + case ACCEL_CTRL_DOWN: + // transpose Selection 1 frame down and scroll to it + if (piano_roll.drag_mode != DRAG_MODE_SELECTION) + { + selection.Transpose(1); + piano_roll.FollowSelection(); + } + break; + case ACCEL_CTRL_LEFT: + case ACCEL_SHIFT_LEFT: + // scroll Piano Roll horizontally to the left + ListView_Scroll(piano_roll.hwndList, -COLUMN_BUTTON_WIDTH, 0); + break; + case ACCEL_CTRL_RIGHT: + case ACCEL_SHIFT_RIGHT: + // scroll Piano Roll horizontally to the right + ListView_Scroll(piano_roll.hwndList, COLUMN_BUTTON_WIDTH, 0); + break; + case ACCEL_SHIFT_HOME: + // send Playback to the beginning + playback.jump(0); + break; + case ACCEL_SHIFT_END: + // send Playback to the end + playback.jump(currMovieData.getNumRecords() - 1); + break; + case ACCEL_SHIFT_PGUP: + playback.RewindFull(); + break; + case ACCEL_SHIFT_PGDN: + playback.ForwardFull(); + break; + case ACCEL_SHIFT_UP: + // rewind 1 frame + playback.RewindFrame(); + break; + case ACCEL_SHIFT_DOWN: + // step forward 1 frame + playback.ForwardFrame(); break; - } break; diff --git a/src/drivers/win/taseditor/taseditor_window.h b/src/drivers/win/taseditor/taseditor_window.h index 095d94f4..8f4544c5 100644 --- a/src/drivers/win/taseditor/taseditor_window.h +++ b/src/drivers/win/taseditor/taseditor_window.h @@ -24,12 +24,6 @@ struct Window_items_struct HWND tooltip_hwnd; }; -enum ECONTEXTMENU -{ - CONTEXTMENU_STRAY = 0, - CONTEXTMENU_SELECTED = 1, -}; - class TASEDITOR_WINDOW { public: diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 5f60caf3..fc96d3c0 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -4398,11 +4398,11 @@ static int taseditor_setmarker(lua_State *L) return 1; } -// taseditor.clearmarker(int frame) -static int taseditor_clearmarker(lua_State *L) +// taseditor.removemarker(int frame) +static int taseditor_removemarker(lua_State *L) { #ifdef WIN32 - taseditor_lua.clearmarker(luaL_checkinteger(L, 1)); + taseditor_lua.removemarker(luaL_checkinteger(L, 1)); #endif return 0; } @@ -5387,7 +5387,7 @@ static const struct luaL_reg taseditorlib[] = { {"markedframe", taseditor_markedframe}, {"getmarker", taseditor_getmarker}, {"setmarker", taseditor_setmarker}, - {"clearmarker", taseditor_clearmarker}, + {"removemarker", taseditor_removemarker}, {"getnote", taseditor_getnote}, {"setnote", taseditor_setnote}, {"getcurrentbranch", taseditor_getcurrentbranch}, diff --git a/vc/vc10_fceux.vcxproj b/vc/vc10_fceux.vcxproj index 589bc22a..99e278d5 100644 --- a/vc/vc10_fceux.vcxproj +++ b/vc/vc10_fceux.vcxproj @@ -422,6 +422,7 @@ + @@ -748,6 +749,7 @@ + diff --git a/vc/vc10_fceux.vcxproj.filters b/vc/vc10_fceux.vcxproj.filters index 7e278a46..775d22c0 100644 --- a/vc/vc10_fceux.vcxproj.filters +++ b/vc/vc10_fceux.vcxproj.filters @@ -955,6 +955,9 @@ drivers\win\taseditor + + drivers\win\taseditor + @@ -1444,6 +1447,9 @@ drivers\win\taseditor + + drivers\win\taseditor +