* Taseditor: quicksave/quickload hotkeys save/load current branch

* Taseditor: Help->Show Tooltips
* Added "Restore Playback (TAS Editor)" hotkey (Enter by default)
* 9 new Lua functions in TAS Editor library
This commit is contained in:
ansstuff 2012-01-29 22:33:23 +00:00
parent d509d8ecac
commit a1e0de898b
45 changed files with 2345 additions and 1555 deletions

View File

@ -17,8 +17,8 @@ pads = {
buttons = {
A = {x=30,y=5,w=3,h=3},
B = {x=24,y=5,w=3,h=3},
start = {x=12,y=7,w=3,h=1},
select = {x=18,y=7,w=3,h=1},
start = {x=12,y=7,w=3,h=1},
up = {x=4, y=1,w=2,h=2},
down = {x=4, y=7,w=2,h=2},
left = {x=1, y=4,w=2,h=2},

View File

@ -342,6 +342,8 @@ static CFGSTRUCT fceuconfig[] = {
AC(taseditor_config.savecompact_selection),
AC(taseditor_config.findnote_matchcase),
AC(taseditor_config.findnote_search_up),
AC(taseditor_config.silent_autosave),
AC(taseditor_config.tooltips),
ACS(taseditor_config_last_author),
AC(lagCounterDisplay),
AC(oldInputDisplay),

View File

@ -75,6 +75,7 @@ static struct
{ EMUCMD_MISC_TOGGLEFULLSCREEN, SCAN_ENTER | CMD_KEY_ALT, },
{ EMUCMD_TASEDITOR_REWIND, SCAN_ESCAPE, },
{ EMUCMD_RERECORD_DISPLAY_TOGGLE, SCAN_M, },
{ EMUCMD_TASEDITOR_RESTORE_PLAYBACK, SCAN_ENTER, },
};
#define NUM_DEFAULT_MAPPINGS (sizeof(DefaultCommandMapping)/sizeof(DefaultCommandMapping[0]))

View File

@ -255,8 +255,7 @@ BEGIN
MENUITEM "&Insert\tShift+Ins", ID_EDIT_INSERTFRAMES
MENUITEM "Insert # of Frames\tIns", ID_EDIT_INSERT
MENUITEM SEPARATOR
MENUITEM "Truncate\tCtrl+T", ID_EDIT_TRUNCATE
MENUITEM SEPARATOR
MENUITEM "Truncate movie", ID_EDIT_TRUNCATE
END
POPUP "&View"
BEGIN
@ -296,7 +295,8 @@ BEGIN
END
POPUP "&Help"
BEGIN
MENUITEM "&TAS Editor Help", ID_HELP_TASEDITORHELP
MENUITEM "TAS Editor &Help", ID_HELP_TASEDITORHELP
MENUITEM "Enable &Tooltips", ID_HELP_TOOLTIPS
MENUITEM SEPARATOR
MENUITEM "&About", ID_HELP_ABOUT
END
@ -376,15 +376,16 @@ TASEDITORCONTEXTMENUS MENU
BEGIN
POPUP "Stray"
BEGIN
MENUITEM "Insert # of Frames", MENU_CONTEXT_STRAY_INSERTFRAMES
MENUITEM "Unpause emulator", ID_STRAY_UNPAUSE
MENUITEM SEPARATOR
MENUITEM "Truncate movie", ID_CONTEXT_STRAY_TRUNCATE
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 "Select mid &Markers", ID_SELECTED_SELECTMIDMARKERS
MENUITEM "Select between &Markers", ID_SELECTED_SELECTMIDMARKERS
MENUITEM SEPARATOR
MENUITEM "C&lear", ID_CONTEXT_SELECTED_CLEARFRAMES
MENUITEM "&Delete", ID_CONTEXT_SELECTED_DELETEFRAMES
@ -1649,6 +1650,7 @@ END
IDD_LUA DIALOGEX 0, 0, 270, 150
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Lua Script"
MENU LUAWINDOW_MENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
@ -2189,7 +2191,6 @@ BEGIN
VK_PRIOR, ACCEL_CTRL_PGUP, VIRTKEY, CONTROL, NOINVERT
"Q", ACCEL_CTRL_Q, VIRTKEY, CONTROL, NOINVERT
"S", ACCEL_CTRL_S, VIRTKEY, CONTROL, NOINVERT
"T", ACCEL_CTRL_T, VIRTKEY, CONTROL, NOINVERT
"V", ACCEL_CTRL_V, VIRTKEY, CONTROL, NOINVERT
"W", ACCEL_CTRL_W, VIRTKEY, CONTROL, NOINVERT
"X", ACCEL_CTRL_X, VIRTKEY, CONTROL, NOINVERT
@ -2243,7 +2244,8 @@ IDB_BITMAP16 BITMAP "res\\te_16.bmp"
IDB_BITMAP17 BITMAP "res\\te_17.bmp"
IDB_BITMAP18 BITMAP "res\\te_18.bmp"
IDB_BITMAP19 BITMAP "res\\te_19.bmp"
IDB_TE_ARROW BITMAP "res/te_arrow.bmp"
IDB_TE_ARROW BITMAP "res\\te_arrow.bmp"
IDB_TE_GREEN_ARROW BITMAP "res\\te_green_arrow.bmp"
IDB_BRANCH_SPRITESHEET BITMAP "res\\branch_spritesheet.bmp"
#endif // Àíãëèéñêèé (ÑØÀ) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -234,6 +234,8 @@
#define IDC_DEBUGGER_FLAG_D 204
#define IDC_NETMOO_KEY 205
#define IDC_DEBUGGER_FLAG_I 205
#define IDB_BITMAP20 205
#define IDB_TE_GREEN_ARROW 205
#define IDC_NETMOO_PASS 206
#define IDC_DEBUGGER_FLAG_Z 206
#define IDC_DEBUGGER_FLAG_C 207
@ -977,6 +979,11 @@
#define ID_HELP_TASEDITORHELP 40523
#define MENU_TASEDITOR 40524
#define ID_FILE_NEW 40525
#define ID_HELP_SHOWTOOLTIPS 40526
#define ID_HELP_TOOLTIPS 40527
#define ID_STRAY_UNPAUSEEMULATOR 40528
#define ID_STRAY_UNPAUSE 40529
#define ID_STRAY_TRUNCATE40530 40530
#define IDC_DEBUGGER_ICONTRAY 55535
#define MW_ValueLabel2 65423
#define MW_ValueLabel1 65426
@ -985,8 +992,8 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 203
#define _APS_NEXT_COMMAND_VALUE 40526
#define _APS_NEXT_RESOURCE_VALUE 206
#define _APS_NEXT_COMMAND_VALUE 40531
#define _APS_NEXT_CONTROL_VALUE 1280
#define _APS_NEXT_SYMED_VALUE 101
#endif

View File

@ -6,29 +6,22 @@
#include "main.h" // for GetRomName
#include "taseditor.h"
#include "version.h"
#include <Shlwapi.h> // for StrStrI
#pragma comment(lib, "Shlwapi.lib")
using namespace std;
// TAS Editor data
bool Taseditor_rewind_now = false;
bool must_call_manual_lua_function = false;
// note editing/search (probably should be moved to separate class/module)
int marker_note_edit = MARKER_NOTE_EDIT_NONE;
char findnote_string[MAX_NOTE_LEN] = {0};
int search_similar_marker = 0;
// all Taseditor functional modules
TASEDITOR_CONFIG taseditor_config;
TASEDITOR_WINDOW taseditor_window;
TASEDITOR_PROJECT project;
INPUT_HISTORY history;
HISTORY history;
PLAYBACK playback;
RECORDER recorder;
GREENZONE greenzone;
MARKERS current_markers;
MARKERS_MANAGER markers_manager;
BOOKMARKS bookmarks;
POPUP_DISPLAY popup_display;
TASEDITOR_LIST list;
@ -61,7 +54,7 @@ void UpdateTasEditor()
// update all modules that need to be updated every frame
recorder.update();
list.update();
current_markers.update();
markers_manager.update();
greenzone.update();
playback.update();
bookmarks.update();
@ -81,187 +74,6 @@ void UpdateTasEditor()
}
}
void SingleClick(LPNMITEMACTIVATE info)
{
int row_index = info->iItem;
if(row_index == -1) return;
int column_index = info->iSubItem;
if(column_index == COLUMN_ICONS)
{
// click on the "icons" column - jump to the frame
selection.ClearSelection();
playback.jump(row_index);
} else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
{
// click on the "frame number" column - set marker if clicked with Alt
if (info->uKeyFlags & LVKF_ALT)
{
// reverse MARKER_FLAG_BIT in pointed frame
current_markers.ToggleMarker(row_index);
selection.must_find_current_marker = playback.must_find_current_marker = true;
if (current_markers.GetMarker(row_index))
history.RegisterMarkersChange(MODTYPE_MARKER_SET, row_index);
else
history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, row_index);
list.RedrawRow(row_index);
}
}
else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
{
ToggleJoypadBit(column_index, row_index, info->uKeyFlags);
}
}
void DoubleClick(LPNMITEMACTIVATE info)
{
int row_index = info->iItem;
if(row_index == -1) return;
int column_index = info->iSubItem;
if(column_index == COLUMN_ICONS || column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
{
// double click sends playback to the frame
selection.ClearSelection();
playback.jump(row_index);
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
{
ToggleJoypadBit(column_index, row_index, info->uKeyFlags);
}
}
void 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 & (LVKF_SHIFT|LVKF_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 (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 ColumnSet(int column)
{
if (column == COLUMN_FRAMENUM || column == COLUMN_FRAMENUM2)
FrameColumnSet();
else
InputColumnSet(column);
}
void FrameColumnSet()
{
SelectionFrames* current_selection = selection.MakeStrobe();
if (current_selection->size() == 0) return;
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(!current_markers.GetMarker(*it))
{
unset_found = true;
break;
}
}
if (unset_found)
{
// set all
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
{
if(!current_markers.GetMarker(*it))
{
if (current_markers.SetMarker(*it))
{
changes_made = true;
list.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(current_markers.GetMarker(*it))
{
current_markers.ClearMarker(*it);
changes_made = true;
list.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;
list.SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
}
}
void InputColumnSet(int column)
{
int joy = (column - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return;
int button = (column - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
SelectionFrames* current_selection = selection.MakeStrobe();
if (current_selection->size() == 0) return;
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);
if (newValue)
{
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, *current_selection_begin, *current_selection->rbegin()));
} else
{
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, *current_selection_begin, *current_selection->rbegin()));
}
list.SetHeaderColumnLight(column, HEADER_LIGHT_MAX);
}
BOOL CALLBACK NewProjectProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static struct NewProjectParameters* p = NULL;
@ -360,10 +172,11 @@ void NewProject()
// copy input from current snapshot (from history)
history.GetCurrentSnapshot().toMovie(currMovieData);
if (!params.copy_current_markers)
current_markers.reset();
markers_manager.reset();
if(params.author_name != L"") currMovieData.comments.push_back(L"author " + params.author_name);
// reset Taseditor
project.init(); // new project has blank name
greenzone.reset();
playback.reset();
playback.StartFromZero();
@ -374,11 +187,8 @@ void NewProject()
splicer.reset();
recorder.reset();
popup_display.reset();
project.reset();
taseditor_window.RedrawTaseditor();
taseditor_window.UpdateCaption();
search_similar_marker = 0;
marker_note_edit = MARKER_NOTE_EDIT_NONE;
}
}
@ -411,8 +221,6 @@ void OpenProject()
}
bool LoadProject(char* fullname)
{
marker_note_edit = MARKER_NOTE_EDIT_NONE;
SetFocus(list.hwndList);
// try to load project
if (project.load(fullname))
{
@ -422,14 +230,12 @@ bool LoadProject(char* fullname)
taseditor_window.UpdateRecentProjectsArray(fullname);
taseditor_window.RedrawTaseditor();
taseditor_window.UpdateCaption();
search_similar_marker = 0;
return true;
} else
{
// failed to load
taseditor_window.RedrawTaseditor();
taseditor_window.UpdateCaption();
search_similar_marker = 0;
return false;
}
}
@ -731,15 +537,15 @@ void Export()
char framenum[11];
std::string subtitle;
int marker_id;
for (int i = 0; i < current_markers.GetMarkersSize(); ++i)
for (int i = 0; i < markers_manager.GetMarkersSize(); ++i)
{
marker_id = current_markers.GetMarker(i);
marker_id = markers_manager.GetMarker(i);
if (marker_id)
{
_itoa(i, framenum, 10);
strcat(framenum, " ");
subtitle = framenum;
subtitle.append(current_markers.GetNote(marker_id));
subtitle.append(markers_manager.GetNote(marker_id));
temp_md.subtitles.push_back(subtitle);
}
}
@ -761,7 +567,7 @@ bool EnterTasEditor()
taseditor_window.init();
if(taseditor_window.hwndTasEditor)
{
SetTaseditInput();
SetTaseditorInput();
// save "eoptions"
saved_eoptions = eoptions;
// set "Run in background"
@ -783,7 +589,7 @@ bool EnterTasEditor()
playback.init();
greenzone.init();
recorder.init();
current_markers.init();
markers_manager.init();
project.init();
bookmarks.init();
popup_display.init();
@ -809,7 +615,6 @@ bool EnterTasEditor()
FCEUI_StopMovie();
movieMode = MOVIEMODE_TASEDITOR;
currMovieData.emuVersion = FCEU_VERSION_NUMERIC;
greenzone.TryDumpIncremental(lagFlag != 0);
}
// ensure that movie has correct set of ports/fourscore
SetInputType(currMovieData, GetInputType(currMovieData));
@ -822,12 +627,11 @@ bool EnterTasEditor()
history.reset();
// reset Taseditor variables
must_call_manual_lua_function = false;
marker_note_edit = MARKER_NOTE_EDIT_NONE;
search_similar_marker = 0;
SetFocus(history.hwndHistoryList); // set focus only once, to show selection cursor
SetFocus(list.hwndList);
FCEU_DispMessage("TAS Editor engaged", 0);
taseditor_window.RedrawTaseditor();
return true;
} else return false;
} else return true;
@ -841,7 +645,7 @@ bool ExitTasEditor()
taseditor_window.exit();
// release memory
list.free();
current_markers.free();
markers_manager.free();
greenzone.free();
bookmarks.free();
popup_display.free();
@ -849,7 +653,7 @@ bool ExitTasEditor()
playback.SeekingStop();
selection.free();
ClearTaseditInput();
ClearTaseditorInput();
// restore "eoptions"
eoptions = saved_eoptions;
// restore autosaves
@ -900,184 +704,16 @@ void SetInputType(MovieData& md, int new_input_type)
}
}
void SetTaseditInput()
void SetTaseditorInput()
{
// set "Background TAS Editor input"
KeyboardSetBackgroundAccessBit(KEYBACKACCESS_TASEDITOR);
JoystickSetBackgroundAccessBit(JOYBACKACCESS_TASEDITOR);
}
void ClearTaseditInput()
void ClearTaseditorInput()
{
// clear "Background TAS Editor input"
KeyboardClearBackgroundAccessBit(KEYBACKACCESS_TASEDITOR);
JoystickClearBackgroundAccessBit(JOYBACKACCESS_TASEDITOR);
}
void UpdateMarkerNote()
{
if (!marker_note_edit) return;
char new_text[MAX_NOTE_LEN];
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
int len = SendMessage(playback.hwndPlaybackMarkerEdit, WM_GETTEXT, MAX_NOTE_LEN, (LPARAM)new_text);
new_text[len] = 0;
// check changes
if (strcmp(current_markers.GetNote(playback.shown_marker).c_str(), new_text))
{
current_markers.SetNote(playback.shown_marker, new_text);
if (playback.shown_marker)
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, current_markers.GetMarkerFrame(playback.shown_marker));
else
// zeroth marker - just assume it's set on frame 0
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, 0);
// notify selection to change text in lower marker (in case both are showing same marker)
selection.must_find_current_marker = true;
}
} else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
int len = SendMessage(selection.hwndSelectionMarkerEdit, WM_GETTEXT, MAX_NOTE_LEN, (LPARAM)new_text);
new_text[len] = 0;
// check changes
if (strcmp(current_markers.GetNote(selection.shown_marker).c_str(), new_text))
{
current_markers.SetNote(selection.shown_marker, new_text);
if (selection.shown_marker)
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, current_markers.GetMarkerFrame(selection.shown_marker));
else
// zeroth marker - just assume it's set on frame 0
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, 0);
// notify playback to change text in upper marker (in case both are showing same marker)
playback.must_find_current_marker = true;
}
}
}
BOOL CALLBACK FindNoteProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
if (taseditor_config.findnote_wndx == -32000) taseditor_config.findnote_wndx = 0; //Just in case
if (taseditor_config.findnote_wndy == -32000) taseditor_config.findnote_wndy = 0;
SetWindowPos(hwndDlg, 0, taseditor_config.findnote_wndx, taseditor_config.findnote_wndy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
CheckDlgButton(hwndDlg, IDC_MATCH_CASE, taseditor_config.findnote_matchcase?MF_CHECKED : MF_UNCHECKED);
if (taseditor_config.findnote_search_up)
Button_SetCheck(GetDlgItem(hwndDlg, IDC_RADIO_UP), BST_CHECKED);
else
Button_SetCheck(GetDlgItem(hwndDlg, IDC_RADIO_DOWN), BST_CHECKED);
HWND hwndEdit = GetDlgItem(hwndDlg, IDC_NOTE_TO_FIND);
SendMessage(hwndEdit, EM_SETLIMITTEXT, MAX_NOTE_LEN - 1, 0);
SetWindowText(hwndEdit, findnote_string);
if (GetDlgCtrlID((HWND)wParam) != IDC_NOTE_TO_FIND)
{
SetFocus(hwndEdit);
return false;
}
return true;
}
case WM_MOVE:
{
if (!IsIconic(hwndDlg))
{
RECT wrect;
GetWindowRect(hwndDlg, &wrect);
taseditor_config.findnote_wndx = wrect.left;
taseditor_config.findnote_wndy = wrect.top;
WindowBoundsCheckNoResize(taseditor_config.findnote_wndx, taseditor_config.findnote_wndy, wrect.right);
}
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_NOTE_TO_FIND:
{
if(HIWORD(wParam) == EN_CHANGE)
{
if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_NOTE_TO_FIND)))
EnableWindow(GetDlgItem(hwndDlg, IDOK), true);
else
EnableWindow(GetDlgItem(hwndDlg, IDOK), false);
}
break;
}
case IDC_RADIO_UP:
taseditor_config.findnote_search_up = true;
break;
case IDC_RADIO_DOWN:
taseditor_config.findnote_search_up = false;
break;
case IDC_MATCH_CASE:
taseditor_config.findnote_matchcase ^= 1;
CheckDlgButton(hwndDlg, IDC_MATCH_CASE, taseditor_config.findnote_matchcase?MF_CHECKED : MF_UNCHECKED);
break;
case IDOK:
{
int len = SendMessage(GetDlgItem(hwndDlg, IDC_NOTE_TO_FIND), WM_GETTEXT, MAX_NOTE_LEN, (LPARAM)findnote_string);
findnote_string[len] = 0;
// scan frames from current selection to the border
int cur_marker = 0;
bool result;
int movie_size = currMovieData.getNumRecords();
int current_frame = selection.GetCurrentSelectionBeginning();
if (current_frame < 0 && taseditor_config.findnote_search_up)
current_frame = movie_size;
while (true)
{
// move forward
if (taseditor_config.findnote_search_up)
{
current_frame--;
if (current_frame < 0)
{
MessageBox(taseditor_window.hwndFindNote, "Nothing was found.", "Find Note", MB_OK);
break;
}
} else
{
current_frame++;
if (current_frame >= movie_size)
{
MessageBox(taseditor_window.hwndFindNote, "Nothing was found!", "Find Note", MB_OK);
break;
}
}
// scan marked frames
cur_marker = current_markers.GetMarker(current_frame);
if (cur_marker)
{
if (taseditor_config.findnote_matchcase)
result = (strstr(current_markers.GetNote(cur_marker).c_str(), findnote_string) != 0);
else
result = (StrStrI(current_markers.GetNote(cur_marker).c_str(), findnote_string) != 0);
if (result)
{
// found note containing searched string - jump there
selection.JumpToFrame(current_frame);
break;
}
}
}
return TRUE;
}
case IDCANCEL:
DestroyWindow(taseditor_window.hwndFindNote);
taseditor_window.hwndFindNote = 0;
return TRUE;
}
break;
}
case WM_CLOSE:
case WM_QUIT:
{
DestroyWindow(taseditor_window.hwndFindNote);
taseditor_window.hwndFindNote = 0;
break;
}
}
return FALSE;
}

View File

@ -1,9 +1,4 @@
enum
{
MARKER_NOTE_EDIT_NONE,
MARKER_NOTE_EDIT_UPPER,
MARKER_NOTE_EDIT_LOWER
};
// main TAS Editor file
struct NewProjectParameters
{
@ -13,14 +8,6 @@ struct NewProjectParameters
std::wstring author_name;
};
void SingleClick(LPNMITEMACTIVATE info);
void DoubleClick(LPNMITEMACTIVATE info);
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags);
void ColumnSet(int column);
void InputColumnSet(int column);
void FrameColumnSet();
bool EnterTasEditor();
bool ExitTasEditor();
void UpdateTasEditor();
@ -39,8 +26,5 @@ void Export();
int GetInputType(MovieData& md);
void SetInputType(MovieData& md, int new_input_type);
void SetTaseditInput();
void ClearTaseditInput();
void UpdateMarkerNote();
void SetTaseditorInput();
void ClearTaseditorInput();

View File

@ -4,7 +4,7 @@
extern TASEDITOR_CONFIG taseditor_config;
extern GREENZONE greenzone;
extern INPUT_HISTORY history;
extern HISTORY history;
extern uint8 *XBuf;
extern uint8 *XBackBuf;
@ -45,16 +45,16 @@ void BOOKMARK::set()
flash_type = FLASH_TYPE_SET;
}
void BOOKMARK::jump()
void BOOKMARK::jumped()
{
flash_phase = FLASH_PHASE_MAX;
flash_type = FLASH_TYPE_JUMP;
}
void BOOKMARK::unleashed()
void BOOKMARK::deployed()
{
flash_phase = FLASH_PHASE_MAX;
flash_type = FLASH_TYPE_UNLEASH;
flash_type = FLASH_TYPE_DEPLOY;
}
void BOOKMARK::save(EMUFILE *os)

View File

@ -5,7 +5,7 @@ enum
{
FLASH_TYPE_SET = 0,
FLASH_TYPE_JUMP = 1,
FLASH_TYPE_UNLEASH = 2,
FLASH_TYPE_DEPLOY = 2,
};
#define SCREENSHOT_WIDTH 256
@ -19,8 +19,8 @@ public:
void init();
void set();
void jump();
void unleashed();
void jumped();
void deployed();
void save(EMUFILE *os);
bool load(EMUFILE *is);
@ -28,7 +28,7 @@ public:
bool not_empty;
int flash_phase;
int flash_type;
INPUT_SNAPSHOT snapshot;
SNAPSHOT snapshot;
std::vector<uint8> savestate;
std::vector<uint8> saved_screenshot;
int parent_branch;

View File

@ -16,11 +16,9 @@ extern PLAYBACK playback;
extern TASEDITOR_SELECTION selection;
extern GREENZONE greenzone;
extern TASEDITOR_PROJECT project;
extern INPUT_HISTORY history;
extern HISTORY history;
extern TASEDITOR_LIST list;
extern MARKERS current_markers;
extern void UpdateMarkerNote();
extern MARKERS_MANAGER markers_manager;
// resources
char bookmarks_save_id[BOOKMARKS_ID_LEN] = "BOOKMARKS";
@ -33,7 +31,7 @@ COLORREF bookmark_flash_colors[3][FLASH_PHASE_MAX+1] = {
0x0d1241, 0x111853, 0x161e64, 0x1a2575, 0x1f2b87, 0x233197, 0x2837a8, 0x2c3db9, 0x3144cb, 0x354adc, 0x3a50ed, 0x3f57ff,
// jump
0x14350f, 0x1c480f, 0x235a0f, 0x2a6c0f, 0x317f10, 0x38910f, 0x3fa30f, 0x46b50f, 0x4dc80f, 0x54da0f, 0x5bec0f, 0x63ff10,
// unleash
// deploy
0x43171d, 0x541d21, 0x652325, 0x762929, 0x872f2c, 0x983530, 0xa93b34, 0xba4137, 0xcb463b, 0xdc4c3f, 0xed5243, 0xff5947 };
// corners cursor animation
int corners_cursor_shift[BRANCHES_ANIMATION_FRAMES] = {0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 0 };
@ -173,6 +171,8 @@ void BOOKMARKS::free()
}
void BOOKMARKS::reset()
{
// delete all commands if there are any
commands.resize(0);
// init bookmarks
bookmarks_array.resize(0);
bookmarks_array.resize(TOTAL_BOOKMARKS);
@ -208,6 +208,26 @@ void BOOKMARKS::reset_vars()
void BOOKMARKS::update()
{
// execute all commands if needed
for (int i = 0; (i + 1) < (int)commands.size(); )
{
int command_id = commands[i++];
int slot = commands[i++];
switch (command_id)
{
case COMMAND_SET:
set(slot);
break;
case COMMAND_JUMP:
jump(slot);
break;
case COMMAND_DEPLOY:
deploy(slot);
break;
}
}
commands.resize(0);
// once per 100 milliseconds fade bookmark flashes
if (clock() > check_flash_shedule)
{
@ -264,12 +284,38 @@ void BOOKMARKS::update()
}
}
// stores commands in array for update() function
void BOOKMARKS::command(int command_id, int slot)
{
switch (command_id)
{
case COMMAND_SET:
{
if (slot < 0 || slot >= TOTAL_BOOKMARKS)
slot = DEFAULT_BOOKMARK;
commands.push_back(command_id);
commands.push_back(slot);
break;
}
case COMMAND_JUMP:
case COMMAND_DEPLOY:
{
if (slot >= 0 && slot < TOTAL_BOOKMARKS)
{
commands.push_back(command_id);
commands.push_back(slot);
}
break;
}
}
}
void BOOKMARKS::set(int slot)
{
if (slot < 0 || slot >= TOTAL_BOOKMARKS) return;
// First save edited note (in case it's being currently edited)
UpdateMarkerNote();
markers_manager.UpdateMarkerNote();
int previous_frame = bookmarks_array[slot].snapshot.jump_frame;
// save time of this slot before rewriting it
@ -405,13 +451,13 @@ void BOOKMARKS::jump(int slot)
{
int frame = bookmarks_array[slot].snapshot.jump_frame;
playback.jump(frame);
if (playback.GetPauseFrame())
if (playback.pause_frame)
list.FollowPauseframe();
bookmarks_array[slot].jump();
bookmarks_array[slot].jumped();
}
}
void BOOKMARKS::unleash(int slot)
void BOOKMARKS::deploy(int slot)
{
if (taseditor_config.branch_only_when_rec && movie_readonly)
{
@ -424,13 +470,13 @@ void BOOKMARKS::unleash(int slot)
int jump_frame = bookmarks_array[slot].snapshot.jump_frame;
bool markers_changed = false;
// revert current movie to the input_snapshot state
// revert current movie to the snapshot state
if (taseditor_config.branch_full_movie)
{
// update Markers
if (taseditor_config.bind_markers)
{
if (bookmarks_array[slot].snapshot.my_markers.checkMarkersDiff(current_markers))
if (bookmarks_array[slot].snapshot.MarkersDifferFromCurrent())
{
bookmarks_array[slot].snapshot.copyToMarkers();
project.SetProjectChanged();
@ -447,26 +493,26 @@ void BOOKMARKS::unleash(int slot)
selection.must_find_current_marker = playback.must_find_current_marker = true;
history.RegisterBranching(MODTYPE_BRANCH_0 + slot, first_change, slot);
greenzone.Invalidate(first_change);
bookmarks_array[slot].unleashed();
bookmarks_array[slot].deployed();
} else if (markers_changed)
{
selection.must_find_current_marker = playback.must_find_current_marker = true;
history.RegisterBranching(MODTYPE_BRANCH_MARKERS_0 + slot, first_change, slot);
list.RedrawList();
bookmarks_array[slot].unleashed();
bookmarks_array[slot].deployed();
} else
{
// didn't restore anything
bookmarks_array[slot].jump();
bookmarks_array[slot].jumped();
}
} else if (jump_frame > 0)
{
// update Markers
if (taseditor_config.bind_markers)
{
if (bookmarks_array[slot].snapshot.my_markers.checkMarkersDiff(current_markers, jump_frame))
if (bookmarks_array[slot].snapshot.MarkersDifferFromCurrent(jump_frame))
{
bookmarks_array[slot].snapshot.copyToMarkers(jump_frame-1);
bookmarks_array[slot].snapshot.copyToMarkers(jump_frame);
project.SetProjectChanged();
markers_changed = true;
}
@ -482,17 +528,17 @@ void BOOKMARKS::unleash(int slot)
selection.must_find_current_marker = playback.must_find_current_marker = true;
history.RegisterBranching(MODTYPE_BRANCH_0 + slot, first_change, slot);
greenzone.Invalidate(first_change);
bookmarks_array[slot].unleashed();
bookmarks_array[slot].deployed();
} else if (markers_changed)
{
selection.must_find_current_marker = playback.must_find_current_marker = true;
history.RegisterBranching(MODTYPE_BRANCH_MARKERS_0 + slot, first_change, slot);
list.RedrawList();
bookmarks_array[slot].unleashed();
bookmarks_array[slot].deployed();
} else
{
// didn't restore anything
bookmarks_array[slot].jump();
bookmarks_array[slot].jumped();
}
}
@ -938,7 +984,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
// frame number
SelectObject(msg->nmcd.hdc, list.hMainListFont);
int frame = bookmarks_array[cell_y].snapshot.jump_frame;
if (frame == currFrameCounter || frame == (playback.GetPauseFrame() - 1))
if (frame == currFrameCounter || frame == (playback.GetFlashingPauseFrame() - 1))
{
// current frame
msg->clrTextBk = CUR_FRAMENUM_COLOR;
@ -969,7 +1015,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
// frame number
SelectObject(msg->nmcd.hdc, list.hMainListFont);
int frame = bookmarks_array[cell_y].snapshot.jump_frame;
if (frame == currFrameCounter || frame == (playback.GetPauseFrame() - 1))
if (frame == currFrameCounter || frame == (playback.GetFlashingPauseFrame() - 1))
{
// current frame
msg->clrTextBk = CUR_INPUT_COLOR1;
@ -1006,9 +1052,9 @@ void BOOKMARKS::LeftClick(LPNMITEMACTIVATE info)
if (cell_y >= 0 && cell_x >= 0)
{
if (cell_x <= BOOKMARKS_COLUMN_FRAME || (taseditor_config.branch_only_when_rec && movie_readonly))
jump((cell_y + 1) % TOTAL_BOOKMARKS);
command(COMMAND_JUMP, (cell_y + 1) % TOTAL_BOOKMARKS);
else if (cell_x == BOOKMARKS_COLUMN_TIME && (!taseditor_config.branch_only_when_rec || !movie_readonly))
unleash((cell_y + 1) % TOTAL_BOOKMARKS);
command(COMMAND_DEPLOY, (cell_y + 1) % TOTAL_BOOKMARKS);
}
// remove selection
ListView_SetItemState(hwndBookmarksList, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
@ -1017,7 +1063,7 @@ void BOOKMARKS::RightClick(LPNMITEMACTIVATE info)
{
int cell_y = info->iItem;
if (cell_y >= 0)
set((cell_y + 1) % TOTAL_BOOKMARKS);
command(COMMAND_SET, (cell_y + 1) % TOTAL_BOOKMARKS);
// remove selection
ListView_SetItemState(hwndBookmarksList, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
}

View File

@ -10,6 +10,14 @@ enum
EDIT_MODE_BRANCHES = 2,
};
enum COMMANDS
{
COMMAND_SET = 0,
COMMAND_JUMP = 1,
COMMAND_DEPLOY = 2,
COMMAND_DELETE = 3, // not implemented, probably useless
};
#define ITEM_UNDER_MOUSE_NONE -2
#define ITEM_UNDER_MOUSE_CLOUD -1
@ -90,6 +98,8 @@ enum
#define BOOKMARKS_ID_LEN 10
#define TIME_DESC_LENGTH 9 // "HH:MM:SS"
#define DEFAULT_BOOKMARK 1
class BOOKMARKS
{
public:
@ -103,9 +113,7 @@ public:
void save(EMUFILE *os, bool really_save = true);
bool load(EMUFILE *is);
void set(int slot);
void jump(int slot);
void unleash(int slot);
void command(int command_id, int slot);
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo);
LONG CustomDraw(NMLVCUSTOMDRAW* msg);
@ -132,6 +140,7 @@ public:
void RecursiveAddHeight(int branch_num, int amount);
void RecursiveSetYPos(int parent, int parentY);
// saved vars
std::vector<BOOKMARK> bookmarks_array;
// not saved vars
@ -143,6 +152,10 @@ public:
TRACKMOUSEEVENT tme, list_tme;
private:
void set(int slot);
void jump(int slot);
void deploy(int slot);
void SetCurrentPosTime();
// also saved vars
@ -152,6 +165,7 @@ private:
char current_pos_time[TIME_DESC_LENGTH];
// not saved vars
std::vector<int> commands;
int check_flash_shedule;
int edit_mode;
int animation_frame;

View File

@ -9,6 +9,8 @@ extern PLAYBACK playback;
extern BOOKMARKS bookmarks;
extern TASEDITOR_LIST list;
extern char lagFlag;
char greenzone_save_id[GREENZONE_ID_LEN] = "GREENZONE";
char greenzone_skipsave_id[GREENZONE_ID_LEN] = "GREENZONX";
@ -31,7 +33,6 @@ void GREENZONE::free()
savestates.resize(0);
greenZoneCount = 0;
lag_history.resize(0);
// reset lua_colorings
// reset monitorings
}
@ -42,24 +43,21 @@ void GREENZONE::reset()
}
void GREENZONE::update()
{
if ((int)savestates.size() < greenZoneCount)
savestates.resize(greenZoneCount);
if ((int)lag_history.size() < greenZoneCount)
lag_history.resize(greenZoneCount);
// keep memorizing savestates, this function should be called at the end of every frame
if (greenZoneCount <= currFrameCounter || (int)savestates.size() <= currFrameCounter || savestates[currFrameCounter].empty())
CollectCurrentState();
// run cleaning from time to time
if (clock() > next_cleaning_time)
GreenzoneCleaning();
}
void GREENZONE::TryDumpIncremental(bool lagFlag)
void GREENZONE::CollectCurrentState()
{
// if movie length is less than currFrame, pad it with empty frames
if(currMovieData.getNumRecords() <= currFrameCounter)
currMovieData.insertEmpty(-1, 1 + currFrameCounter - currMovieData.getNumRecords());
// update greenzone upper limit
// update greenzone upper limit if needed
if (greenZoneCount <= currFrameCounter)
greenZoneCount = currFrameCounter+1;
if ((int)savestates.size() < greenZoneCount)
savestates.resize(greenZoneCount);
if ((int)lag_history.size() < greenZoneCount)
@ -67,7 +65,7 @@ void GREENZONE::TryDumpIncremental(bool lagFlag)
// if frame changed - log savestate
storeTasSavestate(currFrameCounter);
// also log frame_flags
// also log lag frames
if (currFrameCounter > 0)
{
// lagFlag indicates that lag was in previous frame
@ -91,8 +89,8 @@ bool GREENZONE::loadTasSavestate(int frame)
void GREENZONE::storeTasSavestate(int frame)
{
if ((int)savestates.size()<=frame)
savestates.resize(frame+1);
if ((int)savestates.size() <= frame)
savestates.resize(frame + 1);
EMUFILE_MEMORY ms(&savestates[frame]);
FCEUSS_SaveMS(&ms, Z_DEFAULT_COMPRESSION);
@ -103,11 +101,11 @@ void GREENZONE::GreenzoneCleaning()
{
int i = currFrameCounter - taseditor_config.greenzone_capacity;
bool changed = false;
if (i < 0) goto finish;
if (i <= 0) goto finish; // zeroth frame should not be cleaned
int limit;
// 2x of 1/2
limit = i - 2 * taseditor_config.greenzone_capacity;
if (limit < -1) limit = -1;
if (limit < 0) limit = 0;
for (; i > limit; i--)
{
if ((i & 0x1) && !savestates[i].empty())
@ -119,7 +117,7 @@ void GREENZONE::GreenzoneCleaning()
if (i < 0) goto finish;
// 4x of 1/4
limit = i - 4 * taseditor_config.greenzone_capacity;
if (limit < -1) limit = -1;
if (limit < 0) limit = 0;
for (; i > limit; i--)
{
if ((i & 0x3) && !savestates[i].empty())
@ -131,7 +129,7 @@ void GREENZONE::GreenzoneCleaning()
if (i < 0) goto finish;
// 8x of 1/8
limit = i - 8 * taseditor_config.greenzone_capacity;
if (limit < -1) limit = -1;
if (limit < 0) limit = 0;
for (; i > limit; i--)
{
if ((i & 0x7) && !savestates[i].empty())
@ -143,7 +141,7 @@ void GREENZONE::GreenzoneCleaning()
if (i < 0) goto finish;
// 16x of 1/16
limit = i - 16 * taseditor_config.greenzone_capacity;
if (limit < -1) limit = -1;
if (limit < 0) limit = 0;
for (; i > limit; i--)
{
if ((i & 0xF) && !savestates[i].empty())
@ -153,7 +151,7 @@ void GREENZONE::GreenzoneCleaning()
}
}
// clear all remaining
for (; i >= 0; i--)
for (; i > 0; i--)
{
if (!savestates[i].empty())
{
@ -208,7 +206,6 @@ void GREENZONE::save(EMUFILE *os, bool really_save)
}
if (savestates[frame].empty()) continue;
write32le(frame, os);
// write lua_colorings
// write monitorings
// write savestate
size = savestates[frame].size();
@ -312,7 +309,6 @@ bool GREENZONE::load(EMUFILE *is)
playback.SetProgressbar(frame, greenZoneCount);
last_tick = frame / PROGRESSBAR_UPDATE_RATE;
}
// read lua_colorings
// read monitorings
// read savestate
if (!read32le(&size, is)) break;
@ -380,6 +376,10 @@ void GREENZONE::InvalidateAndCheck(int after)
// either set playback cursor to the end of greenzone or run seeking to restore playback position
if (currFrameCounter >= greenZoneCount)
{
// remember the lost position
if (playback.lost_position_frame-1 < currFrameCounter)
playback.lost_position_frame = currFrameCounter + 1;
// auto-restore position if needed
if (taseditor_config.restore_position)
playback.restorePosition();
else

View File

@ -1,10 +1,8 @@
//Specification file for Greenzone class
//#define LAG_FLAG_BIT 1
#define TIME_BETWEEN_CLEANINGS 10000 // in milliseconds
#define GREENZONE_ID_LEN 10
#define TIME_BETWEEN_CLEANINGS 10000 // in milliseconds
// greenzone cleaning masks
#define EVERY16TH 0xFFFFFFF0
#define EVERY8TH 0xFFFFFFF8
@ -23,7 +21,7 @@ public:
void save(EMUFILE *os, bool really_save = true);
bool load(EMUFILE *is);
void TryDumpIncremental(bool lagFlag = true);
void CollectCurrentState();
bool loadTasSavestate(int frame);
void storeTasSavestate(int frame);

View File

@ -1,4 +1,4 @@
//Implementation file of Input History class (Undo feature)
//Implementation file of History class (Undo feature)
#include "taseditor_project.h"
LRESULT APIENTRY HistoryListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
@ -6,13 +6,14 @@ WNDPROC hwndHistoryList_oldWndProc;
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern MARKERS current_markers;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern PLAYBACK playback;
extern TASEDITOR_SELECTION selection;
extern GREENZONE greenzone;
extern TASEDITOR_PROJECT project;
extern TASEDITOR_LIST list;
extern TASEDITOR_LUA taseditor_lua;
extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES];
extern int GetInputType(MovieData& md);
@ -60,13 +61,14 @@ char modCaptions[41][20] = {" Init",
" LUA Marker Unset",
" LUA Marker Rename",
" LUA Change" };
char LuaCaptionPrefix[6] = " LUA ";
char joypadCaptions[4][5] = {"(1P)", "(2P)", "(3P)", "(4P)"};
INPUT_HISTORY::INPUT_HISTORY()
HISTORY::HISTORY()
{
}
void INPUT_HISTORY::init()
void HISTORY::init()
{
// prepare the history listview
hwndHistoryList = GetDlgItem(taseditor_window.hwndTasEditor, IDC_HISTORYLIST);
@ -79,31 +81,31 @@ void INPUT_HISTORY::init()
lvc.fmt = LVCFMT_LEFT;
ListView_InsertColumn(hwndHistoryList, 0, &lvc);
}
void INPUT_HISTORY::free()
void HISTORY::free()
{
input_snapshots.resize(0);
snapshots.resize(0);
history_total_items = 0;
}
void INPUT_HISTORY::reset()
void HISTORY::reset()
{
free();
// init vars
history_size = taseditor_config.undo_levels + 1;
undo_hint_pos = old_undo_hint_pos = undo_hint_time = -1;
old_show_undo_hint = show_undo_hint = false;
input_snapshots.resize(history_size);
snapshots.resize(history_size);
history_start_pos = 0;
history_cursor_pos = -1;
// create initial snapshot
INPUT_SNAPSHOT inp;
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
strcat(inp.description, modCaptions[0]);
inp.jump_frame = -1;
AddInputSnapshotToHistory(inp);
AddSnapshotToHistory(inp);
UpdateHistoryList();
RedrawHistoryList();
}
void INPUT_HISTORY::update()
void HISTORY::update()
{
// update undo_hint
if (old_undo_hint_pos != undo_hint_pos && old_undo_hint_pos >= 0)
@ -120,13 +122,10 @@ void INPUT_HISTORY::update()
}
if (old_show_undo_hint != show_undo_hint)
list.RedrawRow(undo_hint_pos); // not changing bookmarks list
}
// returns frame of first input change (for greenzone invalidation)
int INPUT_HISTORY::jump(int new_pos)
int HISTORY::jump(int new_pos)
{
if (new_pos < 0) new_pos = 0; else if (new_pos >= history_total_items) new_pos = history_total_items-1;
// if nothing is done, do not invalidate greenzone
@ -150,25 +149,25 @@ int INPUT_HISTORY::jump(int new_pos)
bool markers_changed = false;
if (taseditor_config.bind_markers)
{
if (input_snapshots[real_pos].my_markers.checkMarkersDiff(current_markers))
if (snapshots[real_pos].MarkersDifferFromCurrent())
{
input_snapshots[real_pos].copyToMarkers();
snapshots[real_pos].copyToMarkers();
project.SetProjectChanged();
markers_changed = true;
}
}
// update current movie
int first_change = input_snapshots[real_pos].findFirstChange(currMovieData);
int first_change = snapshots[real_pos].findFirstChange(currMovieData);
if (first_change >= 0)
{
input_snapshots[real_pos].toMovie(currMovieData, first_change);
snapshots[real_pos].toMovie(currMovieData, first_change);
selection.must_find_current_marker = playback.must_find_current_marker = true;
bookmarks.ChangesMadeSinceBranch();
// list will be redrawn by greenzone invalidation
} else if (markers_changed)
{
current_markers.update();
markers_manager.update();
selection.must_find_current_marker = playback.must_find_current_marker = true;
bookmarks.ChangesMadeSinceBranch();
list.RedrawList();
@ -181,19 +180,18 @@ int INPUT_HISTORY::jump(int new_pos)
return first_change;
}
int INPUT_HISTORY::undo()
int HISTORY::undo()
{
return jump(history_cursor_pos - 1);
}
int INPUT_HISTORY::redo()
int HISTORY::redo()
{
return jump(history_cursor_pos + 1);
}
// ----------------------------
void INPUT_HISTORY::AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp)
void HISTORY::AddSnapshotToHistory(SNAPSHOT &inp)
{
// history uses conveyor of snapshots (vector with fixed size) to aviod resizing which is awfully expensive with such large objects as INPUT_SNAPSHOT
int real_pos;
// history uses conveyor of snapshots (vector with fixed size) to aviod resizing which is awfully expensive with such large objects as SNAPSHOT
if (history_cursor_pos+1 >= history_size)
{
// reached the end of available history_size - move history_start_pos (thus deleting oldest snapshot)
@ -203,47 +201,25 @@ void INPUT_HISTORY::AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp)
{
// didn't reach the end of history yet
history_cursor_pos++;
if (history_cursor_pos < history_total_items)
{
// overwrite old snapshot
real_pos = (history_start_pos + history_cursor_pos) % history_size;
// compare with the snapshot we're going to overwrite, if it's different then truncate history after this item
if (input_snapshots[real_pos].checkDiff(inp) || input_snapshots[real_pos].my_markers.checkMarkersDiff(inp.my_markers))
{
history_total_items = history_cursor_pos+1;
UpdateHistoryList();
} else
{
// it's not different - don't truncate history, but break the chain of coherent snapshots
for (int i = history_cursor_pos+1; i < history_total_items; ++i)
{
real_pos = (history_start_pos + i) % history_size;
input_snapshots[real_pos].coherent = false;
}
}
} else
{
// add new snapshot
history_total_items = history_cursor_pos+1;
UpdateHistoryList();
}
history_total_items = history_cursor_pos+1;
UpdateHistoryList();
}
// write snapshot
real_pos = (history_start_pos + history_cursor_pos) % history_size;
input_snapshots[real_pos] = inp;
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
snapshots[real_pos] = inp;
RedrawHistoryList();
}
// returns frame of first actual change
int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end)
int HISTORY::RegisterChanges(int mod_type, int start, int end)
{
// create new input shanshot
INPUT_SNAPSHOT inp;
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = mod_type;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(input_snapshots[real_pos], start, end);
int first_changes = inp.findFirstChange(snapshots[real_pos], start, end);
if (first_changes >= 0)
{
// differences found
@ -264,7 +240,6 @@ int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end)
case MODTYPE_INSERT:
case MODTYPE_DELETE:
case MODTYPE_PASTE:
case MODTYPE_PASTEINSERT:
case MODTYPE_CLONE:
{
// for these changes user prefers to see frame of attempted change (selection beginning), not frame of actual differences
@ -290,14 +265,11 @@ int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end)
switch (mod_type)
{
case MODTYPE_DELETE:
inp.inheritHotChanges_DeleteSelection(&input_snapshots[real_pos]);
inp.inheritHotChanges_DeleteSelection(&snapshots[real_pos]);
break;
case MODTYPE_INSERT:
case MODTYPE_CLONE:
inp.inheritHotChanges_InsertSelection(&input_snapshots[real_pos]);
break;
case MODTYPE_PASTEINSERT:
inp.inheritHotChanges_PasteInsert(&input_snapshots[real_pos]);
inp.inheritHotChanges_InsertSelection(&snapshots[real_pos]);
break;
case MODTYPE_CHANGE:
case MODTYPE_SET:
@ -305,24 +277,53 @@ int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end)
case MODTYPE_CLEAR:
case MODTYPE_CUT:
case MODTYPE_PASTE:
inp.inheritHotChanges(&input_snapshots[real_pos]);
inp.fillHotChanges(input_snapshots[real_pos], first_changes, end);
inp.inheritHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], first_changes, end);
break;
case MODTYPE_TRUNCATE:
inp.copyHotChanges(&input_snapshots[real_pos]);
inp.copyHotChanges(&snapshots[real_pos]);
// do not add new hotchanges and do not fade old hotchanges, because there was nothing added
break;
}
}
AddInputSnapshotToHistory(inp);
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
}
return first_changes;
}
void INPUT_HISTORY::RegisterMarkersChange(int mod_type, int start, int end)
int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
{
// create new input shanshot
INPUT_SNAPSHOT inp;
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = MODTYPE_PASTEINSERT;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(snapshots[real_pos], start);
if (first_changes >= 0)
{
// differences found
// fill description:
strcat(inp.description, modCaptions[inp.mod_type]);
// for PasteInsert user prefers to see frame of attempted change (selection beginning), not frame of actual differences
inp.jump_frame = start;
// add upper frame to description
char framenum[11];
_itoa(start, framenum, 10);
strcat(inp.description, " ");
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
inp.inheritHotChanges_PasteInsert(&snapshots[real_pos], inserted_set);
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
}
return first_changes;
}
void HISTORY::RegisterMarkersChange(int mod_type, int start, int end)
{
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = mod_type;
// fill description:
@ -341,14 +342,14 @@ void INPUT_HISTORY::RegisterMarkersChange(int mod_type, int start, int end)
}
if (taseditor_config.enable_hot_changes)
inp.copyHotChanges(&GetCurrentSnapshot());
AddInputSnapshotToHistory(inp);
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
project.SetProjectChanged();
}
void INPUT_HISTORY::RegisterBranching(int mod_type, int first_change, int slot)
void HISTORY::RegisterBranching(int mod_type, int first_change, int slot)
{
// create new input snapshot
INPUT_SNAPSHOT inp;
// create new snapshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
// fill description: modification type + time of the Branch
inp.mod_type = mod_type;
@ -375,25 +376,25 @@ void INPUT_HISTORY::RegisterBranching(int mod_type, int first_change, int slot)
inp.copyHotChanges(&GetCurrentSnapshot());
}
}
AddInputSnapshotToHistory(inp);
AddSnapshotToHistory(inp);
}
void INPUT_HISTORY::RegisterRecording(int frame_of_change)
void HISTORY::RegisterRecording(int frame_of_change)
{
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
INPUT_SNAPSHOT inp;
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.fillJoypadsDiff(input_snapshots[real_pos], frame_of_change);
inp.fillJoypadsDiff(snapshots[real_pos], frame_of_change);
inp.mod_type = MODTYPE_RECORD;
strcat(inp.description, modCaptions[MODTYPE_RECORD]);
char framenum[11];
// check if current snapshot is also Recording and maybe it is consecutive recording
if (taseditor_config.combine_consecutive_rec
&& input_snapshots[real_pos].mod_type == MODTYPE_RECORD // a) also Recording
&& input_snapshots[real_pos].rec_end_frame+1 == frame_of_change // b) consecutive
&& input_snapshots[real_pos].rec_joypad_diff_bits == inp.rec_joypad_diff_bits) // c) recorded same set of joysticks
&& snapshots[real_pos].mod_type == MODTYPE_RECORD // a) also Recording
&& snapshots[real_pos].rec_end_frame+1 == frame_of_change // b) consecutive
&& snapshots[real_pos].rec_joypad_diff_bits == inp.rec_joypad_diff_bits) // c) recorded same set of joysticks
{
// clone this snapshot and continue chain of recorded frames
inp.jump_frame = input_snapshots[real_pos].jump_frame;
inp.jump_frame = snapshots[real_pos].jump_frame;
inp.rec_end_frame = frame_of_change;
// add info which joypads were affected
int num = joysticks_per_frame[inp.input_type];
@ -414,11 +415,11 @@ void INPUT_HISTORY::RegisterRecording(int frame_of_change)
// set hotchanges
if (taseditor_config.enable_hot_changes)
{
inp.copyHotChanges(&input_snapshots[real_pos]);
inp.fillHotChanges(input_snapshots[real_pos], frame_of_change, frame_of_change);
inp.copyHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], frame_of_change, frame_of_change);
}
// replace current snapshot with this cloned snapshot and truncate history here
input_snapshots[real_pos] = inp;
snapshots[real_pos] = inp;
history_total_items = history_cursor_pos+1;
UpdateHistoryList();
RedrawHistoryList();
@ -442,21 +443,21 @@ void INPUT_HISTORY::RegisterRecording(int frame_of_change)
// set hotchanges
if (taseditor_config.enable_hot_changes)
{
inp.inheritHotChanges(&input_snapshots[real_pos]);
inp.fillHotChanges(input_snapshots[real_pos], frame_of_change, frame_of_change);
inp.inheritHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], frame_of_change, frame_of_change);
}
AddInputSnapshotToHistory(inp);
AddSnapshotToHistory(inp);
}
bookmarks.ChangesMadeSinceBranch();
}
void INPUT_HISTORY::RegisterImport(MovieData& md, char* filename)
void HISTORY::RegisterImport(MovieData& md, char* filename)
{
// create new input snapshot
INPUT_SNAPSHOT inp;
// create new snapshot
SNAPSHOT inp;
inp.init(md, taseditor_config.enable_hot_changes, GetInputType(currMovieData));
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(input_snapshots[real_pos]);
int first_changes = inp.findFirstChange(snapshots[real_pos]);
if (first_changes >= 0)
{
// differences found
@ -470,9 +471,9 @@ void INPUT_HISTORY::RegisterImport(MovieData& md, char* filename)
if (taseditor_config.enable_hot_changes)
{
// do not inherit old hotchanges, because imported input (most likely) doesn't have direct connection with recent edits, so old hotchanges are irrelevant and should not be copied
inp.fillHotChanges(input_snapshots[real_pos], first_changes);
inp.fillHotChanges(snapshots[real_pos], first_changes);
}
AddInputSnapshotToHistory(inp);
AddSnapshotToHistory(inp);
inp.toMovie(currMovieData);
list.update();
bookmarks.ChangesMadeSinceBranch();
@ -483,8 +484,72 @@ void INPUT_HISTORY::RegisterImport(MovieData& md, char* filename)
MessageBox(taseditor_window.hwndTasEditor, "Imported movie has the same input.\nNo changes were made.", "TAS Editor", MB_OK);
}
}
int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDeletion_was_made)
{
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = MODTYPE_LUA_CHANGE;
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(snapshots[real_pos], start);
if (first_changes >= 0)
{
// differences found
// fill description:
if (name[0])
{
// custom name of operation
strcat(inp.description, LuaCaptionPrefix);
strncat(inp.description, name, LUACHANGES_NAME_MAX_LEN);
} else
{
// default name
strcat(inp.description, modCaptions[inp.mod_type]);
}
inp.jump_frame = first_changes;
// add upper frame to description
char framenum[11];
_itoa(first_changes, framenum, 10);
strcat(inp.description, " ");
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
{
if (InsertionDeletion_was_made)
{
// do it hard way: take old hot_changes and insert/delete rows to create a snapshot that is comparable to inp
if (inp.input_type == snapshots[real_pos].input_type)
{
// create temp copy of current snapshot (we need it as a container for hot_changes)
SNAPSHOT hotchanges_snapshot = snapshots[real_pos];
if (hotchanges_snapshot.has_hot_changes)
{
hotchanges_snapshot.FadeHotChanges();
} else
{
hotchanges_snapshot.has_hot_changes = true;
hotchanges_snapshot.hot_changes.resize(joysticks_per_frame[inp.input_type] * hotchanges_snapshot.size * HOTCHANGE_BYTES_PER_JOY);
}
// insert/delete frames in hotchanges_snapshot, so that it will be the same size as inp
taseditor_lua.InsertDelete_rows_to_Snaphot(hotchanges_snapshot);
inp.copyHotChanges(&hotchanges_snapshot);
inp.fillHotChanges(hotchanges_snapshot, first_changes);
}
} else
{
// easy way: inp.size is equal to currentsnapshot.size, so we can simply inherit hotchanges
inp.inheritHotChanges(&snapshots[real_pos]);
inp.fillHotChanges(snapshots[real_pos], first_changes);
}
}
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
}
return first_changes;
}
void INPUT_HISTORY::save(EMUFILE *os, bool really_save)
void HISTORY::save(EMUFILE *os, bool really_save)
{
if (really_save)
{
@ -498,7 +563,7 @@ void INPUT_HISTORY::save(EMUFILE *os, bool really_save)
for (int i = 0; i < history_total_items; ++i)
{
real_pos = (history_start_pos + i) % history_size;
input_snapshots[real_pos].save(os);
snapshots[real_pos].save(os);
playback.SetProgressbar(i, history_total_items);
}
} else
@ -508,12 +573,12 @@ void INPUT_HISTORY::save(EMUFILE *os, bool really_save)
}
}
// returns true if couldn't load
bool INPUT_HISTORY::load(EMUFILE *is)
bool HISTORY::load(EMUFILE *is)
{
int i = -1;
INPUT_SNAPSHOT inp;
SNAPSHOT inp;
// delete old snapshots
input_snapshots.resize(history_size);
snapshots.resize(history_size);
// read "HISTORY" string
char save_id[HISTORY_ID_LEN];
if ((int)is->fread(save_id, HISTORY_ID_LEN) < HISTORY_ID_LEN) goto error;
@ -554,7 +619,7 @@ bool INPUT_HISTORY::load(EMUFILE *is)
// load snapshots
for (i = 0; i < history_total_items; ++i)
{
if (input_snapshots[i].load(is)) goto error;
if (snapshots[i].load(is)) goto error;
playback.SetProgressbar(i, history_total_items);
}
// skip redo snapshots if needed
@ -575,35 +640,30 @@ error:
return true;
}
// ----------------------------
void INPUT_HISTORY::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
void HISTORY::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
{
LVITEM& item = nmlvDispInfo->item;
if(item.mask & LVIF_TEXT)
strcpy(item.pszText, GetItemDesc(item.iItem));
}
LONG INPUT_HISTORY::CustomDraw(NMLVCUSTOMDRAW* msg)
LONG HISTORY::CustomDraw(NMLVCUSTOMDRAW* msg)
{
switch(msg->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT:
{
if (GetItemCoherence(msg->nmcd.dwItemSpec))
msg->clrText = HISTORY_NORMAL_COLOR;
else
msg->clrText = HISTORY_INCOHERENT_COLOR;
}
msg->clrText = HISTORY_NORMAL_COLOR;
default:
return CDRF_DODEFAULT;
}
}
void INPUT_HISTORY::Click(LPNMITEMACTIVATE info)
void HISTORY::Click(LPNMITEMACTIVATE info)
{
// jump to pointed input snapshot
// jump to pointed snapshot
int item = info->iItem;
if (item >= 0)
{
@ -619,7 +679,7 @@ void INPUT_HISTORY::Click(LPNMITEMACTIVATE info)
RedrawHistoryList();
}
void INPUT_HISTORY::UpdateHistoryList()
void HISTORY::UpdateHistoryList()
{
//update the number of items in the history list
int currLVItemCount = ListView_GetItemCount(hwndHistoryList);
@ -627,33 +687,29 @@ void INPUT_HISTORY::UpdateHistoryList()
ListView_SetItemCountEx(hwndHistoryList, history_total_items, LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL);
}
void INPUT_HISTORY::RedrawHistoryList()
void HISTORY::RedrawHistoryList()
{
ListView_SetItemState(hwndHistoryList, history_cursor_pos, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
ListView_EnsureVisible(hwndHistoryList, history_cursor_pos, FALSE);
InvalidateRect(hwndHistoryList, 0, FALSE);
}
// ----------------------------
INPUT_SNAPSHOT& INPUT_HISTORY::GetCurrentSnapshot()
SNAPSHOT& HISTORY::GetCurrentSnapshot()
{
return input_snapshots[(history_start_pos + history_cursor_pos) % history_size];
return snapshots[(history_start_pos + history_cursor_pos) % history_size];
}
INPUT_SNAPSHOT& INPUT_HISTORY::GetNextToCurrentSnapshot()
SNAPSHOT& HISTORY::GetNextToCurrentSnapshot()
{
if (history_cursor_pos < history_total_items)
return input_snapshots[(history_start_pos + history_cursor_pos + 1) % history_size];
return snapshots[(history_start_pos + history_cursor_pos + 1) % history_size];
else
return input_snapshots[(history_start_pos + history_cursor_pos) % history_size];
return snapshots[(history_start_pos + history_cursor_pos) % history_size];
}
char* INPUT_HISTORY::GetItemDesc(int pos)
char* HISTORY::GetItemDesc(int pos)
{
return input_snapshots[(history_start_pos + pos) % history_size].description;
return snapshots[(history_start_pos + pos) % history_size].description;
}
bool INPUT_HISTORY::GetItemCoherence(int pos)
{
return input_snapshots[(history_start_pos + pos) % history_size].coherent;
}
int INPUT_HISTORY::GetUndoHint()
int HISTORY::GetUndoHint()
{
if (show_undo_hint)
return undo_hint_pos;

View File

@ -46,14 +46,13 @@ enum
MODTYPE_LUA_CHANGE = 40,
};
#define HISTORY_NORMAL_COLOR 0x000000
#define HISTORY_INCOHERENT_COLOR 0x999999
#define HISTORY_ID_LEN 8
class INPUT_HISTORY
class HISTORY
{
public:
INPUT_HISTORY();
HISTORY();
void init();
void free();
void reset();
@ -66,18 +65,17 @@ public:
int redo();
int jump(int new_pos);
void AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp);
int RegisterChanges(int mod_type, int start = 0, int end =-1);
int RegisterPasteInsert(int start, SelectionFrames& inserted_set);
void RegisterMarkersChange(int mod_type, int start = 0, int end =-1);
void RegisterBranching(int mod_type, int first_change, int slot);
void RegisterRecording(int frame_of_change);
void RegisterImport(MovieData& md, char* filename);
int RegisterLuaChanges(const char* name, int start, bool InsertionDeletion_was_made);
INPUT_SNAPSHOT& GetCurrentSnapshot();
INPUT_SNAPSHOT& GetNextToCurrentSnapshot();
SNAPSHOT& GetCurrentSnapshot();
SNAPSHOT& GetNextToCurrentSnapshot();
char* GetItemDesc(int pos);
bool GetItemCoherence(int pos);
int GetUndoHint();
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo);
@ -90,7 +88,9 @@ public:
HWND hwndHistoryList;
private:
std::vector<INPUT_SNAPSHOT> input_snapshots;
void AddSnapshotToHistory(SNAPSHOT &inp);
std::vector<SNAPSHOT> snapshots;
int history_cursor_pos;
int history_start_pos;

View File

@ -1,90 +1,38 @@
//Implementation file of Markers class
#include "taseditor_project.h"
#include "../common.h"
#include "markers.h"
#include "zlib.h"
#include <Shlwapi.h> // for StrStrI
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern PLAYBACK playback;
extern TASEDITOR_SELECTION selection;
// resources
char markers_save_id[MARKERS_ID_LEN] = "MARKERS";
char markers_skipsave_id[MARKERS_ID_LEN] = "MARKERX";
char keywordDelimiters[] = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
MARKERS::MARKERS()
{
}
void MARKERS::init()
void MARKERS::save(EMUFILE *os)
{
reset();
}
void MARKERS::free()
{
markers_array.resize(0);
notes.resize(0);
}
void MARKERS::reset()
{
free();
notes.resize(1);
notes[0] = "Power on";
update();
}
void MARKERS::update()
{
if ((int)markers_array.size() < currMovieData.getNumRecords())
markers_array.resize(currMovieData.getNumRecords());
}
void MARKERS::save(EMUFILE *os, bool really_save)
{
if (really_save)
// write size
int size = markers_array.size();
write32le(size, os);
// compress and write array
int len = markers_array.size() * sizeof(int);
uLongf comprlen = (len>>9)+12 + len;
std::vector<uint8> cbuf(comprlen);
compress(&cbuf[0], &comprlen, (uint8*)&markers_array[0], len);
write32le(comprlen, os);
os->fwrite(&cbuf[0], comprlen);
// write notes
size = notes.size();
write32le(size, os);
for (int i = 0; i < size; ++i)
{
// write "MARKERS" string
os->fwrite(markers_save_id, MARKERS_ID_LEN);
// write size
int size = markers_array.size();
write32le(size, os);
// compress and write array
int len = markers_array.size() * sizeof(int);
uLongf comprlen = (len>>9)+12 + len;
std::vector<uint8> cbuf(comprlen);
compress(&cbuf[0], &comprlen, (uint8*)&markers_array[0], len);
write32le(comprlen, os);
os->fwrite(&cbuf[0], comprlen);
// write notes
size = notes.size();
write32le(size, os);
for (int i = 0; i < size; ++i)
{
len = notes[i].length() + 1;
if (len > MAX_NOTE_LEN) len = MAX_NOTE_LEN;
write32le(len, os);
os->fwrite(notes[i].c_str(), len);
}
} else
{
// write "MARKERX" string
os->fwrite(markers_skipsave_id, MARKERS_ID_LEN);
len = notes[i].length() + 1;
if (len > MAX_NOTE_LEN) len = MAX_NOTE_LEN;
write32le(len, os);
os->fwrite(notes[i].c_str(), len);
}
}
// returns true if couldn't load
bool MARKERS::load(EMUFILE *is)
{
// read "MARKERS" string
char save_id[MARKERS_ID_LEN];
if ((int)is->fread(save_id, MARKERS_ID_LEN) < MARKERS_ID_LEN) goto error;
if (!strcmp(markers_skipsave_id, save_id))
{
// string says to skip loading Markers
FCEU_printf("No markers in the file\n");
reset();
return false;
}
if (strcmp(markers_save_id, save_id)) goto error; // string is not valid
int size;
if (read32le(&size, is))
{
@ -92,12 +40,12 @@ bool MARKERS::load(EMUFILE *is)
// read and uncompress array
int comprlen, len;
uLongf destlen = size * sizeof(int);
if (!read32le(&comprlen, is)) goto error;
if (comprlen <= 0) goto error;
if (!read32le(&comprlen, is)) return true;
if (comprlen <= 0) return true;
std::vector<uint8> cbuf(comprlen);
if (is->fread(&cbuf[0], comprlen) != comprlen) goto error;
if (is->fread(&cbuf[0], comprlen) != comprlen) return true;
int e = uncompress((uint8*)&markers_array[0], &destlen, &cbuf[0], comprlen);
if (e != Z_OK && e != Z_BUF_ERROR) goto error;
if (e != Z_OK && e != Z_BUF_ERROR) return true;
// read notes
if (read32le(&size, is) && size >= 0)
{
@ -105,484 +53,36 @@ bool MARKERS::load(EMUFILE *is)
char temp_str[MAX_NOTE_LEN];
for (int i = 0; i < size; ++i)
{
if (!read32le(&len, is) || len < 0) goto error;
if ((int)is->fread(temp_str, len) < len) goto error;
if (!read32le(&len, is) || len < 0) return true;
if ((int)is->fread(temp_str, len) < len) return true;
notes[i] = temp_str;
}
// all ok
return false;
}
}
error:
FCEU_printf("Error loading markers\n");
reset();
return true;
}
bool MARKERS::skipLoad(EMUFILE *is)
{
// read "MARKERS" string
char save_id[MARKERS_ID_LEN];
if ((int)is->fread(save_id, MARKERS_ID_LEN) < MARKERS_ID_LEN) goto error;
if (!strcmp(markers_skipsave_id, save_id))
{
// string says to skip loading Markers
reset();
return false;
}
if (strcmp(markers_save_id, save_id)) goto error; // string is not valid
int size;
if (!(is->fseek(sizeof(int), SEEK_CUR)))
{
// read array
int comprlen, len;
if (!read32le(&comprlen, is)) goto error;
if (is->fseek(comprlen, SEEK_CUR) != 0) goto error;
if (!read32le(&comprlen, is)) return true;
if (is->fseek(comprlen, SEEK_CUR) != 0) return true;
// read notes
if (read32le(&size, is) && size >= 0)
{
for (int i = 0; i < size; ++i)
{
if (!read32le(&len, is) || len < 0) goto error;
if (is->fseek(len, SEEK_CUR) != 0) goto error;
if (!read32le(&len, is) || len < 0) return true;
if (is->fseek(len, SEEK_CUR) != 0) return true;
}
// all ok
return false;
}
}
error:
FCEU_printf("Error skiploading markers\n");
return true;
}
// ----------------------------------------------------------
void MARKERS::MakeCopy(MARKERS& source)
{
// provide references
source.CopyMarkersHere(markers_array, notes);
}
void MARKERS::CopyMarkersHere(std::vector<int>& array_for_markers, std::vector<std::string>& for_notes)
{
// copy data to provided arrays
array_for_markers = markers_array;
for_notes = notes;
}
void MARKERS::RestoreFromCopy(MARKERS& source, int until_frame)
{
if (until_frame >= 0)
{
// restore markers up to and including the frame
if ((int)markers_array.size()-1 <= until_frame)
{
// only copy head of source
source.CopyMarkersHere(markers_array, notes);
markers_array.resize(until_frame+1);
// find last marker
int last_marker = GetMarkerUp(until_frame);
// delete all notes foolowing the note of the last marker
notes.resize(last_marker+1);
} else
{
// combine head of source and tail of destination (old markers)
// 1 - head
std::vector<int> temp_markers_array;
std::vector<std::string> temp_notes;
source.CopyMarkersHere(temp_markers_array, temp_notes);
temp_markers_array.resize(until_frame+1);
// find last marker in temp_markers_array
int last_marker, frame;
for (frame = until_frame; frame >= 0; frame--)
if (temp_markers_array[frame]) break;
if (frame >= 0)
last_marker = temp_markers_array[frame];
else
last_marker = 0;
// delete all temp_notes foolowing the note of the last marker
temp_notes.resize(last_marker+1);
// 2 - tail
// delete all markers (and their notes) up to and including until_frame
//for (int i = until_frame; i >= 0; i--) // actually no need for that
// ClearMarker(i);
// 3 - combine head and tail (if there are actually markers left in the tail)
int size = markers_array.size();
temp_markers_array.resize(size);
for (int i = until_frame+1; i < size; ++i)
{
if (markers_array[i])
{
last_marker++;
temp_markers_array[i] = last_marker;
temp_notes.push_back(notes[markers_array[i]]);
}
}
// 4 - save result
markers_array = temp_markers_array;
notes = temp_notes;
}
} else
{
// frame not specified, consider this as "copy all"
MakeCopy(source);
}
}
// ----------------------------------------------------------
int MARKERS::GetMarkersSize()
{
return markers_array.size();
}
void MARKERS::SetMarkersSize(int new_size)
{
// if we are truncating, clear markers that are gonna be erased (so that obsolete notes will be erased too)
for (int i = markers_array.size() - 1; i >= new_size; i--)
if (markers_array[i])
ClearMarker(i);
markers_array.resize(new_size);
}
int MARKERS::GetMarker(int frame)
{
if (frame >= 0 && frame < (int)markers_array.size())
return markers_array[frame];
else
return 0;
}
// finds and returns # of Marker starting from start_frame and searching up
int MARKERS::GetMarkerUp(int start_frame)
{
if (start_frame >= (int)markers_array.size())
start_frame = markers_array.size() - 1;
for (; start_frame >= 0; start_frame--)
if (markers_array[start_frame]) return markers_array[start_frame];
return 0;
}
// finds frame where the Marker is set
int MARKERS::GetMarkerFrame(int marker_id)
{
for (int i = markers_array.size() - 1; i >= 0; i--)
if (markers_array[i] == marker_id) return i;
// didn't find
return -1;
}
// returns number of new marker
int MARKERS::SetMarker(int frame)
{
if (frame < 0)
return 0;
else if (frame >= (int)markers_array.size())
markers_array.resize(frame + 1);
else if (markers_array[frame])
return markers_array[frame];
int marker_num = GetMarkerUp(frame) + 1;
markers_array[frame] = marker_num;
if (taseditor_config.empty_marker_notes)
notes.insert(notes.begin() + marker_num, 1, "");
else
// copy previous marker note
notes.insert(notes.begin() + marker_num, 1, notes[marker_num - 1]);
// increase following markers' ids
int size = markers_array.size();
for (frame++; frame < size; ++frame)
if (markers_array[frame])
markers_array[frame]++;
return marker_num;
}
void MARKERS::ClearMarker(int frame)
{
if (markers_array[frame])
{
// erase corresponding note
notes.erase(notes.begin() + markers_array[frame]);
// erase marker
markers_array[frame] = 0;
// decrease following markers' ids
int size = markers_array.size();
for (frame++; frame < size; ++frame)
if (markers_array[frame])
markers_array[frame]--;
}
}
void MARKERS::ToggleMarker(int frame)
{
if (frame >= 0 && frame < (int)markers_array.size())
{
if (markers_array[frame])
ClearMarker(frame);
else
SetMarker(frame);
}
}
void MARKERS::EraseMarker(int frame)
{
// if there's a marker, first clear it
if (markers_array[frame])
ClearMarker(frame);
markers_array.erase(markers_array.begin() + frame);
}
void MARKERS::insertEmpty(int at, int frames)
{
if(at == -1)
{
markers_array.resize(markers_array.size() + frames);
} else
{
markers_array.insert(markers_array.begin() + at, frames, 0);
}
}
int MARKERS::GetNotesSize()
{
return notes.size();
}
std::string MARKERS::GetNote(int index)
{
if (index >= 0 && index < (int)notes.size())
return notes[index];
else return notes[0];
}
void MARKERS::SetNote(int index, const char* new_text)
{
if (index >= 0 && index < (int)notes.size())
notes[index] = new_text;
}
// ----------------------------------------------------------
// return true if any difference in markers_array is found, comparing to markers.markers_array
bool MARKERS::checkMarkersDiff(MARKERS& their_markers)
{
if (GetMarkersSize() != their_markers.GetMarkersSize()) return true;
if (GetNotesSize() != their_markers.GetNotesSize()) return true;
for (int i = markers_array.size()-1; i >= 0; i--)
{
if (markers_array[i] != their_markers.GetMarker(i))
return true;
else if (markers_array[i] && notes[markers_array[i]].compare(their_markers.GetNote(markers_array[i])))
return true;
}
// also check if there's difference between 0th notes
if (notes[0].compare(their_markers.GetNote(0)))
return true;
return false;
}
// return true only when difference is found before end frame (not including end frame)
bool MARKERS::checkMarkersDiff(MARKERS& their_markers, int end)
{
if (GetMarkersSize() != their_markers.GetMarkersSize() && (GetMarkersSize()-1 < end || their_markers.GetMarkersSize()-1 < end)) return true;
for (int i = end-1; i >= 0; i--)
{
if (markers_array[i] != their_markers.GetMarker(i))
return true;
else if (markers_array[i] && notes[markers_array[i]].compare(their_markers.GetNote(markers_array[i])))
return true;
}
return false;
}
// ------------------------------------------------------------------------------------
bool ordering(const std::pair<int, double>& d1, const std::pair<int, double>& d2)
{
return d1.second < d2.second;
}
void MARKERS::FindSimilar(int offset)
{
int i, t;
int sourceMarker = playback.shown_marker;
char sourceNote[MAX_NOTE_LEN];
strcpy(sourceNote, GetNote(sourceMarker).c_str());
// check if playback_marker_text is empty
if (!sourceNote[0])
{
MessageBox(taseditor_window.hwndTasEditor, "Marker Note under Playback cursor is empty!", "Find Similar Note", MB_OK);
return;
}
// check if there's at least one note (not counting zeroth note)
if (notes.size() <= 0)
{
MessageBox(taseditor_window.hwndTasEditor, "This project doesn't have any Markers!", "Find Similar Note", MB_OK);
return;
}
// 0 - divide source string into keywords
int totalSourceKeywords = 0;
char sourceKeywords[MAX_NUM_KEYWORDS][MAX_NOTE_LEN] = {0};
int current_line_pos = 0;
char sourceKeywordsLine[MAX_NUM_KEYWORDS] = {0};
char* pch;
// divide into tokens
pch = strtok(sourceNote, keywordDelimiters);
while (pch != NULL)
{
if (strlen(pch) >= KEYWORD_MIN_LEN)
{
// check if same keyword already appeared in the string
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (!_stricmp(sourceKeywords[t], pch)) break;
if (t < 0)
{
// save new keyword
strcpy(sourceKeywords[totalSourceKeywords], pch);
// also set its id into the line
sourceKeywordsLine[current_line_pos++] = totalSourceKeywords + 1;
totalSourceKeywords++;
} else
{
// same keyword found
sourceKeywordsLine[current_line_pos++] = t + 1;
}
}
pch = strtok(NULL, keywordDelimiters);
}
// we found the line (sequence) of keywords
sourceKeywordsLine[current_line_pos] = 0;
if (!totalSourceKeywords)
{
MessageBox(taseditor_window.hwndTasEditor, "Marker Note under Playback cursor doesn't have keywords!", "Find Similar Note", MB_OK);
return;
}
// 1 - find how frequently each keyword appears in notes
std::vector<int> keywordFound(totalSourceKeywords);
char checkedNote[MAX_NOTE_LEN];
for (i = notes.size() - 1; i > 0; i--)
{
if (i != sourceMarker)
{
strcpy(checkedNote, notes[i].c_str());
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (StrStrI(checkedNote, sourceKeywords[t]))
keywordFound[t]++;
}
}
// findmax
int maxFound = 0;
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (maxFound < keywordFound[t])
maxFound = keywordFound[t];
// and then calculate weight of each keyword: the more often it appears in markers, the less weight it has
std::vector<double> keywordWeight(totalSourceKeywords);
for (t = totalSourceKeywords - 1; t >= 0; t--)
keywordWeight[t] = KEYWORD_WEIGHT_BASE + KEYWORD_WEIGHT_FACTOR * (keywordFound[t] / (double)maxFound);
// start accumulating priorities
std::vector<std::pair<int, double>> notePriority(notes.size());
// 2 - find keywords in notes (including cases when keyword appears inside another word)
for (i = notePriority.size() - 1; i > 0; i--)
{
notePriority[i].first = i;
if (i != sourceMarker)
{
strcpy(checkedNote, notes[i].c_str());
for (t = totalSourceKeywords - 1; t >= 0; t--)
{
if (StrStrI(checkedNote, sourceKeywords[t]))
notePriority[i].second += KEYWORD_CASEINSENTITIVE_BONUS_PER_CHAR * keywordWeight[t] * strlen(sourceKeywords[t]);
if (strstr(checkedNote, sourceKeywords[t]))
notePriority[i].second += KEYWORD_CASESENTITIVE_BONUS_PER_CHAR * keywordWeight[t] * strlen(sourceKeywords[t]);
}
}
}
// 3 - search sequences of keywords from all other notes
current_line_pos = 0;
char checkedKeywordsLine[MAX_NUM_KEYWORDS] = {0};
int keyword_id;
for (i = notes.size() - 1; i > 0; i--)
{
if (i != sourceMarker)
{
strcpy(checkedNote, notes[i].c_str());
// divide into tokens
pch = strtok(checkedNote, keywordDelimiters);
while (pch != NULL)
{
if (strlen(pch) >= KEYWORD_MIN_LEN)
{
// check if the keyword is one of sourceKeywords
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (!_stricmp(sourceKeywords[t], pch)) break;
if (t >= 0)
{
// the keyword is one of sourceKeywords - set its id into the line
checkedKeywordsLine[current_line_pos++] = t + 1;
} else
{
// found keyword that doesn't appear in sourceNote, give penalty
notePriority[i].second -= KEYWORD_PENALTY_FOR_STRANGERS * strlen(pch);
// since the keyword breaks our sequence of coincident keywords, check if that sequence is similar to sourceKeywordsLine
if (current_line_pos >= KEYWORDS_LINE_MIN_SEQUENCE)
{
checkedKeywordsLine[current_line_pos] = 0;
// search checkedKeywordsLine in sourceKeywordsLine
if (strstr(sourceKeywordsLine, checkedKeywordsLine))
{
// found same sequence of keywords! add priority to this checkedNote
for (t = current_line_pos - 1; t >= 0; t--)
{
// add bonus for every keyword in the sequence
keyword_id = checkedKeywordsLine[t] - 1;
notePriority[i].second += current_line_pos * KEYWORD_SEQUENCE_BONUS_PER_CHAR * keywordWeight[keyword_id] * strlen(sourceKeywords[keyword_id]);
}
}
}
// clear checkedKeywordsLine
memset(checkedKeywordsLine, 0, MAX_NUM_KEYWORDS);
current_line_pos = 0;
}
}
pch = strtok(NULL, keywordDelimiters);
}
// finished dividing into tokens
if (current_line_pos >= KEYWORDS_LINE_MIN_SEQUENCE)
{
checkedKeywordsLine[current_line_pos] = 0;
// search checkedKeywordsLine in sourceKeywordsLine
if (strstr(sourceKeywordsLine, checkedKeywordsLine))
{
// found same sequence of keywords! add priority to this checkedNote
for (t = current_line_pos - 1; t >= 0; t--)
{
// add bonus for every keyword in the sequence
keyword_id = checkedKeywordsLine[t] - 1;
notePriority[i].second += current_line_pos * KEYWORD_SEQUENCE_BONUS_PER_CHAR * keywordWeight[keyword_id] * strlen(sourceKeywords[keyword_id]);
}
}
}
// clear checkedKeywordsLine
memset(checkedKeywordsLine, 0, MAX_NUM_KEYWORDS);
current_line_pos = 0;
}
}
// 4 - sort notePriority by second member of the pair
std::sort(notePriority.begin(), notePriority.end(), ordering);
/*
// debug trace
FCEU_printf("\n\n\n\n\n\n\n\n\n\n");
for (t = totalSourceKeywords - 1; t >= 0; t--)
FCEU_printf("Keyword: %s, %d, %f\n", sourceKeywords[t], keywordFound[t], keywordWeight[t]);
for (i = notePriority.size() - 1; i > 0; i--)
{
int marker_id = notePriority[i].first;
FCEU_printf("Result: %s, %d, %f\n", notes[marker_id].c_str(), marker_id, notePriority[i].second);
}
*/
// Send selection to the marker found
int index = notePriority.size()-1 - offset;
if (index >= 0 && notePriority[index].second >= MIN_PRIORITY_TRESHOLD)
{
int marker_id = notePriority[index].first;
int frame = GetMarkerFrame(marker_id);
if (frame >= 0)
selection.JumpToFrame(frame);
} else
{
if (offset)
MessageBox(taseditor_window.hwndTasEditor, "Could not find more Notes similar to Marker Note under Playback cursor!", "Find Similar Note", MB_OK);
else
MessageBox(taseditor_window.hwndTasEditor, "Could not find anything similar to Marker Note under Playback cursor!", "Find Similar Note", MB_OK);
}
}

View File

@ -1,63 +1,18 @@
//Specification file for Markers class
#define MARKERS_ID_LEN 8
#define MAX_NOTE_LEN 100
// constants for "Find Similar Note" algorithm (may need finetuning)
#define KEYWORD_MIN_LEN 2
#define MAX_NUM_KEYWORDS (MAX_NOTE_LEN / (KEYWORD_MIN_LEN+1)) + 1
#define KEYWORD_WEIGHT_BASE 2.0
#define KEYWORD_WEIGHT_FACTOR -1.0
#define KEYWORD_CASEINSENTITIVE_BONUS_PER_CHAR 1.0 // these two should be small, because they also work when keyword is inside another keyword, giving irrelevant results
#define KEYWORD_CASESENTITIVE_BONUS_PER_CHAR 1.0
#define KEYWORD_SEQUENCE_BONUS_PER_CHAR 5.0
#define KEYWORD_PENALTY_FOR_STRANGERS 0.2
#define KEYWORDS_LINE_MIN_SEQUENCE 1
#define MIN_PRIORITY_TRESHOLD 5.0
class MARKERS
{
public:
MARKERS();
void init();
void free();
void reset();
void update();
void save(EMUFILE *os, bool really_save = true);
void save(EMUFILE *os);
bool load(EMUFILE *is);
bool skipLoad(EMUFILE *is);
void MakeCopy(MARKERS& source);
void CopyMarkersHere(std::vector<int>& array_for_markers, std::vector<std::string>& for_notes);
void RestoreFromCopy(MARKERS& source, int until_frame = -1);
int GetMarkersSize();
void SetMarkersSize(int new_size);
int GetMarker(int frame);
int GetMarkerUp(int start_frame);
int GetMarkerFrame(int marker_id);
int SetMarker(int frame);
void ClearMarker(int frame);
void ToggleMarker(int frame);
void EraseMarker(int frame);
void insertEmpty(int at, int frames);
int GetNotesSize();
std::string GetNote(int index);
void SetNote(int index, const char* new_text);
bool checkMarkersDiff(MARKERS& their_markers);
bool checkMarkersDiff(MARKERS& their_markers, int end);
void FindSimilar(int offset);
private:
std::vector<int> markers_array; // Format: 0th = marker num (id) for frame 0, 1st = marker num for frame 1, ...
std::vector<std::string> notes; // Format: 0th - note for intro (Marker 0), 1st - note for Marker1, 2nd - note for Marker2, ...
private:
};

View File

@ -0,0 +1,714 @@
//Implementation file of Markers_manager class
#include "taseditor_project.h"
#include <Shlwapi.h> // for StrStrI
#pragma comment(lib, "Shlwapi.lib")
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern PLAYBACK playback;
extern TASEDITOR_SELECTION selection;
extern HISTORY history;
// resources
char markers_save_id[MARKERS_ID_LEN] = "MARKERS";
char markers_skipsave_id[MARKERS_ID_LEN] = "MARKERX";
char keywordDelimiters[] = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
MARKERS_MANAGER::MARKERS_MANAGER()
{
memset(findnote_string, 0, MAX_NOTE_LEN);
}
void MARKERS_MANAGER::init()
{
reset();
}
void MARKERS_MANAGER::free()
{
markers.markers_array.resize(0);
markers.notes.resize(0);
}
void MARKERS_MANAGER::reset()
{
free();
marker_note_edit = MARKER_NOTE_EDIT_NONE;
search_similar_marker = 0;
markers.notes.resize(1);
markers.notes[0] = "Power on";
update();
}
void MARKERS_MANAGER::update()
{
if ((int)markers.markers_array.size() < currMovieData.getNumRecords())
markers.markers_array.resize(currMovieData.getNumRecords());
}
void MARKERS_MANAGER::save(EMUFILE *os, bool really_save)
{
if (really_save)
{
// write "MARKERS" string
os->fwrite(markers_save_id, MARKERS_ID_LEN);
markers.save(os);
} else
{
// write "MARKERX" string, meaning that markers are not saved
os->fwrite(markers_skipsave_id, MARKERS_ID_LEN);
}
}
// returns true if couldn't load
bool MARKERS_MANAGER::load(EMUFILE *is)
{
// read "MARKERS" string
char save_id[MARKERS_ID_LEN];
if ((int)is->fread(save_id, MARKERS_ID_LEN) < MARKERS_ID_LEN) goto error;
if (!strcmp(markers_skipsave_id, save_id))
{
// string says to skip loading Markers
FCEU_printf("No markers in the file\n");
reset();
return false;
}
if (strcmp(markers_save_id, save_id)) goto error; // string is not valid
if (markers.load(is)) goto error;
// all ok
return false;
error:
FCEU_printf("Error loading markers\n");
reset();
return true;
}
// -----------------------------------------------------------------------------------------
int MARKERS_MANAGER::GetMarkersSize()
{
return markers.markers_array.size();
}
void MARKERS_MANAGER::SetMarkersSize(int new_size)
{
// if we are truncating, clear markers that are gonna be erased (so that obsolete notes will be erased too)
for (int i = markers.markers_array.size() - 1; i >= new_size; i--)
if (markers.markers_array[i])
ClearMarker(i);
markers.markers_array.resize(new_size);
}
int MARKERS_MANAGER::GetMarker(int frame)
{
if (frame >= 0 && frame < (int)markers.markers_array.size())
return markers.markers_array[frame];
else
return 0;
}
// finds and returns # of Marker starting from start_frame and searching up
int MARKERS_MANAGER::GetMarkerUp(int start_frame)
{
if (start_frame >= (int)markers.markers_array.size())
start_frame = markers.markers_array.size() - 1;
for (; start_frame >= 0; start_frame--)
if (markers.markers_array[start_frame]) return markers.markers_array[start_frame];
return 0;
}
// special version of the function
int MARKERS_MANAGER::GetMarkerUp(MARKERS& target_markers, int start_frame)
{
if (start_frame >= (int)target_markers.markers_array.size())
start_frame = target_markers.markers_array.size() - 1;
for (; start_frame >= 0; start_frame--)
if (target_markers.markers_array[start_frame]) return target_markers.markers_array[start_frame];
return 0;
}
// finds frame where the Marker is set
int MARKERS_MANAGER::GetMarkerFrame(int marker_id)
{
for (int i = markers.markers_array.size() - 1; i >= 0; i--)
if (markers.markers_array[i] == marker_id) return i;
// didn't find
return -1;
}
// returns number of new marker
int MARKERS_MANAGER::SetMarker(int frame)
{
if (frame < 0)
return 0;
else if (frame >= (int)markers.markers_array.size())
markers.markers_array.resize(frame + 1);
else if (markers.markers_array[frame])
return markers.markers_array[frame];
int marker_num = GetMarkerUp(frame) + 1;
markers.markers_array[frame] = marker_num;
if (taseditor_config.empty_marker_notes)
markers.notes.insert(markers.notes.begin() + marker_num, 1, "");
else
// copy previous marker note
markers.notes.insert(markers.notes.begin() + marker_num, 1, markers.notes[marker_num - 1]);
// increase following markers' ids
int size = markers.markers_array.size();
for (frame++; frame < size; ++frame)
if (markers.markers_array[frame])
markers.markers_array[frame]++;
return marker_num;
}
void MARKERS_MANAGER::ClearMarker(int frame)
{
if (markers.markers_array[frame])
{
// erase corresponding note
markers.notes.erase(markers.notes.begin() + markers.markers_array[frame]);
// erase marker
markers.markers_array[frame] = 0;
// decrease following markers' ids
int size = markers.markers_array.size();
for (frame++; frame < size; ++frame)
if (markers.markers_array[frame])
markers.markers_array[frame]--;
}
}
void MARKERS_MANAGER::ToggleMarker(int frame)
{
if (frame >= 0 && frame < (int)markers.markers_array.size())
{
if (markers.markers_array[frame])
ClearMarker(frame);
else
SetMarker(frame);
}
}
void MARKERS_MANAGER::EraseMarker(int frame)
{
if (frame < (int)markers.markers_array.size())
{
// if there's a marker, first clear it
if (markers.markers_array[frame])
ClearMarker(frame);
markers.markers_array.erase(markers.markers_array.begin() + frame);
}
}
void MARKERS_MANAGER::insertEmpty(int at, int frames)
{
if(at == -1)
{
markers.markers_array.resize(markers.markers_array.size() + frames);
} else
{
markers.markers_array.insert(markers.markers_array.begin() + at, frames, 0);
}
}
int MARKERS_MANAGER::GetNotesSize()
{
return markers.notes.size();
}
std::string MARKERS_MANAGER::GetNote(int index)
{
if (index >= 0 && index < (int)markers.notes.size())
return markers.notes[index];
else
return markers.notes[0];
}
// special version of the function
std::string MARKERS_MANAGER::GetNote(MARKERS& target_markers, int index)
{
if (index >= 0 && index < (int)target_markers.notes.size())
return target_markers.notes[index];
else
return target_markers.notes[0];
}
void MARKERS_MANAGER::SetNote(int index, const char* new_text)
{
if (index >= 0 && index < (int)markers.notes.size())
markers.notes[index] = new_text;
}
// ---------------------------------------------------------------------------------------
void MARKERS_MANAGER::MakeCopyTo(MARKERS& destination)
{
destination.markers_array = markers.markers_array;
destination.notes = markers.notes;
}
void MARKERS_MANAGER::RestoreFromCopy(MARKERS& source, int until_frame)
{
if (until_frame >= 0)
{
// restore markers up to and not including the frame
if ((int)markers.markers_array.size() <= until_frame)
{
// only copy head of source
markers.markers_array = source.markers_array;
markers.markers_array.resize(until_frame);
markers.notes = source.notes;
// find last marker
int last_marker = GetMarkerUp(until_frame-1);
// delete all notes following the note of the last marker
markers.notes.resize(last_marker+1);
} else
{
// combine head of source and tail of destination (old markers)
// 1 - head = part of source markers
std::vector<int> temp_markers_array;
std::vector<std::string> temp_notes;
temp_markers_array = source.markers_array;
temp_markers_array.resize(until_frame);
temp_notes = source.notes;
// find last marker in temp_markers_array
int last_marker, frame;
for (frame = until_frame-1; frame >= 0; frame--)
if (temp_markers_array[frame]) break;
if (frame >= 0)
last_marker = temp_markers_array[frame];
else
last_marker = 0;
// delete all temp_notes foolowing the note of the last marker
temp_notes.resize(last_marker+1);
// 2 - tail = part of old (current) markers
// delete all markers (and their notes) up to and not including until_frame
//for (int i = until_frame-1; i >= 0; i--) // actually no need for that
// ClearMarker(i);
// 3 - combine head and tail (if there are actually markers left in the tail)
int size = markers.markers_array.size();
temp_markers_array.resize(size);
for (int i = until_frame; i < size; ++i)
{
if (markers.markers_array[i])
{
last_marker++; // make new id for old marker
temp_markers_array[i] = last_marker;
temp_notes.push_back(markers.notes[markers.markers_array[i]]); // take note from old markers and add it to the end of the head
}
}
// 4 - save result
markers.markers_array = temp_markers_array;
markers.notes = temp_notes;
}
} else
{
// end frame was not specified, consider this as "copy all"
markers.markers_array = source.markers_array;
markers.notes = source.notes;
}
}
// return true if any difference in markers_array is found, comparing to markers.markers_array
bool MARKERS_MANAGER::checkMarkersDiff(MARKERS& their_markers)
{
if (GetMarkersSize() != their_markers.markers_array.size()) return true;
if (GetNotesSize() != their_markers.notes.size()) return true;
for (int i = markers.markers_array.size()-1; i >= 0; i--)
{
if (markers.markers_array[i] != their_markers.markers_array[i])
return true;
else if (markers.markers_array[i] && markers.notes[markers.markers_array[i]].compare(their_markers.notes[their_markers.markers_array[i]]))
return true;
}
// also check if there's difference between 0th notes
if (markers.notes[0].compare(their_markers.notes[0]))
return true;
return false;
}
// return true only when difference is found before end frame (not including end frame)
bool MARKERS_MANAGER::checkMarkersDiff(MARKERS& their_markers, int end)
{
if (end < 0)
return checkMarkersDiff(their_markers);
if (markers.markers_array.size() != their_markers.markers_array.size() && ((int)markers.markers_array.size()-1 < end || (int)their_markers.markers_array.size()-1 < end)) return true;
for (int i = end-1; i >= 0; i--)
{
if (markers.markers_array[i] != their_markers.markers_array[i])
return true;
else if (markers.markers_array[i] && markers.notes[markers.markers_array[i]].compare(their_markers.notes[their_markers.markers_array[i]]))
return true;
}
return false;
}
// ------------------------------------------------------------------------------------
// ordering function, used by std::sort
bool ordering(const std::pair<int, double>& d1, const std::pair<int, double>& d2)
{
return d1.second < d2.second;
}
void MARKERS_MANAGER::FindSimilar()
{
search_similar_marker = 0;
FindNextSimilar();
}
void MARKERS_MANAGER::FindNextSimilar()
{
int i, t;
int sourceMarker = playback.shown_marker;
char sourceNote[MAX_NOTE_LEN];
strcpy(sourceNote, GetNote(sourceMarker).c_str());
// check if playback_marker_text is empty
if (!sourceNote[0])
{
MessageBox(taseditor_window.hwndTasEditor, "Marker Note under Playback cursor is empty!", "Find Similar Note", MB_OK);
return;
}
// check if there's at least one note (not counting zeroth note)
if (markers.notes.size() <= 0)
{
MessageBox(taseditor_window.hwndTasEditor, "This project doesn't have any Markers!", "Find Similar Note", MB_OK);
return;
}
// 0 - divide source string into keywords
int totalSourceKeywords = 0;
char sourceKeywords[MAX_NUM_KEYWORDS][MAX_NOTE_LEN] = {0};
int current_line_pos = 0;
char sourceKeywordsLine[MAX_NUM_KEYWORDS] = {0};
char* pch;
// divide into tokens
pch = strtok(sourceNote, keywordDelimiters);
while (pch != NULL)
{
if (strlen(pch) >= KEYWORD_MIN_LEN)
{
// check if same keyword already appeared in the string
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (!_stricmp(sourceKeywords[t], pch)) break;
if (t < 0)
{
// save new keyword
strcpy(sourceKeywords[totalSourceKeywords], pch);
// also set its id into the line
sourceKeywordsLine[current_line_pos++] = totalSourceKeywords + 1;
totalSourceKeywords++;
} else
{
// same keyword found
sourceKeywordsLine[current_line_pos++] = t + 1;
}
}
pch = strtok(NULL, keywordDelimiters);
}
// we found the line (sequence) of keywords
sourceKeywordsLine[current_line_pos] = 0;
if (!totalSourceKeywords)
{
MessageBox(taseditor_window.hwndTasEditor, "Marker Note under Playback cursor doesn't have keywords!", "Find Similar Note", MB_OK);
return;
}
// 1 - find how frequently each keyword appears in notes
std::vector<int> keywordFound(totalSourceKeywords);
char checkedNote[MAX_NOTE_LEN];
for (i = markers.notes.size() - 1; i > 0; i--)
{
if (i != sourceMarker)
{
strcpy(checkedNote, markers.notes[i].c_str());
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (StrStrI(checkedNote, sourceKeywords[t]))
keywordFound[t]++;
}
}
// findmax
int maxFound = 0;
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (maxFound < keywordFound[t])
maxFound = keywordFound[t];
// and then calculate weight of each keyword: the more often it appears in markers, the less weight it has
std::vector<double> keywordWeight(totalSourceKeywords);
for (t = totalSourceKeywords - 1; t >= 0; t--)
keywordWeight[t] = KEYWORD_WEIGHT_BASE + KEYWORD_WEIGHT_FACTOR * (keywordFound[t] / (double)maxFound);
// start accumulating priorities
std::vector<std::pair<int, double>> notePriority(markers.notes.size());
// 2 - find keywords in notes (including cases when keyword appears inside another word)
for (i = notePriority.size() - 1; i > 0; i--)
{
notePriority[i].first = i;
if (i != sourceMarker)
{
strcpy(checkedNote, markers.notes[i].c_str());
for (t = totalSourceKeywords - 1; t >= 0; t--)
{
if (StrStrI(checkedNote, sourceKeywords[t]))
notePriority[i].second += KEYWORD_CASEINSENTITIVE_BONUS_PER_CHAR * keywordWeight[t] * strlen(sourceKeywords[t]);
if (strstr(checkedNote, sourceKeywords[t]))
notePriority[i].second += KEYWORD_CASESENTITIVE_BONUS_PER_CHAR * keywordWeight[t] * strlen(sourceKeywords[t]);
}
}
}
// 3 - search sequences of keywords from all other notes
current_line_pos = 0;
char checkedKeywordsLine[MAX_NUM_KEYWORDS] = {0};
int keyword_id;
for (i = markers.notes.size() - 1; i > 0; i--)
{
if (i != sourceMarker)
{
strcpy(checkedNote, markers.notes[i].c_str());
// divide into tokens
pch = strtok(checkedNote, keywordDelimiters);
while (pch != NULL)
{
if (strlen(pch) >= KEYWORD_MIN_LEN)
{
// check if the keyword is one of sourceKeywords
for (t = totalSourceKeywords - 1; t >= 0; t--)
if (!_stricmp(sourceKeywords[t], pch)) break;
if (t >= 0)
{
// the keyword is one of sourceKeywords - set its id into the line
checkedKeywordsLine[current_line_pos++] = t + 1;
} else
{
// found keyword that doesn't appear in sourceNote, give penalty
notePriority[i].second -= KEYWORD_PENALTY_FOR_STRANGERS * strlen(pch);
// since the keyword breaks our sequence of coincident keywords, check if that sequence is similar to sourceKeywordsLine
if (current_line_pos >= KEYWORDS_LINE_MIN_SEQUENCE)
{
checkedKeywordsLine[current_line_pos] = 0;
// search checkedKeywordsLine in sourceKeywordsLine
if (strstr(sourceKeywordsLine, checkedKeywordsLine))
{
// found same sequence of keywords! add priority to this checkedNote
for (t = current_line_pos - 1; t >= 0; t--)
{
// add bonus for every keyword in the sequence
keyword_id = checkedKeywordsLine[t] - 1;
notePriority[i].second += current_line_pos * KEYWORD_SEQUENCE_BONUS_PER_CHAR * keywordWeight[keyword_id] * strlen(sourceKeywords[keyword_id]);
}
}
}
// clear checkedKeywordsLine
memset(checkedKeywordsLine, 0, MAX_NUM_KEYWORDS);
current_line_pos = 0;
}
}
pch = strtok(NULL, keywordDelimiters);
}
// finished dividing into tokens
if (current_line_pos >= KEYWORDS_LINE_MIN_SEQUENCE)
{
checkedKeywordsLine[current_line_pos] = 0;
// search checkedKeywordsLine in sourceKeywordsLine
if (strstr(sourceKeywordsLine, checkedKeywordsLine))
{
// found same sequence of keywords! add priority to this checkedNote
for (t = current_line_pos - 1; t >= 0; t--)
{
// add bonus for every keyword in the sequence
keyword_id = checkedKeywordsLine[t] - 1;
notePriority[i].second += current_line_pos * KEYWORD_SEQUENCE_BONUS_PER_CHAR * keywordWeight[keyword_id] * strlen(sourceKeywords[keyword_id]);
}
}
}
// clear checkedKeywordsLine
memset(checkedKeywordsLine, 0, MAX_NUM_KEYWORDS);
current_line_pos = 0;
}
}
// 4 - sort notePriority by second member of the pair
std::sort(notePriority.begin(), notePriority.end(), ordering);
/*
// debug trace
FCEU_printf("\n\n\n\n\n\n\n\n\n\n");
for (t = totalSourceKeywords - 1; t >= 0; t--)
FCEU_printf("Keyword: %s, %d, %f\n", sourceKeywords[t], keywordFound[t], keywordWeight[t]);
for (i = notePriority.size() - 1; i > 0; i--)
{
int marker_id = notePriority[i].first;
FCEU_printf("Result: %s, %d, %f\n", notes[marker_id].c_str(), marker_id, notePriority[i].second);
}
*/
// Send selection to the marker found
int index = notePriority.size()-1 - search_similar_marker;
if (index >= 0 && notePriority[index].second >= MIN_PRIORITY_TRESHOLD)
{
int marker_id = notePriority[index].first;
int frame = GetMarkerFrame(marker_id);
if (frame >= 0)
selection.JumpToFrame(frame);
} else
{
if (search_similar_marker)
MessageBox(taseditor_window.hwndTasEditor, "Could not find more Notes similar to Marker Note under Playback cursor!", "Find Similar Note", MB_OK);
else
MessageBox(taseditor_window.hwndTasEditor, "Could not find anything similar to Marker Note under Playback cursor!", "Find Similar Note", MB_OK);
}
// increase search_similar_marker so that next time we'll find another note
search_similar_marker++;
}
// ------------------------------------------------------------------------------------
void MARKERS_MANAGER::UpdateMarkerNote()
{
if (!marker_note_edit) return;
char new_text[MAX_NOTE_LEN];
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
int len = SendMessage(playback.hwndPlaybackMarkerEdit, WM_GETTEXT, MAX_NOTE_LEN, (LPARAM)new_text);
new_text[len] = 0;
// check changes
if (strcmp(GetNote(playback.shown_marker).c_str(), new_text))
{
SetNote(playback.shown_marker, new_text);
if (playback.shown_marker)
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, GetMarkerFrame(playback.shown_marker));
else
// zeroth marker - just assume it's set on frame 0
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, 0);
// notify selection to change text in lower marker (in case both are showing same marker)
selection.must_find_current_marker = true;
}
} else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
int len = SendMessage(selection.hwndSelectionMarkerEdit, WM_GETTEXT, MAX_NOTE_LEN, (LPARAM)new_text);
new_text[len] = 0;
// check changes
if (strcmp(GetNote(selection.shown_marker).c_str(), new_text))
{
SetNote(selection.shown_marker, new_text);
if (selection.shown_marker)
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, GetMarkerFrame(selection.shown_marker));
else
// zeroth marker - just assume it's set on frame 0
history.RegisterMarkersChange(MODTYPE_MARKER_RENAME, 0);
// notify playback to change text in upper marker (in case both are showing same marker)
playback.must_find_current_marker = true;
}
}
}
// ------------------------------------------------------------------------------------
BOOL CALLBACK FindNoteProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
extern MARKERS_MANAGER markers_manager;
switch (message)
{
case WM_INITDIALOG:
{
if (taseditor_config.findnote_wndx == -32000) taseditor_config.findnote_wndx = 0; //Just in case
if (taseditor_config.findnote_wndy == -32000) taseditor_config.findnote_wndy = 0;
SetWindowPos(hwndDlg, 0, taseditor_config.findnote_wndx, taseditor_config.findnote_wndy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
CheckDlgButton(hwndDlg, IDC_MATCH_CASE, taseditor_config.findnote_matchcase?MF_CHECKED : MF_UNCHECKED);
if (taseditor_config.findnote_search_up)
Button_SetCheck(GetDlgItem(hwndDlg, IDC_RADIO_UP), BST_CHECKED);
else
Button_SetCheck(GetDlgItem(hwndDlg, IDC_RADIO_DOWN), BST_CHECKED);
HWND hwndEdit = GetDlgItem(hwndDlg, IDC_NOTE_TO_FIND);
SendMessage(hwndEdit, EM_SETLIMITTEXT, MAX_NOTE_LEN - 1, 0);
SetWindowText(hwndEdit, markers_manager.findnote_string);
if (GetDlgCtrlID((HWND)wParam) != IDC_NOTE_TO_FIND)
{
SetFocus(hwndEdit);
return false;
}
return true;
}
case WM_MOVE:
{
if (!IsIconic(hwndDlg))
{
RECT wrect;
GetWindowRect(hwndDlg, &wrect);
taseditor_config.findnote_wndx = wrect.left;
taseditor_config.findnote_wndy = wrect.top;
WindowBoundsCheckNoResize(taseditor_config.findnote_wndx, taseditor_config.findnote_wndy, wrect.right);
}
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_NOTE_TO_FIND:
{
if(HIWORD(wParam) == EN_CHANGE)
{
if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_NOTE_TO_FIND)))
EnableWindow(GetDlgItem(hwndDlg, IDOK), true);
else
EnableWindow(GetDlgItem(hwndDlg, IDOK), false);
}
break;
}
case IDC_RADIO_UP:
taseditor_config.findnote_search_up = true;
break;
case IDC_RADIO_DOWN:
taseditor_config.findnote_search_up = false;
break;
case IDC_MATCH_CASE:
taseditor_config.findnote_matchcase ^= 1;
CheckDlgButton(hwndDlg, IDC_MATCH_CASE, taseditor_config.findnote_matchcase?MF_CHECKED : MF_UNCHECKED);
break;
case IDOK:
{
int len = SendMessage(GetDlgItem(hwndDlg, IDC_NOTE_TO_FIND), WM_GETTEXT, MAX_NOTE_LEN, (LPARAM)markers_manager.findnote_string);
markers_manager.findnote_string[len] = 0;
// scan frames from current selection to the border
int cur_marker = 0;
bool result;
int movie_size = currMovieData.getNumRecords();
int current_frame = selection.GetCurrentSelectionBeginning();
if (current_frame < 0 && taseditor_config.findnote_search_up)
current_frame = movie_size;
while (true)
{
// move forward
if (taseditor_config.findnote_search_up)
{
current_frame--;
if (current_frame < 0)
{
MessageBox(taseditor_window.hwndFindNote, "Nothing was found.", "Find Note", MB_OK);
break;
}
} else
{
current_frame++;
if (current_frame >= movie_size)
{
MessageBox(taseditor_window.hwndFindNote, "Nothing was found!", "Find Note", MB_OK);
break;
}
}
// scan marked frames
cur_marker = markers_manager.GetMarker(current_frame);
if (cur_marker)
{
if (taseditor_config.findnote_matchcase)
result = (strstr(markers_manager.GetNote(cur_marker).c_str(), markers_manager.findnote_string) != 0);
else
result = (StrStrI(markers_manager.GetNote(cur_marker).c_str(), markers_manager.findnote_string) != 0);
if (result)
{
// found note containing searched string - jump there
selection.JumpToFrame(current_frame);
break;
}
}
}
return TRUE;
}
case IDCANCEL:
DestroyWindow(taseditor_window.hwndFindNote);
taseditor_window.hwndFindNote = 0;
return TRUE;
}
break;
}
case WM_CLOSE:
case WM_QUIT:
{
DestroyWindow(taseditor_window.hwndFindNote);
taseditor_window.hwndFindNote = 0;
break;
}
}
return FALSE;
}

View File

@ -0,0 +1,76 @@
//Specification file for Markers_manager class
#include "markers.h"
#define MARKERS_ID_LEN 8
// constants for "Find Similar Note" algorithm (may need finetuning)
#define KEYWORD_MIN_LEN 2
#define MAX_NUM_KEYWORDS (MAX_NOTE_LEN / (KEYWORD_MIN_LEN+1)) + 1
#define KEYWORD_WEIGHT_BASE 2.0
#define KEYWORD_WEIGHT_FACTOR -1.0
#define KEYWORD_CASEINSENTITIVE_BONUS_PER_CHAR 1.0 // these two should be small, because they also work when keyword is inside another keyword, giving irrelevant results
#define KEYWORD_CASESENTITIVE_BONUS_PER_CHAR 1.0
#define KEYWORD_SEQUENCE_BONUS_PER_CHAR 5.0
#define KEYWORD_PENALTY_FOR_STRANGERS 0.2
#define KEYWORDS_LINE_MIN_SEQUENCE 1
#define MIN_PRIORITY_TRESHOLD 5.0
enum
{
MARKER_NOTE_EDIT_NONE,
MARKER_NOTE_EDIT_UPPER,
MARKER_NOTE_EDIT_LOWER
};
class MARKERS_MANAGER
{
public:
MARKERS_MANAGER();
void init();
void free();
void reset();
void update();
void save(EMUFILE *os, bool really_save = true);
bool load(EMUFILE *is);
int GetMarkersSize();
void SetMarkersSize(int new_size);
int GetMarker(int frame);
int GetMarkerUp(int start_frame);
int GetMarkerUp(MARKERS& target_markers, int start_frame); // special version of the function
int GetMarkerFrame(int marker_id);
int SetMarker(int frame);
void ClearMarker(int frame);
void ToggleMarker(int frame);
void EraseMarker(int frame);
void insertEmpty(int at, int frames);
int GetNotesSize();
std::string GetNote(int index);
std::string GetNote(MARKERS& target_markers, int index); // special version of the function
void SetNote(int index, const char* new_text);
void MakeCopyTo(MARKERS& destination);
void RestoreFromCopy(MARKERS& source, int until_frame = -1);
bool checkMarkersDiff(MARKERS& their_markers);
bool checkMarkersDiff(MARKERS& their_markers, int end);
void FindSimilar();
void FindNextSimilar();
void UpdateMarkerNote();
// not saved vars
int marker_note_edit;
char findnote_string[MAX_NOTE_LEN];
int search_similar_marker;
private:
// saved vars
MARKERS markers;
};

View File

@ -1,6 +1,5 @@
//Implementation file of Playback class
#include "taseditor_project.h"
#include "..\taseditor.h" // only for MARKER_NOTE_EDIT_UPPER
#ifdef _S9XLUA_H
extern void ForceExecuteLuaFrameFunctions();
@ -8,18 +7,14 @@ extern void ForceExecuteLuaFrameFunctions();
extern bool Taseditor_rewind_now;
extern bool turbo;
extern int marker_note_edit;
extern int search_similar_marker;
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern MARKERS current_markers;
extern MARKERS_MANAGER markers_manager;
extern GREENZONE greenzone;
extern TASEDITOR_LIST list;
extern BOOKMARKS bookmarks;
extern void UpdateMarkerNote();
LRESULT APIENTRY UpperMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC playbackMarkerEdit_oldWndproc;
@ -53,7 +48,7 @@ void PLAYBACK::reset()
must_find_current_marker = true;
shown_marker = 0;
lastCursor = -1;
pause_frame = old_pauseframe = 0;
lost_position_frame = pause_frame = old_pauseframe = 0;
old_show_pauseframe = show_pauseframe = false;
old_rewind_button_state = rewind_button_state = false;
old_forward_button_state = forward_button_state = false;
@ -65,6 +60,11 @@ void PLAYBACK::reset()
void PLAYBACK::update()
{
jump_was_used_this_frame = false;
// forget lost_position_frame when the position is restored
if (currFrameCounter + 1 == lost_position_frame)
lost_position_frame = 0;
// pause when seeking hit pause_frame
if(!FCEUI_EmulationPaused())
if(pause_frame && pause_frame <= currFrameCounter + 1)
@ -124,10 +124,10 @@ void PLAYBACK::update()
lastCursor = currFrameCounter;
UpdateWindow(list.hwndList);
// lazy update of "Playback's Marker text"
int current_marker = current_markers.GetMarkerUp(currFrameCounter);
int current_marker = markers_manager.GetMarkerUp(currFrameCounter);
if (shown_marker != current_marker)
{
UpdateMarkerNote();
markers_manager.UpdateMarkerNote();
shown_marker = current_marker;
RedrawMarker();
must_find_current_marker = false;
@ -137,8 +137,8 @@ void PLAYBACK::update()
// [non-lazy] update "Playback's Marker text" if needed
if (must_find_current_marker)
{
UpdateMarkerNote();
shown_marker = current_markers.GetMarkerUp(currFrameCounter);
markers_manager.UpdateMarkerNote();
shown_marker = markers_manager.GetMarkerUp(currFrameCounter);
RedrawMarker();
must_find_current_marker = false;
}
@ -270,7 +270,7 @@ void PLAYBACK::RewindFull()
// jump to previous marker
int index = currFrameCounter - 1;
for (; index >= 0; index--)
if (current_markers.GetMarker(index)) break;
if (markers_manager.GetMarker(index)) break;
if (index >= 0)
jump(index);
else
@ -283,7 +283,7 @@ void PLAYBACK::ForwardFull()
int last_frame = currMovieData.getNumRecords()-1;
int index = currFrameCounter + 1;
for (; index <= last_frame; ++index)
if (current_markers.GetMarker(index)) break;
if (markers_manager.GetMarker(index)) break;
if (index <= last_frame)
jump(index);
else
@ -301,17 +301,18 @@ void PLAYBACK::RedrawMarker()
strcat(new_text, num);
SetWindowText(hwndPlaybackMarker, new_text);
// change marker note
strcpy(new_text, current_markers.GetNote(shown_marker).c_str());
strcpy(new_text, markers_manager.GetNote(shown_marker).c_str());
SetWindowText(hwndPlaybackMarkerEdit, new_text);
// reset search_similar_marker
search_similar_marker = 0;
// reset search_similar_marker, because source marker changed
markers_manager.search_similar_marker = 0;
}
void PLAYBACK::StartFromZero()
{
poweron(true);
currFrameCounter = 0;
greenzone.TryDumpIncremental();
if(currMovieData.getNumRecords() == 0)
currMovieData.insertEmpty(-1, 1);
}
void PLAYBACK::jump(int frame)
@ -327,7 +328,7 @@ void PLAYBACK::restorePosition()
if (pause_frame)
jump(pause_frame-1);
else
jump(currFrameCounter);
jump(lost_position_frame-1);
}
bool PLAYBACK::JumpToFrame(int index)
@ -367,7 +368,7 @@ bool PLAYBACK::JumpToFrame(int index)
return true;
}
int PLAYBACK::GetPauseFrame()
int PLAYBACK::GetFlashingPauseFrame()
{
if (show_pauseframe)
return pause_frame;
@ -382,7 +383,7 @@ void PLAYBACK::SetProgressbar(int a, int b)
// -------------------------------------------------------------------------
LRESULT APIENTRY UpperMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
extern PLAYBACK playback;
extern TASEDITOR_SELECTION selection;
@ -394,7 +395,7 @@ LRESULT APIENTRY UpperMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPAR
{
case VK_ESCAPE:
// revert text to original note text
SetWindowText(playback.hwndPlaybackMarkerEdit, current_markers.GetNote(playback.shown_marker).c_str());
SetWindowText(playback.hwndPlaybackMarkerEdit, markers_manager.GetNote(playback.shown_marker).c_str());
SetFocus(list.hwndList);
return 0;
case VK_RETURN:

View File

@ -36,11 +36,12 @@ public:
void StartFromZero();
int GetPauseFrame();
int GetFlashingPauseFrame();
void SetProgressbar(int a, int b);
bool JumpToFrame(int index);
int lost_position_frame;
int pause_frame;
bool must_find_current_marker;
int shown_marker;

View File

@ -4,9 +4,9 @@
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern MARKERS current_markers;
extern BOOKMARKS bookmarks;
extern TASEDITOR_LIST list;
extern MARKERS_MANAGER markers_manager;
LRESULT CALLBACK ScrBmpWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT APIENTRY MarkerNoteTooltipWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
@ -217,9 +217,9 @@ void POPUP_DISPLAY::ChangeTooltipText()
{
// retrieve info from the pointed bookmark's markers
int frame = bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.jump_frame;
int marker_id = bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.my_markers.GetMarkerUp(frame);
int marker_id = markers_manager.GetMarkerUp(bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.GetMarkers(), frame);
char new_text[MAX_NOTE_LEN];
strcpy(new_text, bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.my_markers.GetNote(marker_id).c_str());
strcpy(new_text, markers_manager.GetNote(bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.GetMarkers(), marker_id).c_str());
SetWindowText(marker_note_tooltip, new_text);
}

View File

@ -1,17 +1,15 @@
//Implementation file of RECORDER class
#include "taseditor_project.h"
#include "zlib.h"
extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES];
extern uint32 GetGamepadPressedImmediate();
extern void ColumnSet(int column);
extern int GetInputType(MovieData& md);
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern BOOKMARKS bookmarks;
extern INPUT_HISTORY history;
extern HISTORY history;
extern GREENZONE greenzone;
extern TASEDITOR_LIST list;
@ -131,7 +129,7 @@ void RECORDER::update()
{
// if the button was pressed right now
if ((current_joy[joy] & (1 << button)) && !(old_joy[joy] & (1 << button)))
ColumnSet(COLUMN_JOYPAD1_A + joy * NUM_JOYPAD_BUTTONS + button);
list.ColumnSet(COLUMN_JOYPAD1_A + joy * NUM_JOYPAD_BUTTONS + button);
}
}
}

View File

@ -1,19 +1,19 @@
//Implementation file of Input Snapshot class (Undo feature)
//Implementation file of Snapshot class (Undo feature)
#include "taseditor_project.h"
#include "zlib.h"
int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES] = {1, 2, 4};
extern MARKERS current_markers;
extern MARKERS_MANAGER markers_manager;
extern TASEDITOR_SELECTION selection;
extern int GetInputType(MovieData& md);
INPUT_SNAPSHOT::INPUT_SNAPSHOT()
SNAPSHOT::SNAPSHOT()
{
}
void INPUT_SNAPSHOT::init(MovieData& md, bool hotchanges, int force_input_type)
void SNAPSHOT::init(MovieData& md, bool hotchanges, int force_input_type)
{
has_hot_changes = hotchanges;
if (force_input_type < 0)
@ -64,12 +64,11 @@ void INPUT_SNAPSHOT::init(MovieData& md, bool hotchanges, int force_input_type)
}
}
// make a copy of current_markers
my_markers.MakeCopy(current_markers);
if ((int)my_markers.GetMarkersSize() < size)
my_markers.SetMarkersSize(size);
// make a copy of markers_manager.markers
markers_manager.MakeCopyTo(my_markers);
if ((int)my_markers.markers_array.size() < size)
my_markers.markers_array.resize(size);
coherent = true;
already_compressed = false;
// save current time to description
time_t raw_time;
@ -78,12 +77,20 @@ void INPUT_SNAPSHOT::init(MovieData& md, bool hotchanges, int force_input_type)
strftime(description, 10, "%H:%M:%S", timeinfo);
}
void INPUT_SNAPSHOT::copyToMarkers(int end)
bool SNAPSHOT::MarkersDifferFromCurrent(int end)
{
current_markers.RestoreFromCopy(my_markers, end);
return markers_manager.checkMarkersDiff(my_markers, end);
}
void SNAPSHOT::copyToMarkers(int end)
{
markers_manager.RestoreFromCopy(my_markers, end);
}
MARKERS& SNAPSHOT::GetMarkers()
{
return my_markers;
}
void INPUT_SNAPSHOT::toMovie(MovieData& md, int start, int end)
void SNAPSHOT::toMovie(MovieData& md, int start, int end)
{
if (end < 0) end = size-1;
// write input data to movie data
@ -127,7 +134,7 @@ void INPUT_SNAPSHOT::toMovie(MovieData& md, int start, int end)
}
}
void INPUT_SNAPSHOT::compress_data()
void SNAPSHOT::compress_data()
{
// compress joysticks
int len = joysticks.size();
@ -154,12 +161,11 @@ void INPUT_SNAPSHOT::compress_data()
already_compressed = true;
}
void INPUT_SNAPSHOT::save(EMUFILE *os)
void SNAPSHOT::save(EMUFILE *os)
{
// write vars
write32le(size, os);
write8le(input_type, os);
if (coherent) write8le(1, os); else write8le((uint8)0, os);
write32le(jump_frame, os);
write32le(rec_end_frame, os);
write32le(rec_joypad_diff_bits, os);
@ -185,18 +191,16 @@ void INPUT_SNAPSHOT::save(EMUFILE *os)
os->fwrite(&hot_changes_compressed[0], hot_changes_compressed.size());
}
// save markers data
my_markers.save(os, true);
my_markers.save(os);
}
// returns true if couldn't load
bool INPUT_SNAPSHOT::load(EMUFILE *is)
bool SNAPSHOT::load(EMUFILE *is)
{
uint8 tmp;
// read vars
if (!read32le(&size, is)) return true;
if (!read8le(&tmp, is)) return true;
input_type = tmp;
if (!read8le(&tmp, is)) return true;
coherent = (tmp != 0);
if (!read32le(&jump_frame, is)) return true;
if (!read32le(&rec_end_frame, is)) return true;
if (!read32le(&rec_joypad_diff_bits, is)) return true;
@ -249,14 +253,13 @@ bool INPUT_SNAPSHOT::load(EMUFILE *is)
if (my_markers.load(is)) return true;
return false;
}
bool INPUT_SNAPSHOT::skipLoad(EMUFILE *is)
bool SNAPSHOT::skipLoad(EMUFILE *is)
{
int tmp;
uint8 tmp1;
// read vars
if (is->fseek(sizeof(int) + // size
sizeof(uint8) + // input_type
sizeof(uint8) + // coherent
sizeof(int) + // jump_frame
sizeof(int) + // rec_end_frame
sizeof(int) + // rec_joypad_diff_bits
@ -285,7 +288,7 @@ bool INPUT_SNAPSHOT::skipLoad(EMUFILE *is)
}
// return true if any difference is found
bool INPUT_SNAPSHOT::checkDiff(INPUT_SNAPSHOT& inp)
bool SNAPSHOT::checkDiff(SNAPSHOT& inp)
{
if (size != inp.size) return true;
if (findFirstChange(inp) >= 0)
@ -295,7 +298,7 @@ bool INPUT_SNAPSHOT::checkDiff(INPUT_SNAPSHOT& inp)
}
// fills map of bits judging on which joypads differ (this function is only used by "Record" modtype)
void INPUT_SNAPSHOT::fillJoypadsDiff(INPUT_SNAPSHOT& inp, int frame)
void SNAPSHOT::fillJoypadsDiff(SNAPSHOT& inp, int frame)
{
rec_joypad_diff_bits = 0;
uint32 current_mask = 1;
@ -323,8 +326,12 @@ void INPUT_SNAPSHOT::fillJoypadsDiff(INPUT_SNAPSHOT& inp, int frame)
}
// return number of first frame of difference between two snapshots
int INPUT_SNAPSHOT::findFirstChange(INPUT_SNAPSHOT& inp, int start, int end)
int SNAPSHOT::findFirstChange(SNAPSHOT& inp, int start, int end)
{
// if these two snapshots have different input_type (abnormal situation) then refuse to search and return the beginning
if (inp.input_type != input_type)
return start;
// search for differences to the specified end (or to the end of this snapshot)
if (end < 0 || end >= size) end = size-1;
int inp_end = inp.size;
@ -402,8 +409,8 @@ int INPUT_SNAPSHOT::findFirstChange(INPUT_SNAPSHOT& inp, int start, int end)
// no changes were found
return -1;
}
// return number of first frame of difference between this input_snapshot and MovieData
int INPUT_SNAPSHOT::findFirstChange(MovieData& md, int start, int end)
// return number of first frame of difference between this snapshot and MovieData
int SNAPSHOT::findFirstChange(MovieData& md, int start, int end)
{
// search for differences to the specified end (or to the end of this snapshot / to the end of the movie)
if (end < 0 || end >= size) end = size-1;
@ -449,7 +456,7 @@ int INPUT_SNAPSHOT::findFirstChange(MovieData& md, int start, int end)
return -1; // no changes were found
}
int INPUT_SNAPSHOT::GetJoystickInfo(int frame, int joy)
int SNAPSHOT::GetJoystickInfo(int frame, int joy)
{
if (frame < 0 || frame >= size) return 0;
switch(input_type)
@ -463,11 +470,63 @@ int INPUT_SNAPSHOT::GetJoystickInfo(int frame, int joy)
}
return 0;
}
void SNAPSHOT::insertFrames(int at, int frames)
{
size += frames;
if(at == -1)
{
// append frames to the end
commands.resize(size);
joysticks.resize(BYTES_PER_JOYSTICK * joysticks_per_frame[input_type] * size);
if (has_hot_changes)
{
hot_changes.resize(joysticks_per_frame[input_type] * size * HOTCHANGE_BYTES_PER_JOY);
// fill new hotchanges with max value
int lower_limit = joysticks_per_frame[input_type] * (size - frames) * HOTCHANGE_BYTES_PER_JOY;
for (int i = hot_changes.size() - 1; i >= lower_limit; i--)
hot_changes[i] = 0xFF;
}
} else
{
// insert frames
// insert 1 byte of commands
commands.insert(commands.begin() + at, frames, 0);
// insert X bytes of joystics
int bytes = BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
joysticks.insert(joysticks.begin() + (at * bytes), frames * bytes, 0);
if (has_hot_changes)
{
// insert X bytes of hot_changes
bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
hot_changes.insert(hot_changes.begin() + (at * bytes), frames * bytes, 0xFF);
}
}
// data was changed
already_compressed = false;
}
void SNAPSHOT::eraseFrame(int frame)
{
// erase 1 byte of commands
commands.erase(commands.begin() + frame);
// erase X bytes of joystics
int bytes = BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
joysticks.erase(joysticks.begin() + (frame * bytes), joysticks.begin() + ((frame + 1) * bytes));
if (has_hot_changes)
{
// erase X bytes of hot_changes
bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
hot_changes.erase(hot_changes.begin() + (frame * bytes), hot_changes.begin() + ((frame + 1) * bytes));
}
size--;
// data was changed
already_compressed = false;
}
// --------------------------------------------------------
void INPUT_SNAPSHOT::copyHotChanges(INPUT_SNAPSHOT* source_of_hotchanges, int limit_frame_of_source)
void SNAPSHOT::copyHotChanges(SNAPSHOT* source_of_hotchanges, int limit_frame_of_source)
{
// copy hot changes from source snapshot
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
{
int min = hot_changes.size();
if (min > (int)source_of_hotchanges->hot_changes.size())
@ -483,10 +542,10 @@ void INPUT_SNAPSHOT::copyHotChanges(INPUT_SNAPSHOT* source_of_hotchanges, int li
memcpy(&hot_changes[0], &source_of_hotchanges->hot_changes[0], min);
}
}
void INPUT_SNAPSHOT::inheritHotChanges(INPUT_SNAPSHOT* source_of_hotchanges)
void SNAPSHOT::inheritHotChanges(SNAPSHOT* source_of_hotchanges)
{
// copy hot changes from source snapshot and fade them
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
{
int min = hot_changes.size();
if (min > (int)source_of_hotchanges->hot_changes.size())
@ -496,10 +555,10 @@ void INPUT_SNAPSHOT::inheritHotChanges(INPUT_SNAPSHOT* source_of_hotchanges)
FadeHotChanges();
}
}
void INPUT_SNAPSHOT::inheritHotChanges_DeleteSelection(INPUT_SNAPSHOT* source_of_hotchanges)
void SNAPSHOT::inheritHotChanges_DeleteSelection(SNAPSHOT* source_of_hotchanges)
{
// copy hot changes from source snapshot, but omit deleted frames (which are represented by current selection)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
{
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
int frame = 0, pos = 0, source_pos = 0;
@ -525,10 +584,10 @@ void INPUT_SNAPSHOT::inheritHotChanges_DeleteSelection(INPUT_SNAPSHOT* source_of
FadeHotChanges();
}
}
void INPUT_SNAPSHOT::inheritHotChanges_InsertSelection(INPUT_SNAPSHOT* source_of_hotchanges)
void SNAPSHOT::inheritHotChanges_InsertSelection(SNAPSHOT* source_of_hotchanges)
{
// copy hot changes from source snapshot, but insert filled lines for inserted frames (which are represented by current selection)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
{
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
int frame = 0, region_len = 0, pos = 0, source_pos = 0;
@ -588,16 +647,16 @@ void INPUT_SNAPSHOT::inheritHotChanges_InsertSelection(INPUT_SNAPSHOT* source_of
}
}
}
void INPUT_SNAPSHOT::inheritHotChanges_PasteInsert(INPUT_SNAPSHOT* source_of_hotchanges)
void SNAPSHOT::inheritHotChanges_PasteInsert(SNAPSHOT* source_of_hotchanges, SelectionFrames& inserted_set)
{
// copy hot changes from source snapshot and insert filled lines for inserted frames (which are represented by inserted_set)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes)
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
{
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
int frame = 0, pos = 0, source_pos = 0;
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
SelectionFrames::iterator it(selection.GetInsertedSet().begin());
SelectionFrames::iterator inserted_set_end(selection.GetInsertedSet().end());
SelectionFrames::iterator it(inserted_set.begin());
SelectionFrames::iterator inserted_set_end(inserted_set.end());
while (pos < this_size)
{
if (it != inserted_set_end && frame == *it)
@ -622,8 +681,8 @@ void INPUT_SNAPSHOT::inheritHotChanges_PasteInsert(INPUT_SNAPSHOT* source_of_hot
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
int frame = 0, pos = 0;
int this_size = hot_changes.size();
SelectionFrames::iterator it(selection.GetInsertedSet().begin());
SelectionFrames::iterator inserted_set_end(selection.GetInsertedSet().end());
SelectionFrames::iterator it(inserted_set.begin());
SelectionFrames::iterator inserted_set_end(inserted_set.end());
while (pos < this_size)
{
if (it != inserted_set_end && frame == *it)
@ -644,9 +703,13 @@ void INPUT_SNAPSHOT::inheritHotChanges_PasteInsert(INPUT_SNAPSHOT* source_of_hot
}
}
}
void INPUT_SNAPSHOT::fillHotChanges(INPUT_SNAPSHOT& inp, int start, int end)
void SNAPSHOT::fillHotChanges(SNAPSHOT& inp, int start, int end)
{
// search for differences to the specified end (or to the end of this snapshot)
// if these two snapshots have different input_type (abnormal situation) then refuse to compare
if (inp.input_type != input_type)
return;
// compare snapshots to the specified end (or to the end of this snapshot)
if (end < 0 || end >= size) end = size-1;
int inp_end = inp.size;
switch(input_type)
@ -735,7 +798,7 @@ void INPUT_SNAPSHOT::fillHotChanges(INPUT_SNAPSHOT& inp, int start, int end)
}
}
void INPUT_SNAPSHOT::SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits)
void SNAPSHOT::SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits)
{
uint8 mask = 1;
// check all 8 buttons and set max hot_changes for bits that are set
@ -746,7 +809,7 @@ void INPUT_SNAPSHOT::SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits)
mask <<= 1;
}
}
void INPUT_SNAPSHOT::SetMaxHotChange(int frame, int absolute_button)
void SNAPSHOT::SetMaxHotChange(int frame, int absolute_button)
{
if (frame < 0 || frame >= size || !has_hot_changes) return;
// set max value (15) to the button hotness
@ -788,7 +851,7 @@ void INPUT_SNAPSHOT::SetMaxHotChange(int frame, int absolute_button)
}
}
void INPUT_SNAPSHOT::FadeHotChanges()
void SNAPSHOT::FadeHotChanges()
{
uint8 hi_half, low_half;
for (int i = hot_changes.size() - 1; i >= 0; i--)
@ -804,7 +867,7 @@ void INPUT_SNAPSHOT::FadeHotChanges()
}
}
int INPUT_SNAPSHOT::GetHotChangeInfo(int frame, int absolute_button)
int SNAPSHOT::GetHotChangeInfo(int frame, int absolute_button)
{
if (!has_hot_changes || frame < 0 || frame >= size || absolute_button < 0 || absolute_button >= NUM_JOYPAD_BUTTONS * joysticks_per_frame[input_type])
return 0;

View File

@ -13,33 +13,39 @@ enum Input_types
#define SNAPSHOT_DESC_MAX_LENGTH 100
class INPUT_SNAPSHOT
class SNAPSHOT
{
public:
INPUT_SNAPSHOT();
SNAPSHOT();
void init(MovieData& md, bool hotchanges, int force_input_type = -1);
void toMovie(MovieData& md, int start = 0, int end = -1);
bool MarkersDifferFromCurrent(int end = -1);
void copyToMarkers(int end = -1);
MARKERS& GetMarkers();
void toMovie(MovieData& md, int start = 0, int end = -1);
void save(EMUFILE *os);
bool load(EMUFILE *is);
bool skipLoad(EMUFILE *is);
bool checkDiff(INPUT_SNAPSHOT& inp);
void fillJoypadsDiff(INPUT_SNAPSHOT& inp, int frame);
bool checkDiff(SNAPSHOT& inp);
void fillJoypadsDiff(SNAPSHOT& inp, int frame);
int findFirstChange(INPUT_SNAPSHOT& inp, int start = 0, int end = -1);
int findFirstChange(SNAPSHOT& inp, int start = 0, int end = -1);
int findFirstChange(MovieData& md, int start = 0, int end = -1);
int GetJoystickInfo(int frame, int joy);
void copyHotChanges(INPUT_SNAPSHOT* source_of_hotchanges, int limit_frame_of_source = -1);
void inheritHotChanges(INPUT_SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_DeleteSelection(INPUT_SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_InsertSelection(INPUT_SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_PasteInsert(INPUT_SNAPSHOT* source_of_hotchanges);
void fillHotChanges(INPUT_SNAPSHOT& inp, int start = 0, int end = -1);
void insertFrames(int at, int frames);
void eraseFrame(int frame);
void copyHotChanges(SNAPSHOT* source_of_hotchanges, int limit_frame_of_source = -1);
void inheritHotChanges(SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_DeleteSelection(SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_InsertSelection(SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_PasteInsert(SNAPSHOT* source_of_hotchanges, SelectionFrames& inserted_set);
void fillHotChanges(SNAPSHOT& inp, int start = 0, int end = -1);
void SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits);
void SetMaxHotChange(int frame, int absolute_button);
@ -48,14 +54,12 @@ public:
int GetHotChangeInfo(int frame, int absolute_button);
// saved data
int size; // in frames
int input_type; // theoretically TAS Editor can support any other input types
std::vector<uint8> joysticks; // Format: joy0-for-frame0, joy1-for-frame0, joy2-for-frame0, joy3-for-frame0, joy0-for-frame1, joy1-for-frame1, ...
std::vector<uint8> commands; // Format: commands-for-frame0, commands-for-frame1, ...
std::vector<uint8> hot_changes; // Format: buttons01joy0-for-frame0, buttons23joy0-for-frame0, buttons45joy0-for-frame0, buttons67joy0-for-frame0, buttons01joy1-for-frame0, ...
MARKERS my_markers;
bool coherent; // indicates whether this state was made right after previous state
int jump_frame; // for jumping when making undo
int rec_end_frame; // for consecutive Recordings
uint32 rec_joypad_diff_bits; // for consecutive Recordings
@ -66,10 +70,12 @@ public:
private:
void compress_data();
bool already_compressed; // to compress only once
// also saved data
MARKERS my_markers;
std::vector<uint8> joysticks_compressed;
std::vector<uint8> commands_compressed;
std::vector<uint8> hot_changes_compressed;
bool already_compressed; // to compress only once
};

View File

@ -5,8 +5,8 @@
extern TASEDITOR_WINDOW taseditor_window;
extern TASEDITOR_CONFIG taseditor_config;
extern INPUT_HISTORY history;
extern MARKERS current_markers;
extern HISTORY history;
extern MARKERS_MANAGER markers_manager;
extern PLAYBACK playback;
extern GREENZONE greenzone;
extern TASEDITOR_LIST list;
@ -105,13 +105,13 @@ void SPLICER::CloneFrames()
// end of current region
currMovieData.cloneRegion(*it, frames);
if (taseditor_config.bind_markers)
current_markers.insertEmpty(*it, frames);
markers_manager.insertEmpty(*it, frames);
frames = 1;
} else frames++;
}
if (taseditor_config.bind_markers)
{
current_markers.update();
markers_manager.update();
selection.must_find_current_marker = playback.must_find_current_marker = true;
}
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_CLONE, *current_selection->begin()));
@ -139,13 +139,13 @@ void SPLICER::InsertFrames()
// end of current region
currMovieData.insertEmpty(*it,frames);
if (taseditor_config.bind_markers)
current_markers.insertEmpty(*it,frames);
markers_manager.insertEmpty(*it,frames);
frames = 1;
} else frames++;
}
if (taseditor_config.bind_markers)
{
current_markers.update();
markers_manager.update();
selection.must_find_current_marker = playback.must_find_current_marker = true;
}
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_INSERT, *current_selection->begin()));
@ -173,7 +173,7 @@ void SPLICER::InsertNumFrames()
currMovieData.insertEmpty(index, frames);
if (taseditor_config.bind_markers)
{
current_markers.insertEmpty(index, frames);
markers_manager.insertEmpty(index, frames);
selection.must_find_current_marker = playback.must_find_current_marker = true;
}
// select inserted rows
@ -197,7 +197,7 @@ void SPLICER::DeleteFrames()
{
currMovieData.records.erase(currMovieData.records.begin() + *it);
if (taseditor_config.bind_markers)
current_markers.EraseMarker(*it);
markers_manager.EraseMarker(*it);
}
if (taseditor_config.bind_markers)
selection.must_find_current_marker = playback.must_find_current_marker = true;
@ -249,7 +249,7 @@ void SPLICER::Truncate()
currMovieData.truncateAt(frame+1);
if (taseditor_config.bind_markers)
{
current_markers.SetMarkersSize(frame+1);
markers_manager.SetMarkersSize(frame+1);
selection.must_find_current_marker = playback.must_find_current_marker = true;
}
list.update();
@ -308,26 +308,24 @@ bool SPLICER::Copy(SelectionFrames* current_selection)
}
}
clipString << std::endl;
if (!OpenClipboard(taseditor_window.hwndTasEditor))
return false;
EmptyClipboard();
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, clipString.str().size()+1);
if (hGlobal==INVALID_HANDLE_VALUE)
{
CloseClipboard();
return false;
}
char *pGlobal = (char*)GlobalLock(hGlobal);
strcpy(pGlobal, clipString.str().c_str());
GlobalUnlock(hGlobal);
SetClipboardData(CF_TEXT, hGlobal);
CloseClipboard();
}
// write data to clipboard
if (!OpenClipboard(taseditor_window.hwndTasEditor))
return false;
EmptyClipboard();
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, clipString.str().size()+1);
if (hGlobal==INVALID_HANDLE_VALUE)
{
CloseClipboard();
return false;
}
char *pGlobal = (char*)GlobalLock(hGlobal);
strcpy(pGlobal, clipString.str().c_str());
GlobalUnlock(hGlobal);
SetClipboardData(CF_TEXT, hGlobal);
CloseClipboard();
}
catch (std::bad_alloc e)
{
@ -374,7 +372,7 @@ bool SPLICER::Paste()
if (currMovieData.getNumRecords() < pos+range)
{
currMovieData.insertEmpty(currMovieData.getNumRecords(),pos+range-currMovieData.getNumRecords());
current_markers.update();
markers_manager.update();
}
pGlobal = strchr(pGlobal, '\n');
@ -490,15 +488,14 @@ bool SPLICER::PasteInsert()
if (pGlobal[0]=='T' && pGlobal[1]=='A' && pGlobal[2]=='S')
{
// make sure markers have the same size as movie
current_markers.update();
// init inserted_set (for input history hot changes)
selection.GetInsertedSet().clear();
markers_manager.update();
// create inserted_set (for input history hot changes)
SelectionFrames inserted_set;
// Extract number of frames
int range;
sscanf (pGlobal+3, "%d", &range);
pGlobal = strchr(pGlobal, '\n');
char* frame;
int joy=0;
@ -514,7 +511,7 @@ bool SPLICER::PasteInsert()
if (currMovieData.getNumRecords() < pos)
{
currMovieData.insertEmpty(currMovieData.getNumRecords(), pos - currMovieData.getNumRecords());
current_markers.update();
markers_manager.update();
}
while (*frame && *frame != '\n' && *frame != '|')
++frame;
@ -526,8 +523,8 @@ bool SPLICER::PasteInsert()
// insert new frame
currMovieData.insertEmpty(pos, 1);
if (taseditor_config.bind_markers) current_markers.insertEmpty(pos, 1);
selection.GetInsertedSet().insert(pos);
if (taseditor_config.bind_markers) markers_manager.insertEmpty(pos, 1);
inserted_set.insert(pos);
// read this frame input
int joy = 0;
@ -555,10 +552,10 @@ bool SPLICER::PasteInsert()
pGlobal = strchr(pGlobal, '\n');
}
current_markers.update();
markers_manager.update();
if (taseditor_config.bind_markers)
selection.must_find_current_marker = playback.must_find_current_marker = true;
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_PASTEINSERT, *current_selection_begin));
greenzone.InvalidateAndCheck(history.RegisterPasteInsert(*current_selection_begin, inserted_set));
// flash list header columns that were changed during paste
for (int joy = 0; joy < num_joypads; ++joy)
{

View File

@ -49,6 +49,7 @@ TASEDITOR_CONFIG::TASEDITOR_CONFIG()
findnote_search_up = false;
enable_auto_function = true;
silent_autosave = true;
tooltips = true;
// empty name
last_author[0] = 0;

View File

@ -1,4 +1,6 @@
//Specification file for TASEDITOR_CONFIG class
// --------------------------------------------------------
#define GREENZONE_CAPACITY_MIN 1
#define GREENZONE_CAPACITY_MAX 50000
#define GREENZONE_CAPACITY_DEFAULT 10000
@ -63,6 +65,7 @@ public:
bool findnote_search_up;
bool enable_auto_function;
bool silent_autosave;
bool tooltips;
char last_author[AUTHOR_MAX_LEN];
private:

View File

@ -7,7 +7,6 @@
extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES];
extern char buttonNames[NUM_JOYPAD_BUTTONS][2];
extern void ColumnSet(int column);
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
@ -15,8 +14,8 @@ extern BOOKMARKS bookmarks;
extern PLAYBACK playback;
extern RECORDER recorder;
extern GREENZONE greenzone;
extern INPUT_HISTORY history;
extern MARKERS current_markers;
extern HISTORY history;
extern MARKERS_MANAGER markers_manager;
extern TASEDITOR_SELECTION selection;
extern int GetInputType(MovieData& md);
@ -26,13 +25,12 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC hwndList_oldWndProc = 0, hwndHeader_oldWndproc = 0;
// resources
char list_save_id[LIST_ID_LEN] = "LIST";
char list_skipsave_id[LIST_ID_LEN] = "LISX";
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, 0x006311, 0x008500, 0x1dad00, 0x46d100, 0x6ee300, 0x97e800, 0xb8f000, 0xdaf700, 0xffff7e, 0xffffb7 };
char list_save_id[LIST_ID_LEN] = "LIST";
char list_skipsave_id[LIST_ID_LEN] = "LISX";
TASEDITOR_LIST::TASEDITOR_LIST()
{
}
@ -68,7 +66,7 @@ void TASEDITOR_LIST::init()
"Arial"); /*font name*/
bg_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
header_colors.resize(MAX_NUM_COLUMNS);
header_colors.resize(TOTAL_COLUMNS);
hwndList = GetDlgItem(taseditor_window.hwndTasEditor, IDC_LIST1);
// prepare the main listview
@ -145,6 +143,9 @@ void TASEDITOR_LIST::init()
bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_TE_ARROW));
ImageList_AddMasked(himglist, bmp, 0xFFFFFF);
DeleteObject(bmp);
bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_TE_GREEN_ARROW));
ImageList_AddMasked(himglist, bmp, 0xFFFFFF);
DeleteObject(bmp);
ListView_SetImageList(hwndList, himglist, LVSIL_SMALL);
// setup 0th column
LVCOLUMN lvc;
@ -193,8 +194,8 @@ void TASEDITOR_LIST::reset()
// delete all columns except 0th
while (ListView_DeleteColumn(hwndList, 1)) {}
// setup columns
LVCOLUMN lvc;
num_columns = 1;
LVCOLUMN lvc;
// frame number column
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
lvc.fmt = LVCFMT_CENTER;
@ -427,7 +428,7 @@ void TASEDITOR_LIST::FollowSelection()
}
void TASEDITOR_LIST::FollowPauseframe()
{
int jump_frame = playback.GetPauseFrame();
int jump_frame = playback.pause_frame;
if (jump_frame >= 0)
{
// center list at jump_frame
@ -474,6 +475,8 @@ void TASEDITOR_LIST::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
{
if (item.iItem == currFrameCounter)
item.iImage = ARROW_IMAGE_ID;
else if (item.iItem == playback.lost_position_frame-1)
item.iImage = GREEN_ARROW_IMAGE_ID;
}
}
break;
@ -538,7 +541,7 @@ LONG TASEDITOR_LIST::CustomDraw(NMLVCUSTOMDRAW* msg)
if(cell_x == COLUMN_FRAMENUM || cell_x == COLUMN_FRAMENUM2)
{
// font
if(current_markers.GetMarker(cell_y))
if(markers_manager.GetMarker(cell_y))
SelectObject(msg->nmcd.hdc, hMainListSelectFont);
else
SelectObject(msg->nmcd.hdc, hMainListFont);
@ -547,24 +550,24 @@ LONG TASEDITOR_LIST::CustomDraw(NMLVCUSTOMDRAW* msg)
if (cell_y == history.GetUndoHint())
{
// undo hint here
if (taseditor_config.show_markers && current_markers.GetMarker(cell_y))
if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y))
{
msg->clrTextBk = (taseditor_config.bind_markers) ? BINDMARKED_UNDOHINT_FRAMENUM_COLOR : MARKED_UNDOHINT_FRAMENUM_COLOR;
} else
{
msg->clrTextBk = UNDOHINT_FRAMENUM_COLOR;
}
} else if (cell_y == currFrameCounter || cell_y == (playback.GetPauseFrame() - 1))
} else if (cell_y == currFrameCounter || cell_y == (playback.GetFlashingPauseFrame() - 1))
{
// current frame
if (taseditor_config.show_markers && current_markers.GetMarker(cell_y))
if (taseditor_config.show_markers && markers_manager.GetMarker(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 && current_markers.GetMarker(cell_y))
} else if (taseditor_config.show_markers && markers_manager.GetMarker(cell_y))
{
// marked frame
msg->clrTextBk = (taseditor_config.bind_markers) ? BINDMARKED_FRAMENUM_COLOR : MARKED_FRAMENUM_COLOR;
@ -600,7 +603,7 @@ LONG TASEDITOR_LIST::CustomDraw(NMLVCUSTOMDRAW* msg)
{
// undo hint here
msg->clrTextBk = UNDOHINT_INPUT_COLOR1;
} else if (cell_y == currFrameCounter || cell_y == (playback.GetPauseFrame() - 1))
} else if (cell_y == currFrameCounter || cell_y == (playback.GetFlashingPauseFrame() - 1))
{
// current frame
msg->clrTextBk = CUR_INPUT_COLOR1;
@ -633,7 +636,7 @@ LONG TASEDITOR_LIST::CustomDraw(NMLVCUSTOMDRAW* msg)
{
// undo hint here
msg->clrTextBk = UNDOHINT_INPUT_COLOR2;
} else if (cell_y == currFrameCounter || cell_y == (playback.GetPauseFrame() - 1))
} else if (cell_y == currFrameCounter || cell_y == (playback.GetFlashingPauseFrame() - 1))
{
// current frame
msg->clrTextBk = CUR_INPUT_COLOR2;
@ -684,9 +687,191 @@ LONG TASEDITOR_LIST::HeaderCustomDraw(NMLVCUSTOMDRAW* msg)
return CDRF_DODEFAULT;
}
}
void TASEDITOR_LIST::SingleClick(LPNMITEMACTIVATE info)
{
int row_index = info->iItem;
if(row_index == -1) return;
int column_index = info->iSubItem;
if(column_index == COLUMN_ICONS)
{
// click on the "icons" column - jump to the frame
selection.ClearSelection();
playback.jump(row_index);
} else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
{
// click on the "frame number" column - set marker if clicked with Alt
if (info->uKeyFlags & LVKF_ALT)
{
// reverse MARKER_FLAG_BIT in pointed frame
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);
RedrawRow(row_index);
}
}
else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
{
ToggleJoypadBit(column_index, row_index, info->uKeyFlags);
}
}
void TASEDITOR_LIST::DoubleClick(LPNMITEMACTIVATE info)
{
int row_index = info->iItem;
if(row_index == -1) return;
int column_index = info->iSubItem;
if(column_index == COLUMN_ICONS || column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
{
// double click sends playback to the frame
selection.ClearSelection();
playback.jump(row_index);
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
{
ToggleJoypadBit(column_index, row_index, info->uKeyFlags);
}
}
void TASEDITOR_LIST::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 & (LVKF_SHIFT|LVKF_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 (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 TASEDITOR_LIST::ColumnSet(int column)
{
if (column == COLUMN_FRAMENUM || column == COLUMN_FRAMENUM2)
FrameColumnSet();
else
InputColumnSet(column);
}
void TASEDITOR_LIST::FrameColumnSet()
{
SelectionFrames* current_selection = selection.MakeStrobe();
if (current_selection->size() == 0) return;
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;
SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
}
}
void TASEDITOR_LIST::InputColumnSet(int column)
{
int joy = (column - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
if (joy < 0 || joy >= joysticks_per_frame[GetInputType(currMovieData)]) return;
int button = (column - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
SelectionFrames* current_selection = selection.MakeStrobe();
if (current_selection->size() == 0) return;
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);
if (newValue)
{
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, *current_selection_begin, *current_selection->rbegin()));
} else
{
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, *current_selection_begin, *current_selection->rbegin()));
}
SetHeaderColumnLight(column, HEADER_LIGHT_MAX);
}
// -------------------------------------------------------------------------
LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
extern TASEDITOR_LIST list;
switch(msg)
{
case WM_SETCURSOR:
@ -702,7 +887,7 @@ LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
info.pt.y = GET_Y_LPARAM(lParam);
SendMessage(hWnd,HDM_HITTEST,0,(LPARAM)&info);
if(info.iItem >= COLUMN_FRAMENUM && info.iItem <= COLUMN_FRAMENUM2)
ColumnSet(info.iItem);
list.ColumnSet(info.iItem);
}
}
return true;

View File

@ -51,7 +51,7 @@ enum
COLUMN_JOYPAD4_R,
COLUMN_FRAMENUM2,
MAX_NUM_COLUMNS
TOTAL_COLUMNS
};
// when there's too many button columns, there's need for 2nd Frame# column at the end
@ -59,6 +59,7 @@ enum
#define DIGITS_IN_FRAMENUM 7
#define ARROW_IMAGE_ID 20
#define GREEN_ARROW_IMAGE_ID 21
#define COLUMN_ICONS_WIDTH 13
#define COLUMN_FRAMENUM_WIDTH 75
@ -135,6 +136,15 @@ public:
LONG CustomDraw(NMLVCUSTOMDRAW* msg);
LONG HeaderCustomDraw(NMLVCUSTOMDRAW* msg);
void SingleClick(LPNMITEMACTIVATE info);
void DoubleClick(LPNMITEMACTIVATE info);
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags);
void ColumnSet(int column);
void InputColumnSet(int column);
void FrameColumnSet();
HWND hwndList, hwndHeader;
// GDI stuff

View File

@ -1,12 +1,14 @@
//Implementation file of TASEDITOR_LUA class
#include "taseditor_project.h"
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern INPUT_HISTORY history;
extern MARKERS current_markers;
extern HISTORY history;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern RECORDER recorder;
extern PLAYBACK playback;
extern GREENZONE greenzone;
extern TASEDITOR_LIST list;
extern TASEDITOR_SELECTION selection;
@ -18,6 +20,7 @@ TASEDITOR_LUA::TASEDITOR_LUA()
void TASEDITOR_LUA::init()
{
pending_changes.resize(0);
hwndRunFunction = GetDlgItem(taseditor_window.hwndTasEditor, TASEDITOR_RUN_MANUAL);
TaseditorUpdateManualFunctionStatus();
reset();
@ -39,6 +42,39 @@ void TASEDITOR_LUA::DisableRunFunction()
{
EnableWindow(hwndRunFunction, false);
}
void TASEDITOR_LUA::InsertDelete_rows_to_Snaphot(SNAPSHOT& snapshot)
{
int size = pending_changes.size();
if (size)
{
// apply changes to given snapshot (only insertion/deletion)
for (int i = 0; i < size; ++i)
{
if (pending_changes[i].frame >= snapshot.size)
// expand snapshot to fit the frame
snapshot.insertFrames(-1, 1 + pending_changes[i].frame - snapshot.size);
switch (pending_changes[i].type)
{
case LUA_CHANGE_TYPE_INSERTFRAMES:
{
snapshot.insertFrames(pending_changes[i].frame, pending_changes[i].data);
break;
}
case LUA_CHANGE_TYPE_DELETEFRAMES:
{
for (int t = pending_changes[i].data; t > 0; t--)
{
if (pending_changes[i].frame < snapshot.size)
snapshot.eraseFrame(pending_changes[i].frame);
}
break;
}
}
}
}
}
// --------------------------------------------------------------------------------
// Lua functions of taseditor library
@ -52,7 +88,7 @@ bool TASEDITOR_LUA::engaged()
bool TASEDITOR_LUA::markedframe(int frame)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
return current_markers.GetMarker(frame) != 0;
return markers_manager.GetMarker(frame) != 0;
else
return false;
}
@ -61,7 +97,7 @@ bool TASEDITOR_LUA::markedframe(int frame)
int TASEDITOR_LUA::getmarker(int frame)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
return current_markers.GetMarkerUp(frame);
return markers_manager.GetMarkerUp(frame);
else
return -1;
}
@ -71,10 +107,10 @@ int TASEDITOR_LUA::setmarker(int frame)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
int marker_id = current_markers.GetMarker(frame);
int marker_id = markers_manager.GetMarker(frame);
if(!marker_id)
{
marker_id = current_markers.SetMarker(frame);
marker_id = markers_manager.SetMarker(frame);
if (marker_id)
{
// new marker was created - register changes in TAS Editor
@ -93,9 +129,9 @@ void TASEDITOR_LUA::clearmarker(int frame)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
if (current_markers.GetMarker(frame))
if (markers_manager.GetMarker(frame))
{
current_markers.ClearMarker(frame);
markers_manager.ClearMarker(frame);
// marker was deleted - register changes in TAS Editor
history.RegisterMarkersChange(MODTYPE_LUA_MARKER_UNSET, frame);
selection.must_find_current_marker = playback.must_find_current_marker = true;
@ -108,8 +144,9 @@ void TASEDITOR_LUA::clearmarker(int frame)
const char* TASEDITOR_LUA::getnote(int index)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
return current_markers.GetNote(index).c_str();
else
{
return strdup(markers_manager.GetNote(index).c_str());
} else
return NULL;
}
@ -121,11 +158,11 @@ void TASEDITOR_LUA::setnote(int index, const char* newtext)
// rename only if newtext is different from old text
char text[MAX_NOTE_LEN];
strncpy(text, newtext, MAX_NOTE_LEN - 1);
if (strcmp(current_markers.GetNote(index).c_str(), text))
if (strcmp(markers_manager.GetNote(index).c_str(), text))
{
// text differs from old note - rename
current_markers.SetNote(index, text);
history.RegisterMarkersChange(MODTYPE_LUA_MARKER_RENAME, current_markers.GetMarkerFrame(index));
markers_manager.SetNote(index, text);
history.RegisterMarkersChange(MODTYPE_LUA_MARKER_RENAME, markers_manager.GetMarkerFrame(index));
selection.must_find_current_marker = playback.must_find_current_marker = true;
}
}
@ -149,6 +186,15 @@ const char* TASEDITOR_LUA::getrecordermode()
return NULL;
}
// int taseditor.getlostplayback()
int TASEDITOR_LUA::getlostplayback()
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
return playback.lost_position_frame - 1;
else
return -1;
}
// int taseditor.getplaybacktarget()
int TASEDITOR_LUA::getplaybacktarget()
{
@ -158,7 +204,7 @@ int TASEDITOR_LUA::getplaybacktarget()
return -1;
}
// taseditor.setplayback()
// taseditor.setplayback(int frame)
void TASEDITOR_LUA::setplayback(int frame)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
@ -172,6 +218,220 @@ void TASEDITOR_LUA::stopseeking()
playback.SeekingStop();
}
// table taseditor.getselection()
void TASEDITOR_LUA::getselection(std::vector<int>& placeholder)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
SelectionFrames* current_selection = selection.MakeStrobe();
int frames = current_selection->size();
if (!frames) return;
placeholder.resize(frames);
SelectionFrames::iterator current_selection_end(current_selection->end());
int i = 0;
for(SelectionFrames::iterator it(current_selection->begin()); it != current_selection_end; ++it)
placeholder[i++] = *it;
}
}
// taseditor.setselection(table new_set)
void TASEDITOR_LUA::setselection(std::vector<int>& new_set)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
selection.ClearSelection();
for (int i = new_set.size() - 1; i >= 0; i--)
selection.SetRowSelection(new_set[i]);
}
}
// int taseditor.getinput(int frame, int joypad)
int TASEDITOR_LUA::getinput(int frame, int joypad)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
if (frame < 0) return -1;
if (frame >= currMovieData.getNumRecords()) return 0;
switch (joypad)
{
case LUA_JOYPAD_COMMANDS:
return currMovieData.records[frame].commands;
case LUA_JOYPAD_1P:
return currMovieData.records[frame].joysticks[0];
case LUA_JOYPAD_2P:
return currMovieData.records[frame].joysticks[1];
case LUA_JOYPAD_3P:
return currMovieData.records[frame].joysticks[2];
case LUA_JOYPAD_4P:
return currMovieData.records[frame].joysticks[3];
}
return -1;
} else
{
return -1;
}
}
// taseditor.submitinputchange(int frame, int joypad, int input)
void TASEDITOR_LUA::submitinputchange(int frame, int joypad, int input)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
if (frame >= 0)
{
if (joypad == LUA_JOYPAD_COMMANDS || joypad == LUA_JOYPAD_1P || joypad == LUA_JOYPAD_2P || joypad == LUA_JOYPAD_3P || joypad == LUA_JOYPAD_4P)
{
PENDING_CHANGES new_change;
new_change.type = LUA_CHANGE_TYPE_INPUTCHANGE;
new_change.frame = frame;
new_change.joypad = joypad;
new_change.data = input;
pending_changes.push_back(new_change);
}
}
}
}
void TASEDITOR_LUA::submitinsertframes(int frame, int number)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
if (frame >= 0 && number > 0)
{
PENDING_CHANGES new_change;
new_change.type = LUA_CHANGE_TYPE_INSERTFRAMES;
new_change.frame = frame;
new_change.joypad = 0; // doesn't matter in TAS Editor v1.0, whole frame will be inserted
new_change.data = number;
pending_changes.push_back(new_change);
}
}
}
void TASEDITOR_LUA::submitdeleteframes(int frame, int number)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
if (frame >= 0 && number > 0)
{
PENDING_CHANGES new_change;
new_change.type = LUA_CHANGE_TYPE_DELETEFRAMES;
new_change.frame = frame;
new_change.joypad = 0; // doesn't matter in TAS Editor v1.0, whole frame will be deleted
new_change.data = number;
pending_changes.push_back(new_change);
}
}
}
// int taseditor.applyinputchanges([string name])
int TASEDITOR_LUA::applyinputchanges(const char* name)
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
int size = pending_changes.size();
int start_index = currMovieData.getNumRecords() - 1;
bool InsertionDeletion_was_made = false;
if (size)
{
// apply changes to current movie data
for (int i = 0; i < size; ++i)
{
if (pending_changes[i].frame < start_index)
start_index = pending_changes[i].frame;
if (pending_changes[i].frame >= (int)currMovieData.getNumRecords())
{
// expand movie to fit the frame
currMovieData.insertEmpty(-1, 1 + pending_changes[i].frame - currMovieData.getNumRecords());
markers_manager.update();
InsertionDeletion_was_made = true;
}
switch (pending_changes[i].type)
{
case LUA_CHANGE_TYPE_INPUTCHANGE:
{
switch (pending_changes[i].joypad)
{
case LUA_JOYPAD_COMMANDS:
currMovieData.records[pending_changes[i].frame].commands = pending_changes[i].data;
break;
case LUA_JOYPAD_1P:
currMovieData.records[pending_changes[i].frame].joysticks[0] = pending_changes[i].data;
break;
case LUA_JOYPAD_2P:
currMovieData.records[pending_changes[i].frame].joysticks[1] = pending_changes[i].data;
break;
case LUA_JOYPAD_3P:
currMovieData.records[pending_changes[i].frame].joysticks[2] = pending_changes[i].data;
break;
case LUA_JOYPAD_4P:
currMovieData.records[pending_changes[i].frame].joysticks[3] = pending_changes[i].data;
break;
}
break;
}
case LUA_CHANGE_TYPE_INSERTFRAMES:
{
InsertionDeletion_was_made = true;
currMovieData.insertEmpty(pending_changes[i].frame, pending_changes[i].data);
if (taseditor_config.bind_markers)
markers_manager.insertEmpty(pending_changes[i].frame, pending_changes[i].data);
break;
}
case LUA_CHANGE_TYPE_DELETEFRAMES:
{
InsertionDeletion_was_made = true;
for (int t = pending_changes[i].data; t > 0; t--)
{
if (pending_changes[i].frame < (int)currMovieData.getNumRecords())
currMovieData.records.erase(currMovieData.records.begin() + pending_changes[i].frame);
if (taseditor_config.bind_markers)
markers_manager.EraseMarker(pending_changes[i].frame);
}
break;
}
}
}
if (taseditor_config.bind_markers)
selection.must_find_current_marker = playback.must_find_current_marker = true;
// check if user deleted all frames
if (!currMovieData.getNumRecords())
playback.StartFromZero();
// reduce list
list.update();
// check actual changes
int result = history.RegisterLuaChanges(name, start_index, InsertionDeletion_was_made);
if (result >= 0)
{
greenzone.InvalidateAndCheck(result);
} else if (greenzone.greenZoneCount >= currMovieData.getNumRecords())
{
greenzone.InvalidateAndCheck(currMovieData.getNumRecords()-1);
} else list.RedrawList();
pending_changes.resize(0);
return result;
} else
{
return -1;
}
} else
{
return -1;
}
}
// taseditor.clearinputchanges()
void TASEDITOR_LUA::clearinputchanges()
{
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
pending_changes.resize(0);
}
}

View File

@ -1,4 +1,29 @@
//Specification file for TASEDITOR_LUA class
#define LUACHANGES_NAME_MAX_LEN 80 // the name should not be longer than 80 letters
struct PENDING_CHANGES
{
uint8 type;
int frame;
uint8 joypad;
int data;
};
enum
{
LUA_CHANGE_TYPE_INPUTCHANGE = 0,
LUA_CHANGE_TYPE_INSERTFRAMES = 1,
LUA_CHANGE_TYPE_DELETEFRAMES = 2,
};
enum
{
LUA_JOYPAD_COMMANDS = 0,
LUA_JOYPAD_1P = 1,
LUA_JOYPAD_2P = 2,
LUA_JOYPAD_3P = 3,
LUA_JOYPAD_4P = 4,
};
class TASEDITOR_LUA
{
@ -11,6 +36,8 @@ public:
void EnableRunFunction();
void DisableRunFunction();
void InsertDelete_rows_to_Snaphot(SNAPSHOT& snapshot);
// Taseditor Lua library
bool engaged();
bool markedframe(int frame);
@ -21,12 +48,22 @@ public:
void setnote(int index, const char* newtext);
int getcurrentbranch();
const char* getrecordermode();
int getlostplayback();
int getplaybacktarget();
void setplayback(int frame);
void stopseeking();
void getselection(std::vector<int>& placeholder);
void setselection(std::vector<int>& new_set);
int getinput(int frame, int joypad);
void submitinputchange(int frame, int joypad, int input);
void submitinsertframes(int frame, int number);
void submitdeleteframes(int frame, int number);
int applyinputchanges(const char* name);
void clearinputchanges();
private:
std::vector<PENDING_CHANGES> pending_changes;
HWND hwndRunFunction;
};

View File

@ -5,13 +5,13 @@
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern MARKERS current_markers;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern POPUP_DISPLAY popup_display;
extern GREENZONE greenzone;
extern PLAYBACK playback;
extern RECORDER recorder;
extern INPUT_HISTORY history;
extern HISTORY history;
extern TASEDITOR_LIST list;
extern TASEDITOR_SELECTION selection;
extern SPLICER splicer;
@ -28,14 +28,14 @@ TASEDITOR_PROJECT::TASEDITOR_PROJECT()
void TASEDITOR_PROJECT::init()
{
projectFile = "";
projectName = "";
fm2FileName = "";
reset();
}
void TASEDITOR_PROJECT::reset()
{
changed = false;
projectFile = "";
projectName = "";
fm2FileName = "";
}
void TASEDITOR_PROJECT::update()
{
@ -65,7 +65,7 @@ bool TASEDITOR_PROJECT::save()
// save all modules
unsigned int saved_stuff = ALL_SAVED;
write32le(saved_stuff, ofs);
current_markers.save(ofs);
markers_manager.save(ofs);
bookmarks.save(ofs);
greenzone.save(ofs);
history.save(ofs);
@ -94,7 +94,7 @@ bool TASEDITOR_PROJECT::save_compact(char* filename, bool save_binary, bool save
if (save_list) saved_stuff |= LIST_SAVED;
if (save_selection) saved_stuff |= SELECTION_SAVED;
write32le(saved_stuff, ofs);
current_markers.save(ofs, save_markers);
markers_manager.save(ofs, save_markers);
bookmarks.save(ofs, save_bookmarks);
greenzone.save(ofs, save_greenzone);
history.save(ofs, save_history);
@ -138,7 +138,7 @@ bool TASEDITOR_PROJECT::load(char* fullname)
// load modules
unsigned int saved_stuff;
read32le(&saved_stuff, &ifs);
current_markers.load(&ifs);
markers_manager.load(&ifs);
bookmarks.load(&ifs);
greenzone.load(&ifs);
history.load(&ifs);

View File

@ -1,22 +1,19 @@
//Specification file for the TASEDITOR_PROJECT class
#include <set>
typedef std::set<int> SelectionFrames;
#include <time.h>
#include "movie.h"
#include "../common.h"
#include "taseditor_config.h"
#include "taseditor_window.h"
#include "markers.h"
#include "inputsnapshot.h"
#include "inputhistory.h"
#include "taseditor_sel.h"
#include "markers_manager.h"
#include "snapshot.h"
#include "history.h"
#include "playback.h"
#include "recorder.h"
#include "greenzone.h"
#include "bookmarks.h"
#include "taseditor_list.h"
#include "taseditor_lua.h"
#include "taseditor_sel.h"
#include "splicer.h"
#include "popup_display.h"

View File

@ -1,16 +1,13 @@
//Implementation file of TASEDITOR_SELECTION class
#include "taseditor_project.h"
#include "..\taseditor.h" // only for MARKER_NOTE_EDIT_LOWER
extern TASEDITOR_CONFIG taseditor_config;
extern TASEDITOR_WINDOW taseditor_window;
extern MARKERS current_markers;
extern MARKERS_MANAGER markers_manager;
extern TASEDITOR_LIST list;
extern SPLICER splicer;
extern int marker_note_edit;
extern int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES];
extern void UpdateMarkerNote();
LRESULT APIENTRY LowerMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC selectionMarkerEdit_oldWndproc;
@ -120,8 +117,8 @@ void TASEDITOR_SELECTION::update()
// update "Selection's Marker text" if needed
if (must_find_current_marker)
{
UpdateMarkerNote();
shown_marker = current_markers.GetMarkerUp(last_selection_beginning);
markers_manager.UpdateMarkerNote();
shown_marker = markers_manager.GetMarkerUp(last_selection_beginning);
RedrawMarker();
must_find_current_marker = false;
}
@ -139,7 +136,7 @@ void TASEDITOR_SELECTION::RedrawMarker()
strcat(new_text, num);
SetWindowText(hwndSelectionMarker, new_text);
// change marker note
strcpy(new_text, current_markers.GetNote(shown_marker).c_str());
strcpy(new_text, markers_manager.GetNote(shown_marker).c_str());
SetWindowText(hwndSelectionMarkerEdit, new_text);
}
@ -149,7 +146,7 @@ void TASEDITOR_SELECTION::JumpPrevMarker()
int index = GetCurrentSelectionBeginning();
if (index < 0) index = currFrameCounter; // if nothing is selected, consider playback cursor as current selection
for (index--; index >= 0; index--)
if (current_markers.GetMarker(index)) break;
if (markers_manager.GetMarker(index)) break;
if (index >= 0)
JumpToFrame(index);
else
@ -163,7 +160,7 @@ void TASEDITOR_SELECTION::JumpNextMarker()
int last_frame = currMovieData.getNumRecords()-1;
for (++index; index <= last_frame; ++index)
if (current_markers.GetMarker(index)) break;
if (markers_manager.GetMarker(index)) break;
if (index <= last_frame)
JumpToFrame(index);
else
@ -431,10 +428,10 @@ void TASEDITOR_SELECTION::SelectBetweenMarkers()
// find markers
// searching up starting from center-0
for (upper_marker = center; upper_marker >= 0; upper_marker--)
if (current_markers.GetMarker(upper_marker)) break;
if (markers_manager.GetMarker(upper_marker)) break;
// searching down starting from center+1
for (lower_marker = center+1; lower_marker < movie_size; ++lower_marker)
if (current_markers.GetMarker(lower_marker)) break;
if (markers_manager.GetMarker(lower_marker)) break;
// clear selection without clearing focused, because otherwise there's strange bug when quickly pressing Ctrl+A right after clicking on already selected row
ListView_SetItemState(list.hwndList, -1, 0, LVIS_SELECTED);
@ -528,11 +525,7 @@ SelectionFrames& TASEDITOR_SELECTION::GetStrobedSelection()
return temp_selection;
}
SelectionFrames& TASEDITOR_SELECTION::GetInsertedSet()
{
return inserted_set;
}
// this getter is only for inside-class use
// this getter is private
SelectionFrames& TASEDITOR_SELECTION::CurrentSelection()
{
return selections_history[(history_start_pos + history_cursor_pos) % history_size];
@ -540,7 +533,7 @@ SelectionFrames& TASEDITOR_SELECTION::CurrentSelection()
// -------------------------------------------------------------------------
LRESULT APIENTRY LowerMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
extern PLAYBACK playback;
extern TASEDITOR_SELECTION selection;
@ -552,7 +545,7 @@ LRESULT APIENTRY LowerMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPAR
{
case VK_ESCAPE:
// revert text to original note text
SetWindowText(selection.hwndSelectionMarkerEdit, current_markers.GetNote(selection.shown_marker).c_str());
SetWindowText(selection.hwndSelectionMarkerEdit, markers_manager.GetNote(selection.shown_marker).c_str());
SetFocus(list.hwndList);
return 0;
case VK_RETURN:

View File

@ -1,4 +1,6 @@
//Specification file for TASEDITOR_SELECTION class
#include <set>
typedef std::set<int> SelectionFrames;
#define SELECTION_ID_LEN 10
@ -27,7 +29,6 @@ public:
void undo();
void redo();
void jump(int new_pos);
void ClearSelection();
void ClearRowSelection(int index);
@ -51,8 +52,6 @@ public:
SelectionFrames* MakeStrobe();
SelectionFrames& GetStrobedSelection();
SelectionFrames& GetInsertedSet();
bool must_find_current_marker;
int shown_marker;
@ -60,6 +59,8 @@ public:
HWND hwndSelectionMarker, hwndSelectionMarkerEdit;
private:
void jump(int new_pos);
SelectionFrames& CurrentSelection();
bool track_selection_changes;
@ -71,8 +72,6 @@ private:
std::vector<SelectionFrames> selections_history;
SelectionFrames inserted_set;
int history_cursor_pos;
int history_start_pos;
int history_total_items;

View File

@ -4,6 +4,7 @@
#include "../Win32InputBox.h"
#include "../taseditor.h"
#include <htmlhelp.h>
#include "../../input.h" // for EMUCMD
extern TASEDITOR_CONFIG taseditor_config;
extern PLAYBACK playback;
@ -13,21 +14,22 @@ extern TASEDITOR_PROJECT project;
extern TASEDITOR_LIST list;
extern TASEDITOR_SELECTION selection;
extern SPLICER splicer;
extern MARKERS current_markers;
extern MARKERS_MANAGER markers_manager;
extern BOOKMARKS bookmarks;
extern INPUT_HISTORY history;
extern HISTORY history;
extern POPUP_DISPLAY popup_display;
extern bool turbo;
extern bool muteTurbo;
extern int marker_note_edit;
extern int search_similar_marker;
extern bool must_call_manual_lua_function;
BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
extern char* GetKeyComboName(int c);
extern BOOL CALLBACK FindNoteProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
extern BOOL CALLBACK AboutProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
// Recent Menu
HMENU recent_projects_menu;
char* recent_projects[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -46,49 +48,54 @@ static struct
int y;
int width;
int height;
char tooltip_text_base[TOOLTIP_TEXT_MAX_LEN];
char tooltip_text[TOOLTIP_TEXT_MAX_LEN];
bool static_rect;
int hotkey_emucmd;
HWND tooltip_hwnd;
} window_items[TASEDITOR_WINDOW_TOTAL_ITEMS] = {
IDC_PROGRESS_BUTTON, -1, 0, 0, 0,
IDC_BRANCHES_BUTTON, -1, 0, 0, 0,
IDC_LIST1, 0, 0, -1, -1,
IDC_PLAYBACK_BOX, -1, 0, 0, 0,
IDC_RECORDER_BOX, -1, 0, 0, 0,
IDC_SPLICER_BOX, -1, 0, 0, 0,
IDC_LUA_BOX, -1, 0, 0, 0,
IDC_BOOKMARKS_BOX, -1, 0, 0, 0,
IDC_HISTORY_BOX, -1, 0, 0, -1,
TASEDITOR_REWIND_FULL, -1, 0, 0, 0,
TASEDITOR_REWIND, -1, 0, 0, 0,
TASEDITOR_PLAYSTOP, -1, 0, 0, 0,
TASEDITOR_FORWARD, -1, 0, 0, 0,
TASEDITOR_FORWARD_FULL, -1, 0, 0, 0,
IDC_PROGRESS1, -1, 0, 0, 0,
CHECK_FOLLOW_CURSOR, -1, 0, 0, 0,
CHECK_AUTORESTORE_PLAYBACK, -1, 0, 0, 0,
IDC_BOOKMARKSLIST, -1, 0, 0, 0,
IDC_HISTORYLIST, -1, 0, 0, -1,
IDC_RADIO_ALL, -1, 0, 0, 0,
IDC_RADIO_1P, -1, 0, 0, 0,
IDC_RADIO_2P, -1, 0, 0, 0,
IDC_RADIO_3P, -1, 0, 0, 0,
IDC_RADIO_4P, -1, 0, 0, 0,
IDC_SUPERIMPOSE, -1, 0, 0, 0,
TASEDITOR_PREV_MARKER, -1, -1, 0, -1,
TASEDITOR_FIND_BEST_SIMILAR_MARKER, -1, -1, 0, -1,
TASEDITOR_FIND_NEXT_SIMILAR_MARKER, -1, -1, 0, -1,
TASEDITOR_NEXT_MARKER, -1, -1, 0, -1,
IDC_JUMP_PLAYBACK_BUTTON, 0, 0, 0, 0,
IDC_PLAYBACK_MARKER_EDIT, 0, 0, -1, 0,
IDC_PLAYBACK_MARKER, 0, 0, 0, 0,
IDC_JUMP_SELECTION_BUTTON, 0, -1, 0, -1,
IDC_SELECTION_MARKER_EDIT, 0, -1, -1, -1,
IDC_SELECTION_MARKER, 0, -1, 0, -1,
IDC_BRANCHES_BITMAP, -1, 0, 0, 0,
CHECK_TURBO_SEEK, -1, 0, 0, 0,
IDC_TEXT_SELECTION, -1, 0, 0, 0,
IDC_TEXT_CLIPBOARD, -1, 0, 0, 0,
IDC_RECORDING, -1, 0, 0, 0,
TASEDITOR_RUN_MANUAL, -1, 0, 0, 0,
IDC_RUN_AUTO, -1, 0, 0, 0,
IDC_PROGRESS_BUTTON, -1, 0, 0, 0, "Click here whenever you want to abort seeking", "", false, 0, 0,
IDC_BRANCHES_BUTTON, -1, 0, 0, 0, "Click here to switch between Bookmarks List and Branches Tree", "", false, 0, 0,
IDC_LIST1, 0, 0, -1, -1, "", "", false, 0, 0,
IDC_PLAYBACK_BOX, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_RECORDER_BOX, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_SPLICER_BOX, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_LUA_BOX, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_BOOKMARKS_BOX, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_HISTORY_BOX, -1, 0, 0, -1, "", "", false, 0, 0,
TASEDITOR_REWIND_FULL, -1, 0, 0, 0, "Send Playback to previous Marker (hotkey: Shift+PageUp)", "", false, 0, 0,
TASEDITOR_REWIND, -1, 0, 0, 0, "Rewind one frame", "", false, EMUCMD_TASEDITOR_REWIND, 0,
TASEDITOR_PLAYSTOP, -1, 0, 0, 0, "Pause/Unpause Emulation", "", false, EMUCMD_PAUSE, 0,
TASEDITOR_FORWARD, -1, 0, 0, 0, "Advance one frame", "", false, EMUCMD_FRAME_ADVANCE, 0,
TASEDITOR_FORWARD_FULL, -1, 0, 0, 0, "Send Playback to next Marker (hotkey: Shift+PageDown)", "", false, 0, 0,
IDC_PROGRESS1, -1, 0, 0, 0, "", "", false, 0, 0,
CHECK_FOLLOW_CURSOR, -1, 0, 0, 0, "The List will follow Playback cursor movements", "", false, 0, 0,
CHECK_AUTORESTORE_PLAYBACK, -1, 0, 0, 0, "If you change input above Playback, cursor will run where it was before change", "", false, 0, 0,
IDC_BOOKMARKSLIST, -1, 0, 0, 0, "Right click = set Bookmark, Left click = jump to Bookmark or load Branch", "", false, 0, 0,
IDC_HISTORYLIST, -1, 0, 0, -1, "Click to revert movie back to that time", "", false, 0, 0,
IDC_RADIO_ALL, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_RADIO_1P, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_RADIO_2P, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_RADIO_3P, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_RADIO_4P, -1, 0, 0, 0, "", "", false, 0, 0,
IDC_SUPERIMPOSE, -1, 0, 0, 0, "Allows to superimpose old input with new buttons, instead of overwriting", "", false, 0, 0,
TASEDITOR_PREV_MARKER, -1, -1, 0, -1, "Send Selection to previous Marker (hotkey: Ctrl+PageUp)", "", false, 0, 0,
TASEDITOR_FIND_BEST_SIMILAR_MARKER, -1, -1, 0, -1, "Auto-search for Marker Note", "", false, 0, 0,
TASEDITOR_FIND_NEXT_SIMILAR_MARKER, -1, -1, 0, -1, "Continue Auto-search", "", false, 0, 0,
TASEDITOR_NEXT_MARKER, -1, -1, 0, -1, "Send Selection to next Marker (hotkey: Ctrl+PageDown)", "", false, 0, 0,
IDC_JUMP_PLAYBACK_BUTTON, 0, 0, 0, 0, "Click here to scroll the List to Playback cursor", "", false, 0, 0,
IDC_PLAYBACK_MARKER_EDIT, 0, 0, -1, 0, "Click to edit text", "", false, 0, 0,
IDC_PLAYBACK_MARKER, 0, 0, 0, 0, "", "", false, 0, 0,
IDC_JUMP_SELECTION_BUTTON, 0, -1, 0, -1, "Click here to scroll the List to Selection", "", false, 0, 0,
IDC_SELECTION_MARKER_EDIT, 0, -1, -1, -1, "Click to edit text", "", false, 0, 0,
IDC_SELECTION_MARKER, 0, -1, 0, -1, "", "", false, 0, 0,
IDC_BRANCHES_BITMAP, -1, 0, 0, 0, "This window visualizes the hierarchy of your Branches", "", false, 0, 0,
CHECK_TURBO_SEEK, -1, 0, 0, 0, "Uncheck when you need to watch seeking in slow motion", "", false, 0, 0,
IDC_TEXT_SELECTION, -1, 0, 0, 0, "Current size of Selection", "", true, 0, 0,
IDC_TEXT_CLIPBOARD, -1, 0, 0, 0, "Current size of Input in the Clipboard", "", true, 0, 0,
IDC_RECORDING, -1, 0, 0, 0, "Switch Input Recording on/off", "", false, EMUCMD_MOVIE_READONLY_TOGGLE, 0,
TASEDITOR_RUN_MANUAL, -1, 0, 0, 0, "Press the button to execute Lua Manual Function", "", false, 0, 0,
IDC_RUN_AUTO, -1, 0, 0, 0, "Enable Lua Auto Function (but first it must be registered by Lua script)", "", false, 0, 0,
};
TASEDITOR_WINDOW::TASEDITOR_WINDOW()
@ -108,17 +115,73 @@ void TASEDITOR_WINDOW::init()
ready_for_resizing = false;
hTaseditorIcon = (HICON)LoadImage(fceu_hInstance, MAKEINTRESOURCE(IDI_ICON3), IMAGE_ICON, 16, 16, LR_DEFAULTSIZE);
hwndTasEditor = CreateDialog(fceu_hInstance, "TASEDITOR", hAppWnd, WndprocTasEditor);
SendMessage(hwndTasEditor, WM_SETICON, ICON_SMALL, (LPARAM)hTaseditorIcon);
CalculateItems();
// restore position and size from config, also bring the window on top
//RECT desiredRect = {0, 0, taseditor_config.wndwidth, taseditor_config.wndheight};
//AdjustWindowRectEx(&desiredRect, GetWindowLong(hwndTasEditor, GWL_STYLE), true, GetWindowLong(hwndTasEditor, GWL_EXSTYLE));
SetWindowPos(hwndTasEditor, HWND_TOP, taseditor_config.wndx, taseditor_config.wndy, taseditor_config.wndwidth, taseditor_config.wndheight, SWP_NOOWNERZORDER);
// menus and checked items
hmenu = GetMenu(hwndTasEditor);
hrmenu = LoadMenu(fceu_hInstance,"TASEDITORCONTEXTMENUS");
UpdateCheckedItems();
// tooltips
int x = 0;
for (int i = 0; i < TASEDITOR_WINDOW_TOTAL_ITEMS; ++i)
{
if (window_items[i].tooltip_text_base[0])
{
// Create the tooltip. g_hInst is the global instance handle
window_items[i].tooltip_hwnd = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hwndTasEditor, NULL,
fceu_hInstance, NULL);
if (window_items[i].tooltip_hwnd)
{
// Associate the tooltip with the tool
TOOLINFO toolInfo = {0};
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hwndTasEditor;
toolInfo.uId = (UINT_PTR)GetDlgItem(hwndTasEditor, window_items[i].id);
if (window_items[i].static_rect)
{
// for static text we specify rectangle
toolInfo.uFlags = TTF_SUBCLASS;
RECT tool_rect;
GetWindowRect(GetDlgItem(hwndTasEditor, window_items[i].id), &tool_rect);
POINT pt;
pt.x = tool_rect.left;
pt.y = tool_rect.top;
ScreenToClient(hwndTasEditor, &pt);
toolInfo.rect.left = pt.x;
toolInfo.rect.right = toolInfo.rect.left + (tool_rect.right - tool_rect.left);
toolInfo.rect.top = pt.y;
toolInfo.rect.bottom = toolInfo.rect.top + (tool_rect.bottom - tool_rect.top);
} else
{
// for other controls we provide hwnd
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
}
// add hotkey mapping if needed
if (window_items[i].hotkey_emucmd && FCEUD_CommandMapping[window_items[i].hotkey_emucmd])
{
window_items[i].tooltip_text[0] = 0;
strcpy(window_items[i].tooltip_text, window_items[i].tooltip_text_base);
strcat(window_items[i].tooltip_text, " (hotkey: ");
strncat(window_items[i].tooltip_text, GetKeyComboName(FCEUD_CommandMapping[window_items[i].hotkey_emucmd]), TOOLTIP_TEXT_MAX_LEN - strlen(window_items[i].tooltip_text) - 1);
strncat(window_items[i].tooltip_text, ")", TOOLTIP_TEXT_MAX_LEN - strlen(window_items[i].tooltip_text) - 1);
toolInfo.lpszText = window_items[i].tooltip_text;
} else
{
toolInfo.lpszText = window_items[i].tooltip_text_base;
}
SendMessage(window_items[i].tooltip_hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
SendMessage(window_items[i].tooltip_hwnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, TOOLTIPS_AUTOPOP_TIMEOUT);
}
}
}
UpdateTooltips();
// recent projects submenu
recent_projects_menu = CreateMenu();
UpdateRecentProjectsMenu();
@ -126,6 +189,14 @@ void TASEDITOR_WINDOW::init()
}
void TASEDITOR_WINDOW::exit()
{
for (int i = 0; i < TASEDITOR_WINDOW_TOTAL_ITEMS; ++i)
{
if (window_items[i].tooltip_hwnd)
{
DestroyWindow(window_items[i].tooltip_hwnd);
window_items[i].tooltip_hwnd = 0;
}
}
if (hwndFindNote)
{
DestroyWindow(hwndFindNote);
@ -238,12 +309,10 @@ void TASEDITOR_WINDOW::ResizeItems()
else
// normal height
height = window_items[i].height;
SetWindowPos(hCtrl, 0, x, y, width, height, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOREDRAW);
SetWindowPos(hCtrl, 0, x, y, width, height, SWP_NOZORDER | SWP_NOOWNERZORDER);
}
RedrawTaseditor();
//RedrawWindow(hwndTasEditor, NULL, NULL, RDW_INVALIDATE);
}
void TASEDITOR_WINDOW::WindowMovedOrResized()
{
RECT wrect;
@ -259,6 +328,25 @@ void TASEDITOR_WINDOW::WindowMovedOrResized()
taseditor_config.wndheight = min_height;
}
void TASEDITOR_WINDOW::UpdateTooltips()
{
if (taseditor_config.tooltips)
{
for (int i = 0; i < TASEDITOR_WINDOW_TOTAL_ITEMS; ++i)
{
if (window_items[i].tooltip_hwnd)
SendMessage(window_items[i].tooltip_hwnd, TTM_ACTIVATE, true, 0);
}
} else
{
for (int i = 0; i < TASEDITOR_WINDOW_TOTAL_ITEMS; ++i)
{
if (window_items[i].tooltip_hwnd)
SendMessage(window_items[i].tooltip_hwnd, TTM_ACTIVATE, false, 0);
}
}
}
void TASEDITOR_WINDOW::UpdateCaption()
{
char new_caption[300];
@ -315,7 +403,7 @@ void TASEDITOR_WINDOW::RightClickMenu(LPNMITEMACTIVATE info)
bool set_found = false, unset_found = false;
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
{
if(current_markers.GetMarker(*it))
if(markers_manager.GetMarker(*it))
set_found = true;
else
unset_found = true;
@ -359,6 +447,7 @@ void TASEDITOR_WINDOW::UpdateCheckedItems()
CheckMenuItem(hmenu, ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE, taseditor_config.superimpose_affects_paste?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_MUTETURBO, muteTurbo?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_SILENTAUTOSAVE, taseditor_config.silent_autosave?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_HELP_TOOLTIPS, taseditor_config.tooltips?MF_CHECKED : MF_UNCHECKED);
}
@ -493,7 +582,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
{
if (taseditor_config.wndx == -32000) taseditor_config.wndx = 0; //Just in case
if (taseditor_config.wndy == -32000) taseditor_config.wndy = 0;
SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)taseditor_window.hTaseditorIcon);
break;
}
case WM_WINDOWPOSCHANGED:
@ -542,10 +630,10 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
list.GetDispInfo((NMLVDISPINFO*)lParam);
break;
case NM_CLICK:
SingleClick((LPNMITEMACTIVATE)lParam);
list.SingleClick((LPNMITEMACTIVATE)lParam);
break;
case NM_DBLCLK:
DoubleClick((LPNMITEMACTIVATE)lParam);
list.DoubleClick((LPNMITEMACTIVATE)lParam);
break;
case NM_RCLICK:
taseditor_window.RightClick((LPNMITEMACTIVATE)lParam);
@ -610,6 +698,9 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
break;
}
break;
case ID_STRAY_UNPAUSE:
playback.UnpauseEmulation();
break;
}
break;
case WM_CLOSE:
@ -620,11 +711,11 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
if(LOWORD(wParam))
{
taseditor_window.TASEditor_focus = true;
SetTaseditInput();
SetTaseditorInput();
} else
{
taseditor_window.TASEditor_focus = false;
ClearTaseditInput();
ClearTaseditorInput();
}
break;
case WM_CTLCOLORSTATIC:
@ -659,27 +750,27 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
{
case EN_SETFOCUS:
{
marker_note_edit = MARKER_NOTE_EDIT_UPPER;
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_UPPER;
// enable editing
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETREADONLY, false, 0);
// disable FCEUX keyboard
ClearTaseditInput();
ClearTaseditorInput();
if (taseditor_config.follow_note_context)
list.FollowPlayback();
break;
}
case EN_KILLFOCUS:
{
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
UpdateMarkerNote();
marker_note_edit = MARKER_NOTE_EDIT_NONE;
markers_manager.UpdateMarkerNote();
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_NONE;
}
// disable editing (make it grayed)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETREADONLY, true, 0);
// enable FCEUX keyboard
if (taseditor_window.TASEditor_focus)
SetTaseditInput();
SetTaseditorInput();
break;
}
}
@ -691,27 +782,27 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
{
case EN_SETFOCUS:
{
marker_note_edit = MARKER_NOTE_EDIT_LOWER;
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_LOWER;
// enable editing
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETREADONLY, false, 0);
// disable FCEUX keyboard
ClearTaseditInput();
ClearTaseditorInput();
if (taseditor_config.follow_note_context)
list.FollowSelection();
break;
}
case EN_KILLFOCUS:
{
if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
UpdateMarkerNote();
marker_note_edit = MARKER_NOTE_EDIT_NONE;
markers_manager.UpdateMarkerNote();
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_NONE;
}
// disable editing (make it grayed)
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETREADONLY, true, 0);
// enable FCEUX keyboard
if (taseditor_window.TASEditor_focus)
SetTaseditInput();
SetTaseditorInput();
break;
}
}
@ -743,36 +834,36 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
ExitTasEditor();
break;
case ID_EDIT_SELECTALL:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETSEL, 0, -1);
else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETSEL, 0, -1);
else
selection.SelectAll();
break;
case ACCEL_CTRL_X:
case ID_EDIT_CUT:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, WM_CUT, 0, 0);
else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
SendMessage(selection.hwndSelectionMarkerEdit, WM_CUT, 0, 0);
else
splicer.Cut();
break;
case ACCEL_CTRL_C:
case ID_EDIT_COPY:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, WM_COPY, 0, 0);
else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
SendMessage(selection.hwndSelectionMarkerEdit, WM_COPY, 0, 0);
else
splicer.Copy();
break;
case ACCEL_CTRL_V:
case ID_EDIT_PASTE:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, WM_PASTE, 0, 0);
else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
SendMessage(selection.hwndSelectionMarkerEdit, WM_PASTE, 0, 0);
else
splicer.Paste();
@ -782,13 +873,13 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
// hack to allow entering Shift-V into edit control even though accelerator steals the input message
char insert_v[] = "v";
char insert_V[] = "V";
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
if (GetKeyState(VK_CAPITAL) & 1)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_REPLACESEL, true, (LPARAM)insert_v);
else
SendMessage(playback.hwndPlaybackMarkerEdit, EM_REPLACESEL, true, (LPARAM)insert_V);
} else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
} else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
if (GetKeyState(VK_CAPITAL) & 1)
SendMessage(selection.hwndSelectionMarkerEdit, EM_REPLACESEL, true, (LPARAM)insert_v);
@ -799,9 +890,9 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
break;
}
case ID_EDIT_PASTEINSERT:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, WM_PASTE, 0, 0);
else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
SendMessage(selection.hwndSelectionMarkerEdit, WM_PASTE, 0, 0);
else
splicer.PasteInsert();
@ -811,20 +902,11 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
case ID_CONTEXT_SELECTED_DELETEFRAMES:
splicer.DeleteFrames();
break;
case ACCEL_CTRL_T:
case ID_EDIT_TRUNCATE:
case ID_CONTEXT_SELECTED_TRUNCATE:
case ID_CONTEXT_STRAY_TRUNCATE:
case ID_STRAY_TRUNCATE:
splicer.Truncate();
break;
case ID_HELP_TASEDITHELP:
{
//OpenHelpWindow(tasedithelp);
std::string helpFileName = BaseDirectory;
helpFileName.append(taseditor_help_filename);
HtmlHelp(GetDesktopWindow(), helpFileName.c_str(), HH_DISPLAY_TOPIC, (DWORD)NULL);
break;
}
case ACCEL_INS:
case ID_EDIT_INSERT:
case MENU_CONTEXT_STRAY_INSERTFRAMES:
@ -839,14 +921,14 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
case ACCEL_DEL:
case ID_EDIT_CLEAR:
case ID_CONTEXT_SELECTED_CLEARFRAMES:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
DWORD sel_start, sel_end;
SendMessage(playback.hwndPlaybackMarkerEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
if (sel_start == sel_end)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETSEL, sel_start, sel_start + 1);
SendMessage(playback.hwndPlaybackMarkerEdit, WM_CLEAR, 0, 0);
} else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
} else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
DWORD sel_start, sel_end;
SendMessage(selection.hwndSelectionMarkerEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
@ -864,7 +946,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
taseditor_config.follow_playback ^= 1;
taseditor_window.UpdateCheckedItems();
// if switched off then maybe jump to target frame
if (!taseditor_config.follow_playback && playback.GetPauseFrame())
if (!taseditor_config.follow_playback && playback.pause_frame)
list.FollowPauseframe();
break;
case CHECK_TURBO_SEEK:
@ -1022,7 +1104,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
break;
case IDC_PROGRESS_BUTTON:
// click on progressbar - stop seeking
if (playback.GetPauseFrame()) playback.SeekingStop();
if (playback.pause_frame) playback.SeekingStop();
break;
case IDC_BRANCHES_BUTTON:
// click on "Bookmarks/Branches" - switch "View Tree of branches"
@ -1059,9 +1141,9 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
taseditor_window.UpdateCheckedItems();
break;
case ACCEL_CTRL_A:
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETSEL, 0, -1);
else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETSEL, 0, -1);
else
selection.SelectBetweenMarkers();
@ -1078,10 +1160,10 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
case ACCEL_CTRL_Z:
case ID_EDIT_UNDO:
{
if (marker_note_edit == MARKER_NOTE_EDIT_UPPER)
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
SendMessage(playback.hwndPlaybackMarkerEdit, WM_UNDO, 0, 0);
} else if (marker_note_edit == MARKER_NOTE_EDIT_LOWER)
} else if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
SendMessage(selection.hwndSelectionMarkerEdit, WM_UNDO, 0, 0);
} else
@ -1149,9 +1231,9 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
bool changes_made = false;
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
{
if(!current_markers.GetMarker(*it))
if(!markers_manager.GetMarker(*it))
{
if (current_markers.SetMarker(*it))
if (markers_manager.SetMarker(*it))
{
changes_made = true;
list.RedrawRow(*it);
@ -1176,9 +1258,9 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
bool changes_made = false;
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
{
if(current_markers.GetMarker(*it))
if(markers_manager.GetMarker(*it))
{
current_markers.ClearMarker(*it);
markers_manager.ClearMarker(*it);
changes_made = true;
list.RedrawRow(*it);
}
@ -1215,16 +1297,10 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
break;
}
case TASEDITOR_FIND_BEST_SIMILAR_MARKER:
search_similar_marker = 0;
current_markers.FindSimilar(search_similar_marker);
search_similar_marker++;
markers_manager.FindSimilar();
break;
case TASEDITOR_FIND_NEXT_SIMILAR_MARKER:
current_markers.FindSimilar(search_similar_marker);
search_similar_marker++;
break;
case ID_HELP_ABOUT:
DialogBox(fceu_hInstance, MAKEINTRESOURCE(IDD_TASEDITOR_ABOUT), taseditor_window.hwndTasEditor, AboutProc);
markers_manager.FindNextSimilar();
break;
case TASEDITOR_RUN_MANUAL:
// the function will be called in next window update
@ -1234,6 +1310,21 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
taseditor_config.enable_auto_function ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_HELP_TASEDITHELP:
{
std::string helpFileName = BaseDirectory;
helpFileName.append(taseditor_help_filename);
HtmlHelp(GetDesktopWindow(), helpFileName.c_str(), HH_DISPLAY_TOPIC, (DWORD)NULL);
break;
}
case ID_HELP_TOOLTIPS:
taseditor_config.tooltips ^= 1;
taseditor_window.UpdateCheckedItems();
taseditor_window.UpdateTooltips();
break;
case ID_HELP_ABOUT:
DialogBox(fceu_hInstance, MAKEINTRESOURCE(IDD_TASEDITOR_ABOUT), taseditor_window.hwndTasEditor, AboutProc);
break;
}
@ -1252,20 +1343,3 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
}

View File

@ -1,5 +1,7 @@
//Specification file for TASEDITOR_WINDOW class
#define TASEDITOR_WINDOW_TOTAL_ITEMS 42
#define TOOLTIP_TEXT_MAX_LEN 80
#define TOOLTIPS_AUTOPOP_TIMEOUT 30000
enum ECONTEXTMENU
{
@ -16,11 +18,11 @@ public:
void reset();
void update();
void CalculateItems();
void ResizeItems();
void WindowMovedOrResized();
void UpdateTooltips();
void UpdateCaption();
void RedrawTaseditor();
@ -36,13 +38,16 @@ public:
void LoadRecentProject(int slot);
HWND hwndTasEditor, hwndFindNote;
HMENU hmenu, hrmenu;
HICON hTaseditorIcon;
bool TASEditor_focus;
bool ready_for_resizing;
int min_width;
int min_height;
private:
void CalculateItems();
HWND hToolTipWnd;
HMENU hmenu, hrmenu;
HICON hTaseditorIcon;
};

View File

@ -718,11 +718,6 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
if (movieSubtitles)
ProcessSubtitles();
#ifdef WIN32
if(FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
greenzone.TryDumpIncremental(lagFlag != 0);
#endif
}
void FCEUI_CloseGame(void)

View File

@ -54,11 +54,14 @@
#include "./drivers/win/taseditor/taseditor_window.h"
#include "./drivers/win/taseditor/markers.h"
#include "./drivers/win/taseditor/inputsnapshot.h"
#include "./drivers/win/taseditor/taseditor_sel.h"
#include "./drivers/win/taseditor/snapshot.h"
#include "./drivers/win/taseditor/bookmarks.h"
#include "./drivers/win/taseditor/playback.h"
extern bool Taseditor_rewind_now;
extern BOOKMARKS bookmarks;
extern TASEDITOR_WINDOW taseditor_window;
extern PLAYBACK playback;
#endif // WIN32
//it is easier to declare these input drivers extern here than include a bunch of files
@ -656,6 +659,7 @@ static void FCEUI_DoExit(void);
static void ToggleFullscreen(void);
static void TaseditorRewindOn(void);
static void TaseditorRewindOff(void);
static void TaseditorRestorePlayback(void);
struct EMUCMDTABLE FCEUI_CommandTable[]=
{
@ -686,7 +690,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_SAVE_SLOT_9, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 9", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SAVE_SLOT_NEXT, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Next Savestate Slot", 0 },
{ EMUCMD_SAVE_SLOT_PREV, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Previous Savestate Slot", 0 },
{ EMUCMD_SAVE_STATE, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State", 0 },
{ EMUCMD_SAVE_STATE, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SAVE_STATE_AS, EMUCMDTYPE_STATE, FCEUD_SaveStateAs, 0, 0, "Save State As...", 0 },
{ EMUCMD_SAVE_STATE_SLOT_0, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 0", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SAVE_STATE_SLOT_1, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 1", EMUCMDFLAG_TASEDITOR },
@ -698,7 +702,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_SAVE_STATE_SLOT_7, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 7", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SAVE_STATE_SLOT_8, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 8", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SAVE_STATE_SLOT_9, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 9", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_LOAD_STATE, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State", 0 },
{ EMUCMD_LOAD_STATE, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_LOAD_STATE_FROM, EMUCMDTYPE_STATE, FCEUD_LoadStateFrom, 0, 0, "Load State From...", 0 },
{ EMUCMD_LOAD_STATE_SLOT_0, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 0", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_LOAD_STATE_SLOT_1, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 1", EMUCMDFLAG_TASEDITOR },
@ -779,8 +783,9 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_TOOL_RAMSEARCHGTE, EMUCMDTYPE_TOOL, RamSearchOpGTE, 0, 0, "Ram Search - Greater Than or Equal", 0},
{ EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - Equal", 0},
{ EMUCMD_TOOL_RAMSEARCHNE, EMUCMDTYPE_TOOL, RamSearchOpNE, 0, 0, "Ram Search - Not Equal", 0},
{ EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_MISC, TaseditorRewindOn, TaseditorRewindOff, 0, "Rewind Frame (TAS Editor only)", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_MISC, TaseditorRewindOn, TaseditorRewindOff, 0, "Rewind Frame (TAS Editor)", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_RERECORD_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_MovieToggleRerecordDisplay, 0, 0, "Toggle Rerecord Display", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_TASEDITOR_RESTORE_PLAYBACK, EMUCMDTYPE_MISC, TaseditorRestorePlayback, 0, 0, "Restore Playback (TAS Editor)", EMUCMDFLAG_TASEDITOR },
};
#define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0]))
@ -840,7 +845,7 @@ static void CommandSelectSaveSlot(void)
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
#ifdef WIN32
bookmarks.jump(execcmd - EMUCMD_SAVE_SLOT_0);
bookmarks.command(COMMAND_JUMP, execcmd - EMUCMD_SAVE_SLOT_0);
#endif
} else
{
@ -858,7 +863,10 @@ static void CommandStateSave(void)
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
#ifdef WIN32
bookmarks.set(execcmd - EMUCMD_SAVE_STATE_SLOT_0);
if (execcmd == EMUCMD_SAVE_STATE)
bookmarks.command(COMMAND_SET, bookmarks.GetCurrentBranch());
else if(execcmd >= EMUCMD_SAVE_STATE_SLOT_0 && execcmd <= EMUCMD_SAVE_STATE_SLOT_9)
bookmarks.command(COMMAND_SET, execcmd - EMUCMD_SAVE_STATE_SLOT_0);
#endif
} else
{
@ -879,7 +887,10 @@ static void CommandStateLoad(void)
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{
#ifdef WIN32
bookmarks.unleash(execcmd - EMUCMD_LOAD_STATE_SLOT_0);
if (execcmd == EMUCMD_LOAD_STATE)
bookmarks.command(COMMAND_DEPLOY, bookmarks.GetCurrentBranch());
else if(execcmd >= EMUCMD_LOAD_STATE_SLOT_0 && execcmd <= EMUCMD_LOAD_STATE_SLOT_9)
bookmarks.command(COMMAND_DEPLOY, execcmd - EMUCMD_LOAD_STATE_SLOT_0);
#endif
} else
{
@ -1177,4 +1188,10 @@ static void TaseditorRewindOff(void)
#endif
}
static void TaseditorRestorePlayback(void)
{
#ifdef WIN32
playback.restorePosition();
#endif
}

View File

@ -232,9 +232,10 @@ enum EMUCMD
EMUCMD_TOOL_RAMSEARCHNE,
EMUCMD_TOOL_OPENNTVIEW,
EMUCMD_TASEDITOR_REWIND,
EMUCMD_RERECORD_DISPLAY_TOGGLE,
//-----------------------------
//keep adding these in order of newness or else the hotkey binding configs will get messed up...
EMUCMD_RERECORD_DISPLAY_TOGGLE,
EMUCMD_TASEDITOR_RESTORE_PLAYBACK,
EMUCMD_MAX
};

View File

@ -40,6 +40,9 @@
#ifdef WIN32
#include "drivers/win/common.h"
#include "drivers/win/taseditor/taseditor_sel.h"
#include "drivers/win/taseditor/markers.h"
#include "drivers/win/taseditor/snapshot.h"
#include "drivers/win/taseditor/taseditor_lua.h"
extern TASEDITOR_LUA taseditor_lua;
#endif
@ -2709,7 +2712,7 @@ int movie_isplaying (lua_State *L) {
//
//returns the rerecord count of the current movie
static int movie_rerecordcount (lua_State *L) {
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying())
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
luaL_error(L, "No movie loaded.");
lua_pushinteger(L, FCEUI_GetMovieRerecordCount());
@ -2722,7 +2725,7 @@ static int movie_rerecordcount (lua_State *L) {
//returns an int value representing the total length of the current movie loaded
static int movie_getlength (lua_State *L) {
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying())
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
luaL_error(L, "No movie loaded.");
lua_pushinteger(L, FCEUI_GetMovieLength());
@ -2754,7 +2757,7 @@ static int movie_setreadonly (lua_State *L) {
//returns the filename of the movie loaded
static int movie_getname (lua_State *L) {
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying())
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
luaL_error(L, "No movie loaded.");
std::string name = FCEUI_GetMovieName();
@ -2767,7 +2770,7 @@ static int movie_getname (lua_State *L) {
//returns the filename of movie loaded with no path
static int movie_getfilename (lua_State *L) {
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying())
if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
luaL_error(L, "No movie loaded.");
std::string name = FCEUI_GetMovieName();
@ -4418,6 +4421,17 @@ static int taseditor_getrecordermode(lua_State *L)
return 1;
}
// int taseditor.getlostplayback()
static int taseditor_getlostplayback(lua_State *L)
{
#ifdef WIN32
lua_pushinteger(L, taseditor_lua.getlostplayback());
#else
lua_pushinteger(L, -1);
#endif
return 1;
}
// int taseditor.getplaybacktarget()
static int taseditor_getplaybacktarget(lua_State *L)
{
@ -4447,8 +4461,124 @@ static int taseditor_stopseeking(lua_State *L)
return 0;
}
// table taseditor.getselection()
static int taseditor_getselection(lua_State *L)
{
#ifdef WIN32
// create temp vector and provide its reference to TAS Editor for filling the vector with data
std::vector<int> cur_set;
taseditor_lua.getselection(cur_set);
int size = cur_set.size();
if (size)
{
lua_createtable(L, size, 0);
for (int i = 0; i < size; ++i)
{
lua_pushinteger(L, cur_set[i]);
lua_rawseti(L, -2, i + 1);
}
} else
{
lua_pushnil(L);
}
#else
lua_pushnil(L);
#endif
return 1;
}
// taseditor.setselection(table new_set)
static int taseditor_setselection(lua_State *L)
{
#ifdef WIN32
std::vector<int> cur_set;
// retrieve new_set data from table to vector
if (!lua_isnil(L, 1))
{
luaL_checktype(L, 1, LUA_TTABLE);
int max_index = luaL_getn(L, 1);
int i = 1;
while (i <= max_index)
{
lua_rawgeti(L, 1, i);
cur_set.push_back(lua_tonumber(L, -1));
lua_pop(L, 1);
i++;
}
}
// and provide its reference to TAS Editor for changing selection
taseditor_lua.setselection(cur_set);
#endif
return 0;
}
// int taseditor.getinput(int frame, int joypad)
static int taseditor_getinput(lua_State *L)
{
#ifdef WIN32
lua_pushinteger(L, taseditor_lua.getinput(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)));
#else
lua_pushinteger(L, -1);
#endif
return 1;
}
// taseditor.submitinputchange(int frame, int joypad, int input)
static int taseditor_submitinputchange(lua_State *L)
{
#ifdef WIN32
taseditor_lua.submitinputchange(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3));
#endif
return 0;
}
// taseditor.submitinsertframes(int frame, int joypad, int input)
static int taseditor_submitinsertframes(lua_State *L)
{
#ifdef WIN32
taseditor_lua.submitinsertframes(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2));
#endif
return 0;
}
// taseditor.submitdeleteframes(int frame, int joypad, int input)
static int taseditor_submitdeleteframes(lua_State *L)
{
#ifdef WIN32
taseditor_lua.submitdeleteframes(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2));
#endif
return 0;
}
// int taseditor.applyinputchanges([string name])
static int taseditor_applyinputchanges(lua_State *L)
{
#ifdef WIN32
if (lua_isnil(L, 1))
{
lua_pushinteger(L, taseditor_lua.applyinputchanges(""));
} else
{
const char* name = lua_tostring(L, 1);
if (name)
lua_pushinteger(L, taseditor_lua.applyinputchanges(name));
else
lua_pushinteger(L, taseditor_lua.applyinputchanges(""));
}
#else
lua_pushinteger(L, -1);
#endif
return 1;
}
// taseditor.clearinputchanges()
static int taseditor_clearinputchanges(lua_State *L)
{
#ifdef WIN32
taseditor_lua.clearinputchanges();
#endif
return 0;
}
static int doPopup(lua_State *L, const char* deftype, const char* deficon) {
@ -5221,9 +5351,18 @@ static const struct luaL_reg taseditorlib[] = {
{"setnote", taseditor_setnote},
{"getcurrentbranch", taseditor_getcurrentbranch},
{"getrecordermode", taseditor_getrecordermode},
{"getlostplayback", taseditor_getlostplayback},
{"getplaybacktarget", taseditor_getplaybacktarget},
{"setplayback", taseditor_setplayback},
{"stopseeking", taseditor_stopseeking},
{"getselection", taseditor_getselection},
{"setselection", taseditor_setselection},
{"getinput", taseditor_getinput},
{"submitinputchange", taseditor_submitinputchange},
{"submitinsertframes", taseditor_submitinsertframes},
{"submitdeleteframes", taseditor_submitdeleteframes},
{"applyinputchanges", taseditor_applyinputchanges},
{"clearinputchanges", taseditor_clearinputchanges},
{NULL,NULL}
};

View File

@ -979,9 +979,9 @@ void FCEUMOV_AddInputState()
#ifdef _WIN32
if(movieMode == MOVIEMODE_TASEDITOR)
{
// if movie length is less than currFrame, pad it with empty frames
if((int)currMovieData.records.size() <= currFrameCounter)
currMovieData.insertEmpty(-1, 1 + currFrameCounter - (int)currMovieData.records.size());
// if movie length is less or equal to currFrame, pad it with empty frames
if((int)currMovieData.records.size()-1 <= currFrameCounter)
currMovieData.insertEmpty(-1, 2 + currFrameCounter - (int)currMovieData.records.size());
MovieRecord* mr = &currMovieData.records[currFrameCounter];
if(movie_readonly || turbo || playback.pause_frame > currFrameCounter)
@ -1001,6 +1001,9 @@ void FCEUMOV_AddInputState()
joyports[0].log(mr);
joyports[1].log(mr);
recorder.InputChanged();
// return data from movie to joyports in case Recorder changed it (for example, by applying Superimpose)
joyports[0].load(mr);
joyports[1].load(mr);
}
_currCommand = 0;
} else

View File

@ -424,12 +424,13 @@
<ClCompile Include="..\src\drivers\win\taseditor\bookmark.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\bookmarks.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\greenzone.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\inputhistory.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\inputsnapshot.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\history.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\markers.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\markers_manager.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\playback.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\popup_display.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\recorder.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\snapshot.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\splicer.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\taseditor_config.cpp" />
<ClCompile Include="..\src\drivers\win\taseditor\taseditor_list.cpp" />
@ -750,12 +751,13 @@
<ClInclude Include="..\src\drivers\win\taseditor\bookmark.h" />
<ClInclude Include="..\src\drivers\win\taseditor\bookmarks.h" />
<ClInclude Include="..\src\drivers\win\taseditor\greenzone.h" />
<ClInclude Include="..\src\drivers\win\taseditor\inputhistory.h" />
<ClInclude Include="..\src\drivers\win\taseditor\inputsnapshot.h" />
<ClInclude Include="..\src\drivers\win\taseditor\history.h" />
<ClInclude Include="..\src\drivers\win\taseditor\markers.h" />
<ClInclude Include="..\src\drivers\win\taseditor\markers_manager.h" />
<ClInclude Include="..\src\drivers\win\taseditor\playback.h" />
<ClInclude Include="..\src\drivers\win\taseditor\popup_display.h" />
<ClInclude Include="..\src\drivers\win\taseditor\recorder.h" />
<ClInclude Include="..\src\drivers\win\taseditor\snapshot.h" />
<ClInclude Include="..\src\drivers\win\taseditor\splicer.h" />
<ClInclude Include="..\src\drivers\win\taseditor\taseditor_config.h" />
<ClInclude Include="..\src\drivers\win\taseditor\taseditor_list.h" />
@ -866,6 +868,8 @@
<ResourceCompile Include="..\src\drivers\win\res.rc" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\tasedit\psd\bmp\te_green_arrow.bmp" />
<None Include="..\src\drivers\win\res\bitmap20.bmp" />
<None Include="..\src\drivers\win\res\branch_spritesheet.bmp" />
<None Include="..\src\drivers\win\res\icon3.ico" />
<None Include="..\src\drivers\win\res\icon4.ico" />
@ -908,6 +912,7 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)auxlib.lua;%(Outputs)</Outputs>
</CustomBuild>
<None Include="..\src\drivers\win\res\te_green_arrow.bmp" />
<None Include="..\src\pputile.inc" />
<None Include="ClassDiagram1.cd" />
</ItemGroup>

View File

@ -940,12 +940,6 @@
<ClCompile Include="..\src\drivers\win\taseditor\greenzone.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\inputhistory.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\inputsnapshot.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\markers.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
@ -955,6 +949,15 @@
<ClCompile Include="..\src\drivers\win\taseditor\popup_display.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\history.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\snapshot.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
<ClCompile Include="..\src\drivers\win\taseditor\markers_manager.cpp">
<Filter>drivers\win\taseditor</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\cart.h">
@ -1432,18 +1435,21 @@
<ClInclude Include="..\src\drivers\win\taseditor\greenzone.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\inputhistory.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\inputsnapshot.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\markers.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\playback.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\history.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\snapshot.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
<ClInclude Include="..\src\drivers\win\taseditor\markers_manager.h">
<Filter>drivers\win\taseditor</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\src\drivers\win\res.rc">
@ -1529,6 +1535,9 @@
<None Include="..\src\drivers\win\res\icon4.ico" />
<None Include="..\src\drivers\win\res\taseditor-icon.ico" />
<None Include="..\src\drivers\win\res\taseditor-icon32.ico" />
<None Include="..\src\drivers\win\res\bitmap20.bmp" />
<None Include="..\..\..\tasedit\psd\bmp\te_green_arrow.bmp" />
<None Include="..\src\drivers\win\res\te_green_arrow.bmp" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\src\auxlib.lua" />