From 80662af1d3e89b5204677be4a37f6a50fb1b2e72 Mon Sep 17 00:00:00 2001 From: ansstuff Date: Mon, 7 Nov 2011 16:02:25 +0000 Subject: [PATCH] * Tasedit: Keeping track of branching activities * Tasedit: "Branches mode" of Bookmarks window * Tasedit: Drawing Branches Tree (using GDI), animations, transitions, mouseover --- src/drivers/win/config.cpp | 2 + src/drivers/win/res.rc | 79 +- src/drivers/win/res/branch_spritesheet.bmp | Bin 0 -> 23814 bytes src/drivers/win/res/te_0.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_1.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_10.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_11.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_12.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_13.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_14.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_15.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_16.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_17.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_18.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_19.bmp | Bin 0 -> 418 bytes src/drivers/win/res/te_2.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_3.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_4.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_5.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_6.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_7.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_8.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_9.bmp | Bin 1234 -> 418 bytes src/drivers/win/res/te_arrow.bmp | Bin 1234 -> 418 bytes src/drivers/win/resource.h | 22 +- src/drivers/win/tasedit.cpp | 129 +++- src/drivers/win/tasedit.h | 4 +- src/drivers/win/taseditlib/bookmark.cpp | 16 +- src/drivers/win/taseditlib/bookmark.h | 4 +- src/drivers/win/taseditlib/bookmarks.cpp | 783 +++++++++++++++++++- src/drivers/win/taseditlib/bookmarks.h | 129 +++- src/drivers/win/taseditlib/greenzone.cpp | 12 +- src/drivers/win/taseditlib/inputhistory.cpp | 13 +- src/drivers/win/taseditlib/markers.cpp | 11 +- src/drivers/win/taseditlib/markers.h | 1 + src/drivers/win/taseditlib/playback.cpp | 8 +- vc/vc10_fceux.vcxproj | 24 + vc/vc10_fceux.vcxproj.filters | 24 + 38 files changed, 1150 insertions(+), 111 deletions(-) create mode 100644 src/drivers/win/res/branch_spritesheet.bmp create mode 100644 src/drivers/win/res/te_10.bmp create mode 100644 src/drivers/win/res/te_11.bmp create mode 100644 src/drivers/win/res/te_12.bmp create mode 100644 src/drivers/win/res/te_13.bmp create mode 100644 src/drivers/win/res/te_14.bmp create mode 100644 src/drivers/win/res/te_15.bmp create mode 100644 src/drivers/win/res/te_16.bmp create mode 100644 src/drivers/win/res/te_17.bmp create mode 100644 src/drivers/win/res/te_18.bmp create mode 100644 src/drivers/win/res/te_19.bmp diff --git a/src/drivers/win/config.cpp b/src/drivers/win/config.cpp index c93522dd..b6b2ffc7 100644 --- a/src/drivers/win/config.cpp +++ b/src/drivers/win/config.cpp @@ -74,6 +74,7 @@ extern bool TASEdit_show_markers; extern bool TASEdit_bind_markers; extern bool TASEdit_branch_full_movie; extern bool TASEdit_branch_only_when_rec; +extern bool TASEdit_view_branches_tree; extern bool TASEdit_restore_position; extern bool TASEdit_show_dot; extern int TASEdit_greenzone_capacity; @@ -302,6 +303,7 @@ static CFGSTRUCT fceuconfig[] = { AC(TASEdit_bind_markers), AC(TASEdit_branch_full_movie), AC(TASEdit_branch_only_when_rec), + AC(TASEdit_view_branches_tree), AC(TASEdit_restore_position), AC(TASEdit_show_dot), AC(TASEdit_greenzone_capacity), diff --git a/src/drivers/win/res.rc b/src/drivers/win/res.rc index 8c420d9e..5ecfc108 100644 --- a/src/drivers/win/res.rc +++ b/src/drivers/win/res.rc @@ -1352,38 +1352,48 @@ BEGIN EDITTEXT IDC_LABEL_NEWPPUUSED,76,166,155,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP END -TASEDIT DIALOGEX 0, 0, 438, 380 +TASEDIT DIALOGEX 0, 0, 438, 396 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "TAS Editor" MENU TASEDITMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER,6,5,299,370 - GROUPBOX " Playback ",IDC_STATIC,310,5,123,62,BS_CENTER,WS_EX_RIGHT - PUSHBUTTON "<<",TASEDIT_REWIND_FULL,314,14,23,14,NOT WS_TABSTOP - PUSHBUTTON "<",TASEDIT_REWIND,337,14,23,14,NOT WS_TABSTOP - PUSHBUTTON "||",TASEDIT_PLAYSTOP,360,14,23,14,NOT WS_TABSTOP - PUSHBUTTON ">",TASEDIT_FORWARD,383,14,23,14,NOT WS_TABSTOP - PUSHBUTTON ">>",TASEDIT_FORWARD_FULL,406,14,23,14,NOT WS_TABSTOP - CONTROL "",IDC_PROGRESS_BUTTON,"Button",BS_OWNERDRAW | WS_TABSTOP,314,42,116,10 - CONTROL "",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | WS_BORDER,314,44,115,6 - CONTROL " Follow cursor",CHECK_FOLLOW_CURSOR,"Button",BS_AUTOCHECKBOX,316,30,105,12 + CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER,6,15,299,362 + GROUPBOX " Playback ",IDC_STATIC,310,1,123,62,BS_CENTER,WS_EX_RIGHT + PUSHBUTTON "<<",TASEDIT_REWIND_FULL,314,10,23,14,NOT WS_TABSTOP + PUSHBUTTON "<",TASEDIT_REWIND,337,10,23,14,NOT WS_TABSTOP + PUSHBUTTON "||",TASEDIT_PLAYSTOP,360,10,23,14,NOT WS_TABSTOP + PUSHBUTTON ">",TASEDIT_FORWARD,383,10,23,14,NOT WS_TABSTOP + PUSHBUTTON ">>",TASEDIT_FORWARD_FULL,406,10,23,14,NOT WS_TABSTOP + CONTROL "",IDC_PROGRESS_BUTTON,"Button",BS_OWNERDRAW,314,38,116,10 + CONTROL "",IDC_BRANCHES_BUTTON,"Button",BS_OWNERDRAW,320,151,104,11 + CONTROL "",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | WS_BORDER,314,40,115,6 + CONTROL " Follow cursor",CHECK_FOLLOW_CURSOR,"Button",BS_AUTOCHECKBOX,316,26,105,12 CONTROL " Auto-restore last position",CHECK_AUTORESTORE_PLAYBACK, - "Button",BS_AUTOCHECKBOX,316,53,105,12 - GROUPBOX " Recording ",IDC_STATIC,310,68,123,48,BS_CENTER,WS_EX_RIGHT - GROUPBOX " Editing ",IDC_STATIC,310,118,123,38,BS_CENTER,WS_EX_RIGHT - GROUPBOX " Bookmarks ",IDC_BOOKMARKS_BOX,310,158,123,103,BS_CENTER,WS_EX_RIGHT - CONTROL "",IDC_BOOKMARKSLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,168,113,89 - CONTROL "",IDC_HISTORYLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,273,113,99 - CONTROL " OFF",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,316,78,27,10 - CONTROL " ON",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,316,91,27,10 - CONTROL " 1P",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,373,78,25,10 - CONTROL " 2P",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,402,78,23,10 - CONTROL " 3P",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,373,91,25,10 - CONTROL " 4P",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,402,91,23,10 - CONTROL " Superimpose",IDC_SUPERIMPOSE,"Button",BS_AUTOCHECKBOX,316,104,56,10 - CONTROL " Omit blank",IDC_OMITBLANK,"Button",BS_AUTOCHECKBOX,377,104,51,10 - GROUPBOX " History ",IDC_STATIC,310,263,123,113,BS_CENTER,WS_EX_RIGHT + "Button",BS_AUTOCHECKBOX,316,49,105,12 + GROUPBOX " Recording ",IDC_STATIC,310,64,123,48,BS_CENTER,WS_EX_RIGHT + GROUPBOX " Editing ",IDC_STATIC,310,113,123,37,BS_CENTER,WS_EX_RIGHT + GROUPBOX " Bookmarks ",IDC_BOOKMARKS_BOX,310,152,123,103,BS_CENTER,WS_EX_RIGHT + CONTROL "",IDC_BOOKMARKSLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | NOT WS_VISIBLE | WS_BORDER,315,162,113,89 + CONTROL "",IDC_HISTORYLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,267,113,100 + CONTROL " OFF",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,316,74,27,10 + CONTROL " ON",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,316,87,27,10 + CONTROL " 1P",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,373,74,25,10 + CONTROL " 2P",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,402,74,23,10 + CONTROL " 3P",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,373,87,25,10 + CONTROL " 4P",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,402,87,23,10 + CONTROL " Superimpose",IDC_SUPERIMPOSE,"Button",BS_AUTOCHECKBOX,316,100,56,10 + CONTROL " Omit blank",IDC_OMITBLANK,"Button",BS_AUTOCHECKBOX,377,100,51,10 + GROUPBOX " History ",IDC_STATIC,310,257,123,114,BS_CENTER,WS_EX_RIGHT + EDITTEXT IDC_EDIT1,54,377,251,13,ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "<<",TASEDIT_REWIND_FULL2,315,376,23,14,NOT WS_TABSTOP + PUSHBUTTON "Find",TASEDIT_REWIND_FULL3,338,376,34,14,WS_DISABLED | NOT WS_TABSTOP + PUSHBUTTON "Next",TASEDIT_REWIND_FULL4,372,376,34,14,WS_DISABLED | NOT WS_TABSTOP + PUSHBUTTON ">>",TASEDIT_REWIND_FULL5,405,376,23,14,NOT WS_TABSTOP + RTEXT "Marker 99999",IDC_STATIC,6,379,45,10,0,WS_EX_RIGHT + RTEXT "Marker 0",IDC_STATIC,6,3,45,10,0,WS_EX_RIGHT + EDITTEXT IDC_EDIT2,54,1,251,13,ES_READONLY | NOT WS_TABSTOP + CONTROL "",IDC_BRANCHES_BITMAP,"Static",SS_OWNERDRAW | SS_NOTIFY | SS_REALSIZEIMAGE | NOT WS_VISIBLE,315,162,113,89 END ASSEMBLER DIALOGEX 0, 0, 202, 135 @@ -1890,10 +1900,6 @@ BEGIN "TASEDIT", DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 436 - TOPMARGIN, 5 - BOTTOMMARGIN, 374 END "ASSEMBLER", DIALOG @@ -2064,7 +2070,6 @@ END // Bitmap // -IDB_TE_ARROW BITMAP "res/te_arrow.bmp" IDB_BITMAP0 BITMAP "res\\te_0.bmp" IDB_BITMAP1 BITMAP "res\\te_1.bmp" IDB_BITMAP2 BITMAP "res\\te_2.bmp" @@ -2075,6 +2080,18 @@ IDB_BITMAP6 BITMAP "res\\te_6.bmp" IDB_BITMAP7 BITMAP "res\\te_7.bmp" IDB_BITMAP8 BITMAP "res\\te_8.bmp" IDB_BITMAP9 BITMAP "res\\te_9.bmp" +IDB_BITMAP10 BITMAP "res\\te_10.bmp" +IDB_BITMAP11 BITMAP "res\\te_11.bmp" +IDB_BITMAP12 BITMAP "res\\te_12.bmp" +IDB_BITMAP13 BITMAP "res\\te_13.bmp" +IDB_BITMAP14 BITMAP "res\\te_14.bmp" +IDB_BITMAP15 BITMAP "res\\te_15.bmp" +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_BRANCH_SPRITESHEET BITMAP "res\\branch_spritesheet.bmp" #endif // Английский (США) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/drivers/win/res/branch_spritesheet.bmp b/src/drivers/win/res/branch_spritesheet.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9a532b98717a741e4ad783ff295a4ea022fc9c7d GIT binary patch literal 23814 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 a388N=$)R};=rn{o@yQYJ1KigT1_J=Gj3{XU literal 1234 zcmZ?ry~M%*24+B71IXe8VqPF-WZ(dc&jFKAf)PUhXZX+Xam!j{nNjv=2#kin$P58S cAb|NCnazL@29_sqB_y+vj0YNn!yK3c0N|(w@Bjb+ diff --git a/src/drivers/win/res/te_10.bmp b/src/drivers/win/res/te_10.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2445c23a4e09f2b12d7cdbd5af53d4df181701e3 GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{86Ln1 H>}CJ}uKO?G literal 0 HcmV?d00001 diff --git a/src/drivers/win/res/te_14.bmp b/src/drivers/win/res/te_14.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8573ca3fdb8c0c430636ecda25534418e170a4ec GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{86l7`6v9Q3gE#;t0pua+!!8FDg)4_Mp!$$?V3&jI21xq;@HWSE3F%!ES%mOr;0RWp8DS7|^ literal 0 HcmV?d00001 diff --git a/src/drivers/win/res/te_16.bmp b/src/drivers/win/res/te_16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..628909978af262057f055a08c7eb91e9c36a1fb9 GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{86W+Ka>yA$pf7=uW6BAW?hL;V1xF(i=WV0IwW3;pg7?+@1U7LP)3_R%wJBrZkEinl!o`TpGv#$w3?fWIzC%i;#mm6-5rH98&@)h{Zmr(Lgx> D8Sw(h literal 1234 zcmZ?ry~M%*24+B71IXe8VqPF-WZ(dc&jFKAf)PUhXZX+Xam!j{nNjv=2#kinNDKi+ e2mpH>jg1HnpadBlsF^?tsvX&Upcsm&Q1b!ih6e)x diff --git a/src/drivers/win/res/te_3.bmp b/src/drivers/win/res/te_3.bmp index 1894d65c49be6b7dd5e82ceaef3ca4cd53bd6e2a..5c46c0c79b12712707daa5577d96623c1d5ba8f6 100644 GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{86W08aF#x4gDg~|Z{@ud!` literal 1234 zcmZ?ry~M%*24+B71IXe8VqPF-WZ(dc&jFKAf)PUhXZX+Xam!j{nNjv=2#kinNDTo- nXu$yTKQ=Za1b~AFm5opj(g)WIWWd=#7J?1pAVL|L4HX3d9@!j3NTO;3>i|n4>qV$$008F#2L}KE diff --git a/src/drivers/win/res/te_6.bmp b/src/drivers/win/res/te_6.bmp index c34537efc4521615f1322d1d164a8ebc9dd104a6..9f55852e06fa9641b3fcfaf246e9dcb8e6402592 100644 GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{86nuAc!fW$gTVE)8UWpAKtQ=$;06+HAH-&K^80@V0BUmZ-T(jq literal 1234 zcmZ?ry~M%*24+B71IXe8VqPF-WZ(dc&jFKAf)PUhXZX+Xam!j{nNjv=2#kinhztQn c5PXE`70O;cf3;+NC diff --git a/src/drivers/win/res/te_9.bmp b/src/drivers/win/res/te_9.bmp index f6c95cb83f02fb1539dcca1bc99184405152f7fb..6e864e59612dd84545e91887235a60a0dbc5ea71 100644 GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{86eG9VjjCfp9VG*AQxpkW5# Hppgs!JJIst literal 1234 zcmZ?ry~M%*24+B71IXe8VqPF-WZ(dc&jFKAf)PUhXZX+Xam!j{nNjv=2#kinhztQn l5PV#kE|D!4c38V8H9;M0s!cL2MYiI diff --git a/src/drivers/win/res/te_arrow.bmp b/src/drivers/win/res/te_arrow.bmp index 1ef873ea7b06e4f76785262dab4cb49ea1980632..27a905d461a7c9e78c384cee6ffb9cd6806528ab 100644 GIT binary patch literal 418 zcmZ?rUBt)$24+A~1Bf|+m=}l{865PXGV_ literal 1234 zcmZ?ry~M%*24+B71IXe8VqPF-WZ(dc&jFKAf)PUhXZX+Xam!j{nNjv=2#kinNDKi+ qXrTb|J0lVY$cD>+*f0*54dp=C5DtboG%!Kpuy93U0_}o{qR;^5Q3nG6 diff --git a/src/drivers/win/resource.h b/src/drivers/win/resource.h index c7ecb29b..5a4b58b2 100644 --- a/src/drivers/win/resource.h +++ b/src/drivers/win/resource.h @@ -169,6 +169,17 @@ #define IDB_BITMAP7 170 #define IDB_BITMAP8 171 #define IDB_BITMAP9 172 +#define IDB_BITMAP10 173 +#define IDB_BITMAP11 174 +#define IDB_BITMAP12 175 +#define IDB_BITMAP13 176 +#define IDB_BITMAP14 177 +#define IDB_BITMAP15 178 +#define IDB_BITMAP16 179 +#define IDB_BITMAP17 180 +#define IDB_BITMAP18 181 +#define IDB_BITMAP19 182 +#define IDB_BRANCH_SPRITESHEET 184 #define MENU_RESET 200 #define BUTTON_ROMS 200 #define TXT_PAD1 200 @@ -403,11 +414,17 @@ #define MEMW_EDIT02FORMULA 1144 #define IDC_BUTTON7 1145 #define MEMW_EDIT03FORMULA 1145 +#define TASEDIT_REWIND_FULL2 1145 #define IDC_BUTTON8 1146 +#define TASEDIT_REWIND_FULL3 1146 #define IDC_EDIT1 1147 #define IDC_BUTTON9 1148 +#define TASEDIT_REWIND_FULL4 1148 #define IDC_HISTORYLIST 1149 #define IDC_BOOKMARKSLIST 1150 +#define TASEDIT_REWIND_FULL5 1151 +#define IDC_BRANCHES_BUTTON 1152 +#define IDC_EDIT2 1154 #define CHECK_SOUND_MUTETURBO 1179 #define IDC_EDIT_AUTHOR 1180 #define MEMW_STATIC 1181 @@ -511,6 +528,7 @@ #define IDC_PROGRESS1 1262 #define CHECK_FOLLOW_CURSOR 1263 #define IDC_BOOKMARKS_BOX 1264 +#define IDC_BRANCHES_BITMAP 1265 #define MENU_NETWORK 40040 #define MENU_PALETTE 40041 #define MENU_SOUND 40042 @@ -880,9 +898,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 173 +#define _APS_NEXT_RESOURCE_VALUE 185 #define _APS_NEXT_COMMAND_VALUE 40475 -#define _APS_NEXT_CONTROL_VALUE 1265 +#define _APS_NEXT_CONTROL_VALUE 1266 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/drivers/win/tasedit.cpp b/src/drivers/win/tasedit.cpp index 59dee913..eae9cd0f 100644 --- a/src/drivers/win/tasedit.cpp +++ b/src/drivers/win/tasedit.cpp @@ -39,6 +39,7 @@ bool TASEdit_show_markers = true; bool TASEdit_bind_markers = true; bool TASEdit_branch_full_movie = true; bool TASEdit_branch_only_when_rec = false; +bool TASEdit_view_branches_tree = false; bool TASEdit_restore_position = false; int TASEdit_greenzone_capacity = GREENZONE_CAPACITY_DEFAULT; extern bool muteTurbo; @@ -67,6 +68,8 @@ HWND hwndBookmarksList, hwndBookmarks; WNDPROC hwndBookmarksList_oldWndProc; HWND hwndProgressbar, hwndRewind, hwndForward, hwndRewindFull, hwndForwardFull; HWND hwndRB_RecOff, hwndRB_RecAll, hwndRB_Rec1P, hwndRB_Rec2P, hwndRB_Rec3P, hwndRB_Rec4P; +HWND hwndBranchesBitmap; +WNDPROC hwndBranchesBitmap_oldWndProc; HFONT hMainListFont; @@ -101,8 +104,6 @@ void GetDispInfo(NMLVDISPINFO* nmlvDispInfo) { if (item.iItem == currFrameCounter) item.iImage = ARROW_IMAGE_ID; - else - item.iImage = -1; } } break; @@ -274,7 +275,7 @@ void UpdateTasEdit() { if(!hwndTasEdit) return; - UpdateList(); + UpdateList(); // also markers are updated there greenzone.update(); playback.update(); @@ -349,11 +350,19 @@ void RedrawTasedit() InvalidateRect(hwndTasEdit, 0, FALSE); } void RedrawList() +{ + InvalidateRect(hwndList, 0, FALSE); +} +void RedrawListAndBookmarks() { InvalidateRect(hwndList, 0, FALSE); bookmarks.RedrawBookmarksList(); } void RedrawRow(int index) +{ + ListView_RedrawItems(hwndList, index, index); +} +void RedrawRowAndBookmark(int index) { ListView_RedrawItems(hwndList, index, index); bookmarks.RedrawChangedBookmarks(index); @@ -592,6 +601,8 @@ void Truncate() if (currMovieData.getNumRecords() > frame+1) { currMovieData.truncateAt(frame+1); + if (TASEdit_bind_markers) + markers.truncateAt(frame+1); UpdateList(); int result = history.RegisterChanges(MODTYPE_TRUNCATE, frame+1); if (result >= 0) @@ -981,7 +992,7 @@ LRESULT APIENTRY BookmarksListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM return CallWindowProc(hwndBookmarksList_oldWndProc, hWnd, msg, wParam, lParam); } -LRESULT APIENTRY HistoryListWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +LRESULT APIENTRY HistoryListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { @@ -1000,6 +1011,46 @@ LRESULT APIENTRY HistoryListWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lPar return CallWindowProc(hwndHistoryList_oldWndProc, hWnd, msg, wParam, lParam); } +LRESULT APIENTRY BranchesBitmapWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_MOUSEMOVE: + { + if (!bookmarks.mouse_over_bitmap) + { + bookmarks.mouse_over_bitmap = true; + bookmarks.tme.hwndTrack = hWnd; + TrackMouseEvent(&bookmarks.tme); + } + bookmarks.MouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + } + case WM_MOUSELEAVE: + { + bookmarks.mouse_over_bitmap = false; + bookmarks.MouseMove(-1, -1); + break; + } + case WM_SYSKEYDOWN: + { + if (wParam == VK_F10) + return 0; + break; + } + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + bookmarks.PaintBranchesBitmap(hdc); + EndPaint(hWnd, &ps); + return 0; + } + } + return CallWindowProc(hwndBranchesBitmap_oldWndProc, hWnd, msg, wParam, lParam); +} + + void AddFourscore() { // add list columns @@ -1138,7 +1189,6 @@ void OpenProject() FollowPlayback(); RedrawTasedit(); RedrawWindowCaption(); - bookmarks.RedrawBookmarksCaption(); } } @@ -1315,6 +1365,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar hwndRB_Rec2P = GetDlgItem(hwndDlg, IDC_RADIO4); hwndRB_Rec3P = GetDlgItem(hwndDlg, IDC_RADIO5); hwndRB_Rec4P = GetDlgItem(hwndDlg, IDC_RADIO6); + hwndBranchesBitmap = GetDlgItem(hwndDlg, IDC_BRANCHES_BITMAP); break; case WM_MOVE: @@ -1420,8 +1471,8 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar ExitTasEdit(); break; - case WM_ACTIVATEAPP: - if((BOOL)wParam) + case WM_ACTIVATE: + if(LOWORD(wParam)) GotFocus(); else LostFocus(); @@ -1540,7 +1591,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar //switch "Highlight lag frames" flag TASEdit_show_lag_frames ^= 1; CheckMenuItem(hmenu, ID_VIEW_SHOW_LAG_FRAMES, TASEdit_show_lag_frames?MF_CHECKED : MF_UNCHECKED); - RedrawList(); + RedrawListAndBookmarks(); break; case ID_VIEW_SHOW_MARKERS: //switch "Show Markers" flag @@ -1625,6 +1676,11 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar // click on progressbar - stop seeking if (playback.pauseframe) playback.SeekingStop(); break; + case IDC_BRANCHES_BUTTON: + // click on "Bookmarks/Branches" - switch "View Tree of branches" + TASEdit_view_branches_tree ^= 1; + bookmarks.RedrawBookmarksCaption(); + break; case IDC_RADIO1: // switch to readonly, no need to recheck radiobuttons if (!movie_readonly) FCEUI_MovieToggleReadOnly(); @@ -1838,6 +1894,7 @@ void EnterTasEdit() SetWindowPos(hwndTasEdit,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER); + // init modules greenzone.init(); playback.init(); // either start new movie or use current movie @@ -1877,37 +1934,67 @@ void EnterTasEdit() // setup images for the listview HIMAGELIST himglist = ImageList_Create(9, 13, ILC_COLOR8 | ILC_MASK, 1, 1); HBITMAP bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP0)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP2)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP3)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP4)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP5)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP6)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP7)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP8)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP9)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP10)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP11)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP12)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP13)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP14)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP15)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP16)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP17)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP18)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); + DeleteObject(bmp); + bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BITMAP19)); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); bmp = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_TE_ARROW)); - ImageList_AddMasked(himglist, bmp, 0xFF00FF); + ImageList_AddMasked(himglist, bmp, 0xFFFFFF); DeleteObject(bmp); ListView_SetImageList(hwndList, himglist, LVSIL_SMALL); // setup columns @@ -1967,6 +2054,9 @@ void EnterTasEdit() lvc.fmt = LVCFMT_LEFT; ListView_InsertColumn(hwndHistoryList, 0, &lvc); + // subclass BranchesBitmap + hwndBranchesBitmap_oldWndProc = (WNDPROC)SetWindowLong(hwndBranchesBitmap, GWL_WNDPROC, (LONG)BranchesBitmapWndProc); + // init variables markers.init(); project.init(); @@ -1995,6 +2085,7 @@ bool ExitTasEdit() // clear "Background TASEdit input" KeyboardClearBackgroundAccessBit(KEYBACKACCESS_TASEDIT); JoystickClearBackgroundAccessBit(JOYBACKACCESS_TASEDIT); + // release memory markers.free(); greenzone.clearGreenzone(); diff --git a/src/drivers/win/tasedit.h b/src/drivers/win/tasedit.h index 2fd815d3..21c1f3d4 100644 --- a/src/drivers/win/tasedit.h +++ b/src/drivers/win/tasedit.h @@ -58,7 +58,7 @@ #define COLUMN_JOYPAD4_R 33 #define COLUMN_FRAMENUM2 34 #define DIGITS_IN_FRAMENUM 7 -#define ARROW_IMAGE_ID 10 +#define ARROW_IMAGE_ID 20 // listview colors #define NORMAL_FRAMENUM_COLOR 0xFFFFFF #define NORMAL_INPUT_COLOR1 0xEDEDED @@ -116,7 +116,9 @@ void RemoveFourscore(); void RedrawWindowCaption(); void RedrawTasedit(); void RedrawList(); +void RedrawListAndBookmarks(); void RedrawRow(int index); +void RedrawRowAndBookmark(int index); void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags); void SwitchToReadOnly(); void UncheckRecordingRadioButtons(); diff --git a/src/drivers/win/taseditlib/bookmark.cpp b/src/drivers/win/taseditlib/bookmark.cpp index b5ff9c9e..b9830d28 100644 --- a/src/drivers/win/taseditlib/bookmark.cpp +++ b/src/drivers/win/taseditlib/bookmark.cpp @@ -18,6 +18,7 @@ void BOOKMARK::init() not_empty = false; flash_type = flash_phase = 0; snapshot.jump_frame = -1; + parent_branch = -1; // -1 = root } void BOOKMARK::set() @@ -25,7 +26,7 @@ void BOOKMARK::set() snapshot.init(currMovieData, false); snapshot.jump_frame = currFrameCounter; savestate = greenzone.savestates[currFrameCounter]; - //screenshots + // save screenshot not_empty = true; flash_phase = FLASH_PHASE_MAX; @@ -38,7 +39,7 @@ void BOOKMARK::jump() flash_type = FLASH_TYPE_JUMP; } -void BOOKMARK::unleash() +void BOOKMARK::unleashed() { flash_phase = FLASH_PHASE_MAX; flash_type = FLASH_TYPE_UNLEASH; @@ -49,12 +50,15 @@ void BOOKMARK::save(EMUFILE *os) if (not_empty) { write8le(1, os); + // write parent_branch + write8le((uint8)parent_branch, os); + // write snapshot snapshot.save(os); // write savestate int size = savestate.size(); write32le(size, os); os->fwrite(&savestate[0], size); - //write screenshots (current, saved) + // write saved_screenshot } else write8le((uint8)0, os); } @@ -66,13 +70,17 @@ bool BOOKMARK::load(EMUFILE *is) not_empty = tmp != 0; if (not_empty) { + // read parent_branch + if (!read8le(&tmp, is)) return true; + parent_branch = *(int8*)(&tmp); // don't kill me for that + // read snapshot if (snapshot.load(is)) return true; // read savestate int size; if (!read32le((uint32 *)&size, is)) return true; savestate.resize(size); if ((int)is->fread(&savestate[0], size) < size) return true; - //read screenshots (current, saved) + // read saved_screenshot } // all ok diff --git a/src/drivers/win/taseditlib/bookmark.h b/src/drivers/win/taseditlib/bookmark.h index 1de48bec..6ff1ce8f 100644 --- a/src/drivers/win/taseditlib/bookmark.h +++ b/src/drivers/win/taseditlib/bookmark.h @@ -13,7 +13,7 @@ public: void set(); void jump(); - void unleash(); + void unleashed(); void save(EMUFILE *os); bool load(EMUFILE *is); @@ -23,8 +23,8 @@ public: int flash_type; INPUT_SNAPSHOT snapshot; std::vector savestate; - std::vector current_screenshot; std::vector saved_screenshot; + int parent_branch; private: diff --git a/src/drivers/win/taseditlib/bookmarks.cpp b/src/drivers/win/taseditlib/bookmarks.cpp index 23b1a3ca..907b4683 100644 --- a/src/drivers/win/taseditlib/bookmarks.cpp +++ b/src/drivers/win/taseditlib/bookmarks.cpp @@ -7,8 +7,10 @@ #include "zlib.h" #include "utils/xstring.h" +#pragma comment(lib, "msimg32.lib") + char bookmarks_save_id[BOOKMARKS_ID_LEN] = "BOOKMARKS"; -char bookmarksCaption[2][23] = { " Bookmarks ", " Bookmarks / Branches " }; +char bookmarksCaption[3][23] = { " Bookmarks ", " Bookmarks / Branches ", " Branches " }; // color tables for flashing when saving/loading bookmarks COLORREF bookmark_flash_colors[3][FLASH_PHASE_MAX+1] = { @@ -18,6 +20,8 @@ COLORREF bookmark_flash_colors[3][FLASH_PHASE_MAX+1] = { 0x382309, 0x3c350e, 0x404814, 0x455a19, 0x486c1e, 0x4d7f23, 0x519128, 0x55a32d, 0x5ab532, 0x5ec837, 0x62da3c, 0x66ec41, // unleash 0x320d23, 0x341435, 0x361b48, 0x38215a, 0x39286c, 0x3b2f7f, 0x3c3691, 0x3e3ca3, 0x4043b5, 0x414ac8, 0x4351da, 0x4457ec }; +// corners cursor animation +int corners_cursor_shift[BRANCHES_ANIMATION_FRAMES] = {0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 0 }; extern PLAYBACK playback; extern GREENZONE greenzone; @@ -27,26 +31,16 @@ extern MARKERS markers; extern HWND hwndBookmarks; extern HWND hwndBookmarksList; +extern HWND hwndBranchesBitmap; + extern bool TASEdit_show_lag_frames; extern bool TASEdit_bind_markers; extern bool TASEdit_branch_full_movie; extern bool TASEdit_branch_only_when_rec; +extern bool TASEdit_view_branches_tree; BOOKMARKS::BOOKMARKS() { - -} - -void BOOKMARKS::init() -{ - free(); - bookmarks_array.resize(TOTAL_BOOKMARKS); - for (int i = 0; i < TOTAL_BOOKMARKS; ++i) - { - bookmarks_array[i].init(); - } - ListView_SetItemCountEx(hwndBookmarksList, TOTAL_BOOKMARKS, LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL); - // create font hBookmarksFont = CreateFont(13, 8, /*Height,Width*/ 0, 0, /*escapement,orientation*/ @@ -54,14 +48,120 @@ void BOOKMARKS::init() ANSI_CHARSET, OUT_DEVICE_PRECIS, CLIP_MASK, /*charset, precision, clipping*/ DEFAULT_QUALITY, DEFAULT_PITCH, /*quality, and pitch*/ "Courier"); /*font name*/ - + + // fill TrackMouseEvent struct + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwndBranchesBitmap; +} + +void BOOKMARKS::init() +{ + free(); + // init arrays + BranchX.resize(TOTAL_BOOKMARKS+1); + BranchY.resize(TOTAL_BOOKMARKS+1); + BranchPrevX.resize(TOTAL_BOOKMARKS+1); + BranchPrevY.resize(TOTAL_BOOKMARKS+1); + BranchCurrX.resize(TOTAL_BOOKMARKS+1); + BranchCurrY.resize(TOTAL_BOOKMARKS+1); + for (int i = TOTAL_BOOKMARKS; i >= 0; i--) + { + BranchX[i] = BranchPrevX[i] = BranchCurrX[i] = EMPTY_BRANCHES_X; + BranchY[i] = BranchPrevY[i] = BranchCurrY[i] = EMPTY_BRANCHES_Y_BASE + EMPTY_BRANCHES_Y_FACTOR * ((i + TOTAL_BOOKMARKS - 1) % TOTAL_BOOKMARKS); + } + CursorX = CursorPrevX = CloudX = CloudPrevX = BRANCHES_CLOUD_X; + CursorY = CursorPrevY = BRANCHES_CLOUD_Y; + reset(); + current_branch = -1; // -1 = root + changes_since_current_branch = false; + fireball_size = 0; + + // set cloud_time and current_pos_time + SetCurrentPosTime(); + strcpy(cloud_time, current_pos_time); + + // init bookmarks + bookmarks_array.resize(TOTAL_BOOKMARKS); + for (int i = 0; i < TOTAL_BOOKMARKS; ++i) + bookmarks_array[i].init(); + ListView_SetItemCountEx(hwndBookmarksList, TOTAL_BOOKMARKS, LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL); + + // init GDI stuff + HDC win_hdc = GetWindowDC(hwndBookmarksList); + hBitmapDC = CreateCompatibleDC(win_hdc); + branches_hbitmap = CreateCompatibleBitmap(win_hdc, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_WIDTH); + hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, branches_hbitmap); + hBufferDC = CreateCompatibleDC(win_hdc); + buffer_hbitmap = CreateCompatibleBitmap(win_hdc, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_WIDTH); + hOldBitmap1 = (HBITMAP)SelectObject(hBufferDC, buffer_hbitmap); + normal_brush = CreateSolidBrush(0x000000); + // prepare branches spritesheet + branchesSpritesheet = LoadBitmap(fceu_hInstance, MAKEINTRESOURCE(IDB_BRANCH_SPRITESHEET)); + hSpritesheetDC = CreateCompatibleDC(win_hdc); + hOldBitmap2 = (HBITMAP)SelectObject(hSpritesheetDC, branchesSpritesheet); + // create pens + normal_pen = CreatePen(PS_SOLID, 1, 0x0); + select_pen = CreatePen(PS_SOLID, 2, 0xFF9080); + + RedrawBookmarksCaption(); + update(); +} +void BOOKMARKS::reset() +{ + transition_phase = animation_frame = 0; + mouse_x = mouse_y = -1; + item_under_mouse = ITEM_UNDER_MOUSE_NONE; + mouse_over_bitmap = false; + must_recalculate_branches_tree = must_redraw_branches_tree = true; check_flash_shedule = clock() + BOOKMARKS_FLASH_TICK; - RedrawBookmarksList(); + next_animation_time = clock() + BRANCHES_ANIMATION_TICK; } void BOOKMARKS::free() { bookmarks_array.resize(0); + BranchX.resize(0); + BranchY.resize(0); + BranchPrevX.resize(0); + BranchPrevY.resize(0); + BranchCurrX.resize(0); + BranchCurrY.resize(0); + + // free GDI stuff + if (hOldBitmap && hBitmapDC) + { + SelectObject(hBitmapDC, hOldBitmap); + DeleteDC(hBitmapDC); + hBitmapDC = NULL; + } + if (branches_hbitmap) + { + DeleteObject(branches_hbitmap); + branches_hbitmap = NULL; + } + if (hOldBitmap1 && hBufferDC) + { + SelectObject(hBufferDC, hOldBitmap1); + DeleteDC(hBufferDC); + hBufferDC = NULL; + } + if (buffer_hbitmap) + { + DeleteObject(buffer_hbitmap); + buffer_hbitmap = NULL; + } + if (hOldBitmap2 && hSpritesheetDC) + { + SelectObject(hSpritesheetDC, hOldBitmap2); + DeleteDC(hSpritesheetDC); + hSpritesheetDC = NULL; + } + if (branchesSpritesheet) + { + DeleteObject(branchesSpritesheet); + branchesSpritesheet = NULL; + } } void BOOKMARKS::update() @@ -76,21 +176,98 @@ void BOOKMARKS::update() { bookmarks_array[i].flash_phase--; RedrawBookmarksRow((i + TOTAL_BOOKMARKS - 1) % TOTAL_BOOKMARKS); + must_redraw_branches_tree = true; } } } + + if (must_recalculate_branches_tree) + RecalculateBranchesTree(); + + if (edit_mode == EDIT_MODE_BRANCHES) + { + if (clock() > next_animation_time) + { + // animate + next_animation_time = clock() + BRANCHES_ANIMATION_TICK; + animation_frame = (animation_frame + 1) % BRANCHES_ANIMATION_FRAMES; + // grow or shring fireball + if (changes_since_current_branch) + { + fireball_size++; + if (fireball_size > BRANCHES_FIREBALL_MAX_SIZE) fireball_size = BRANCHES_FIREBALL_MAX_SIZE; + } else + { + fireball_size--; + if (fireball_size < 0) fireball_size = 0; + } + // also update transition from old to new tree + if (transition_phase) + { + transition_phase--; + must_redraw_branches_tree = true; + } else if (!must_redraw_branches_tree) + { + InvalidateRect(hwndBranchesBitmap, 0, FALSE); + } + } + // render + if (must_redraw_branches_tree) + RedrawBranchesTree(); + } } void BOOKMARKS::set(int slot) { if (slot < 0 || slot >= TOTAL_BOOKMARKS) return; int previous_frame = bookmarks_array[slot].snapshot.jump_frame; + // save time of this slot before rewriting it + char saved_time[TIME_DESC_LENGTH]; + if (bookmarks_array[slot].not_empty) + strncpy(saved_time, bookmarks_array[slot].snapshot.description, TIME_DESC_LENGTH-1); + else + saved_time[0] = 0; + bookmarks_array[slot].set(); - if (previous_frame >= 0 && previous_frame != currFrameCounter) - RedrawRow(previous_frame); - RedrawRow(currFrameCounter); - RedrawBookmarksRow((slot + TOTAL_BOOKMARKS - 1) % TOTAL_BOOKMARKS); + // inherit current branch + if (slot != current_branch) + { + int parent = bookmarks_array[slot].parent_branch; + if (parent == -1 && saved_time[0]) + { + // check if this is the only child of cloud parent, if so then set cloud time to the saved_time + int i = 0; + for (; i < TOTAL_BOOKMARKS; ++i) + { + if (bookmarks_array[i].not_empty && bookmarks_array[i].parent_branch == -1 && i != slot) + break; + } + if (i >= TOTAL_BOOKMARKS) + // didn't find another child of cloud + strcpy(cloud_time, saved_time); + } + // before disconnecting from old parent, connect all childs to the parent + for (int i = 0; i < TOTAL_BOOKMARKS; ++i) + { + if (bookmarks_array[i].not_empty && bookmarks_array[i].parent_branch == slot) + bookmarks_array[i].parent_branch = parent; + } + bookmarks_array[slot].parent_branch = current_branch; + } + + // switch current branch to this branch + if (slot != current_branch && current_branch >= 0) + RedrawRowAndBookmark(bookmarks_array[current_branch].snapshot.jump_frame); + if (slot != current_branch || changes_since_current_branch) + must_recalculate_branches_tree = true; + current_branch = slot; + changes_since_current_branch = false; + project.changed = true; + + if (previous_frame >= 0 && previous_frame != currFrameCounter) + RedrawRowAndBookmark(previous_frame); + RedrawRowAndBookmark(currFrameCounter); } void BOOKMARKS::jump(int slot) @@ -143,12 +320,12 @@ void BOOKMARKS::unleash(int slot) UpdateList(); history.RegisterBranch(MODTYPE_BRANCH_0 + slot, first_change, bookmarks_array[slot].snapshot.description); greenzone.Invalidate(first_change); - bookmarks_array[slot].unleash(); + bookmarks_array[slot].unleashed(); } else if (markers_changed) { history.RegisterBranch(MODTYPE_BRANCH_MARKERS_0 + slot, first_change, bookmarks_array[slot].snapshot.description); RedrawList(); - bookmarks_array[slot].unleash(); + bookmarks_array[slot].unleashed(); } else { // didn't restore anything @@ -177,12 +354,12 @@ void BOOKMARKS::unleash(int slot) UpdateList(); history.RegisterBranch(MODTYPE_BRANCH_0 + slot, first_change, bookmarks_array[slot].snapshot.description); greenzone.Invalidate(first_change); - bookmarks_array[slot].unleash(); + bookmarks_array[slot].unleashed(); } else if (markers_changed) { history.RegisterBranch(MODTYPE_BRANCH_MARKERS_0 + slot, first_change, bookmarks_array[slot].snapshot.description); RedrawList(); - bookmarks_array[slot].unleash(); + bookmarks_array[slot].unleashed(); } else { // didn't restore anything @@ -193,23 +370,48 @@ void BOOKMARKS::unleash(int slot) // if greenzone reduced so much that we can't jump immediately - substitute target frame greenzone with our savestate if (greenzone.greenZoneCount <= jump_frame || greenzone.savestates[jump_frame].empty()) { + if ((int)greenzone.savestates.size() <= jump_frame) + greenzone.savestates.resize(jump_frame+1); // clear old savestates: from current end of greenzone to new end of greenzone - for (int i = greenzone.greenZoneCount; i < jump_frame; ++i) - greenzone.ClearSavestate(i); + if (greenzone.greenZoneCount <= jump_frame) + { + for (int i = greenzone.greenZoneCount; i < jump_frame; ++i) + greenzone.ClearSavestate(i); + greenzone.greenZoneCount = jump_frame+1; + } // restore savestate for immediate jump greenzone.savestates[jump_frame] = bookmarks_array[slot].savestate; - // and move greenzone end to this new position - if (greenzone.greenZoneCount <= jump_frame) greenzone.greenZoneCount = jump_frame+1; } + greenzone.update(); // jump to the target (bookmarked frame) playback.jump(jump_frame); + + // switch current branch to this branch + if (slot != current_branch && current_branch >= 0) + { + RedrawRowAndBookmark(bookmarks_array[current_branch].snapshot.jump_frame); + RedrawRowAndBookmark(bookmarks_array[slot].snapshot.jump_frame); + } + current_branch = slot; + changes_since_current_branch = false; + must_recalculate_branches_tree = true; } void BOOKMARKS::save(EMUFILE *os) { // write "BOOKMARKS" string os->fwrite(bookmarks_save_id, BOOKMARKS_ID_LEN); + // write cloud time + os->fwrite(cloud_time, TIME_DESC_LENGTH); + // write current branch and flag of changes since it + write8le((uint8)current_branch, os); + if (changes_since_current_branch) + write8le((uint8)1, os); + else + write8le((uint8)0, os); + // write current_position time + os->fwrite(current_pos_time, TIME_DESC_LENGTH); // write all 10 bookmarks for (int i = 0; i < TOTAL_BOOKMARKS; ++i) { @@ -223,27 +425,53 @@ bool BOOKMARKS::load(EMUFILE *is) char save_id[BOOKMARKS_ID_LEN]; if ((int)is->fread(save_id, BOOKMARKS_ID_LEN) < BOOKMARKS_ID_LEN) return true; if (strcmp(bookmarks_save_id, save_id)) return true; // string is not valid + // read cloud time + if ((int)is->fread(cloud_time, TIME_DESC_LENGTH) < TIME_DESC_LENGTH) return true; + // read current branch and flag of changes since it + uint8 tmp; + if (!read8le(&tmp, is)) return true; + current_branch = tmp; + if (!read8le(&tmp, is)) return true; + changes_since_current_branch = (tmp != 0); + // read current_position time + if ((int)is->fread(current_pos_time, TIME_DESC_LENGTH) < TIME_DESC_LENGTH) return true; // read all 10 bookmarks for (int i = 0; i < TOTAL_BOOKMARKS; ++i) { if (bookmarks_array[i].load(is)) return true; } // all ok - check_flash_shedule = clock() + BOOKMARKS_FLASH_TICK; + reset(); + RedrawBookmarksCaption(); return false; } // ---------------------------------------------------------- void BOOKMARKS::RedrawBookmarksCaption() { - if (TASEdit_branch_only_when_rec) - SetWindowText(hwndBookmarks, bookmarksCaption[(movie_readonly)?0:1]); - else - SetWindowText(hwndBookmarks, bookmarksCaption[1]); - RedrawBookmarksList(); + if (TASEdit_branch_only_when_rec && movie_readonly) + { + edit_mode = EDIT_MODE_BOOKMARKS; + ShowWindow(hwndBranchesBitmap, SW_HIDE); + ShowWindow(hwndBookmarksList, SW_SHOW); + RedrawBookmarksList(); + } else if (TASEdit_view_branches_tree) + { + edit_mode = EDIT_MODE_BRANCHES; + ShowWindow(hwndBookmarksList, SW_HIDE); + ShowWindow(hwndBranchesBitmap, SW_SHOW); + } else + { + edit_mode = EDIT_MODE_BOTH; + ShowWindow(hwndBranchesBitmap, SW_HIDE); + ShowWindow(hwndBookmarksList, SW_SHOW); + RedrawBookmarksList(); + } + SetWindowText(hwndBookmarks, bookmarksCaption[edit_mode]); } void BOOKMARKS::RedrawBookmarksList() { - InvalidateRect(hwndBookmarksList, 0, FALSE); + if (edit_mode != EDIT_MODE_BRANCHES) + InvalidateRect(hwndBookmarksList, 0, FALSE); } void BOOKMARKS::RedrawChangedBookmarks(int frame) { @@ -258,6 +486,215 @@ void BOOKMARKS::RedrawBookmarksRow(int index) ListView_RedrawItems(hwndBookmarksList, index, index); } +void BOOKMARKS::RedrawBranchesTree() +{ + // first calculate current positions of branch items + for (int i = 0; i <= TOTAL_BOOKMARKS; ++i) + { + BranchCurrX[i] = (BranchX[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevX[i] * transition_phase) / BRANCHES_TRANSITION_MAX; + BranchCurrY[i] = (BranchY[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevY[i] * transition_phase) / BRANCHES_TRANSITION_MAX; + } + int cloud_x = (CloudX * (BRANCHES_TRANSITION_MAX - transition_phase) + CloudPrevX * transition_phase) / BRANCHES_TRANSITION_MAX; + // find item under mouse + item_under_mouse = ITEM_UNDER_MOUSE_NONE; + for (int i = 0; i < TOTAL_BOOKMARKS; ++i) + if (item_under_mouse == ITEM_UNDER_MOUSE_NONE && mouse_x >= BranchCurrX[i] - DIGIT_RECT_HALFWIDTH && mouse_x < BranchCurrX[i] - DIGIT_RECT_HALFWIDTH + DIGIT_RECT_WIDTH && mouse_y >= BranchCurrY[i] - DIGIT_RECT_HALFHEIGHT && mouse_y < BranchCurrY[i] - DIGIT_RECT_HALFHEIGHT + DIGIT_RECT_HEIGHT) + item_under_mouse = i; + if (item_under_mouse == ITEM_UNDER_MOUSE_NONE && mouse_x >= cloud_x - BRANCHES_CLOUD_HALFWIDTH && mouse_x < cloud_x - BRANCHES_CLOUD_HALFWIDTH + BRANCHES_CLOUD_WIDTH && mouse_y >= BRANCHES_CLOUD_Y - BRANCHES_CLOUD_HALFHEIGHT && mouse_y < BRANCHES_CLOUD_Y - BRANCHES_CLOUD_HALFHEIGHT + BRANCHES_CLOUD_HEIGHT) + item_under_mouse = ITEM_UNDER_MOUSE_CLOUD; + if (item_under_mouse == ITEM_UNDER_MOUSE_NONE && changes_since_current_branch && mouse_x >= BranchCurrX[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFWIDTH && mouse_x < BranchCurrX[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFWIDTH + DIGIT_RECT_WIDTH && mouse_y >= BranchCurrY[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFHEIGHT && mouse_y < BranchCurrY[TOTAL_BOOKMARKS] - DIGIT_RECT_HALFHEIGHT + DIGIT_RECT_HEIGHT) + item_under_mouse = TOTAL_BOOKMARKS; + + // draw background gradient + TRIVERTEX vertex[2] ; + vertex[0].x = 0; + vertex[0].y = 0; + vertex[0].Red = 0xC700; + vertex[0].Green = 0xE700; + vertex[0].Blue = 0xF300; + vertex[0].Alpha = 0x0000; + vertex[1].x = BRANCHES_BITMAP_WIDTH; + vertex[1].y = BRANCHES_BITMAP_HEIGHT; + vertex[1].Red = 0xEB00; + vertex[1].Green = 0xFA00; + vertex[1].Blue = 0xF800; + vertex[1].Alpha = 0x0000; + GRADIENT_RECT gRect; + gRect.UpperLeft = 0; + gRect.LowerRight = 1; + GradientFill(hBitmapDC, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H); + // lines + int branch_x, branch_y, parent_x, parent_y, child_id; + SelectObject(hBitmapDC, normal_pen); + for (int t = Children.size() - 1; t >= 0; t--) + { + if (t > 0) + { + parent_x = BranchCurrX[t-1]; + parent_y = BranchCurrY[t-1]; + } else + { + parent_x = cloud_x; + parent_y = BRANCHES_CLOUD_Y; + } + for (int i = Children[t].size() - 1; i >= 0; i--) + { + child_id = Children[t][i]; + if (child_id < TOTAL_BOOKMARKS) + { + MoveToEx(hBitmapDC, parent_x, parent_y, 0); + LineTo(hBitmapDC, BranchCurrX[child_id], BranchCurrY[child_id]); + } + } + } + // lines for item under mouse + SelectObject(hBitmapDC, select_pen); + int branch = item_under_mouse; + if (item_under_mouse == TOTAL_BOOKMARKS) + branch = current_branch; + while (branch >= 0) + { + branch_x = BranchCurrX[branch]; + branch_y = BranchCurrY[branch]; + MoveToEx(hBitmapDC, branch_x, branch_y, 0); + branch = bookmarks_array[branch].parent_branch; + if (branch >= 0) + { + branch_x = BranchCurrX[branch]; + branch_y = BranchCurrY[branch]; + } else + { + branch_x = cloud_x; + branch_y = BRANCHES_CLOUD_Y; + } + LineTo(hBitmapDC, branch_x, branch_y); + } + if (changes_since_current_branch) + { + if (item_under_mouse != TOTAL_BOOKMARKS) + SelectObject(hBitmapDC, normal_pen); + if (current_branch >= 0) + { + parent_x = BranchCurrX[current_branch]; + parent_y = BranchCurrY[current_branch]; + } else + { + parent_x = cloud_x; + parent_y = BRANCHES_CLOUD_Y; + } + MoveToEx(hBitmapDC, parent_x, parent_y, 0); + branch_x = BranchCurrX[TOTAL_BOOKMARKS]; + branch_y = BranchCurrY[TOTAL_BOOKMARKS]; + LineTo(hBitmapDC, branch_x, branch_y); + } + + // cloud + TransparentBlt(hBitmapDC, cloud_x - BRANCHES_CLOUD_HALFWIDTH, BRANCHES_CLOUD_Y - BRANCHES_CLOUD_HALFHEIGHT, BRANCHES_CLOUD_WIDTH, BRANCHES_CLOUD_HEIGHT, hSpritesheetDC, BRANCHES_CLOUD_SPRITESHEET_X, BRANCHES_CLOUD_SPRITESHEET_Y, BRANCHES_CLOUD_WIDTH, BRANCHES_CLOUD_HEIGHT, 0x00FF00); + + // branches rectangles + for (int i = 0; i < TOTAL_BOOKMARKS; ++i) + { + temp_rect.left = BranchCurrX[i] - DIGIT_RECT_HALFWIDTH; + temp_rect.top = BranchCurrY[i] - DIGIT_RECT_HALFHEIGHT; + temp_rect.right = temp_rect.left + DIGIT_RECT_WIDTH; + temp_rect.bottom = temp_rect.top + DIGIT_RECT_HEIGHT; + if (bookmarks_array[i].flash_phase) + { + // draw colored rect + HBRUSH color_brush = CreateSolidBrush(bookmark_flash_colors[bookmarks_array[i].flash_type][bookmarks_array[i].flash_phase]); + FillRect(hBitmapDC, &temp_rect, color_brush); + DeleteObject(color_brush); + } else + { + // draw black rect + FillRect(hBitmapDC, &temp_rect, normal_brush); + } + } + // digits + for (int i = 0; i < TOTAL_BOOKMARKS; ++i) + { + branch_x = BranchCurrX[i] - DIGIT_BITMAP_HALFWIDTH; + branch_y = BranchCurrY[i] - DIGIT_BITMAP_HALFHEIGHT; + if(i == current_branch) + { + if (i == item_under_mouse) + BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH + BLUE_DIGITS_SPRITESHEET_DX, MOUSEOVER_DIGITS_SPRITESHEET_DY, SRCCOPY); + else + BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH + BLUE_DIGITS_SPRITESHEET_DX, 0, SRCCOPY); + } else + { + if (i == item_under_mouse) + BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH, MOUSEOVER_DIGITS_SPRITESHEET_DY, SRCCOPY); + else + BitBlt(hBitmapDC, branch_x, branch_y, DIGIT_BITMAP_WIDTH, DIGIT_BITMAP_HEIGHT, hSpritesheetDC, i * DIGIT_BITMAP_WIDTH, 0, SRCCOPY); + } + } + // time of item under cursor + if (item_under_mouse > ITEM_UNDER_MOUSE_NONE) + { + if (item_under_mouse == ITEM_UNDER_MOUSE_CLOUD) + TextOut(hBitmapDC, 0, 0, (LPCSTR)cloud_time, 8); + else if (item_under_mouse < TOTAL_BOOKMARKS) + TextOut(hBitmapDC, 0, 0, (LPCSTR)bookmarks_array[item_under_mouse].snapshot.description, 8); + else + TextOut(hBitmapDC, 0, 0, (LPCSTR)current_pos_time, 8); + } + // finished + must_redraw_branches_tree = false; + InvalidateRect(hwndBranchesBitmap, 0, FALSE); +} +// this is called by wndproc on WM_PAINT +void BOOKMARKS::PaintBranchesBitmap(HDC hdc) +{ + int branch_x, branch_y; + // "bg" + BitBlt(hBufferDC, 0, 0, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_HEIGHT, hBitmapDC, 0, 0, SRCCOPY); + // "sprites" + // fireball + if (fireball_size) + { + branch_x = BranchCurrX[TOTAL_BOOKMARKS] - BRANCHES_FIREBALL_HALFWIDTH; + branch_y = BranchCurrY[TOTAL_BOOKMARKS] - BRANCHES_FIREBALL_HALFHEIGHT; + if (fireball_size >= BRANCHES_FIREBALL_MAX_SIZE) + { + TransparentBlt(hBufferDC, branch_x, branch_y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, hSpritesheetDC, animation_frame * BRANCHES_FIREBALL_WIDTH + BRANCHES_FIREBALL_SPRITESHEET_X, BRANCHES_FIREBALL_SPRITESHEET_Y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, 0x00FF00); + } else + { + TransparentBlt(hBufferDC, branch_x, branch_y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, hSpritesheetDC, BRANCHES_FIREBALL_SPRITESHEET_END_X - fireball_size * BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_SPRITESHEET_Y, BRANCHES_FIREBALL_WIDTH, BRANCHES_FIREBALL_HEIGHT, 0x00FF00); + } + } + // corners cursor + branch_x = (CursorX * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevX * transition_phase) / BRANCHES_TRANSITION_MAX; + branch_y = (CursorY * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevY * transition_phase) / BRANCHES_TRANSITION_MAX; + int current_corners_cursor_shift = BRANCHES_CORNER_BASE_SHIFT + corners_cursor_shift[animation_frame]; + int corner_x, corner_y; + // upper left + corner_x = branch_x - current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH; + corner_y = branch_y - current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT; + TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER1_SPRITESHEET_X, BRANCHES_CORNER1_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00); + // upper right + corner_x = branch_x + current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH; + corner_y = branch_y - current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT; + TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER2_SPRITESHEET_X, BRANCHES_CORNER2_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00); + // lower left + corner_x = branch_x - current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH; + corner_y = branch_y + current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT; + TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER3_SPRITESHEET_X, BRANCHES_CORNER3_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00); + // lower right + corner_x = branch_x + current_corners_cursor_shift - BRANCHES_CORNER_HALFWIDTH; + corner_y = branch_y + current_corners_cursor_shift - BRANCHES_CORNER_HALFHEIGHT; + TransparentBlt(hBufferDC, corner_x, corner_y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, hSpritesheetDC, BRANCHES_CORNER4_SPRITESHEET_X, BRANCHES_CORNER4_SPRITESHEET_Y, BRANCHES_CORNER_WIDTH, BRANCHES_CORNER_HEIGHT, 0x00FF00); + // finish - paste buffer bitmap to screen + BitBlt(hdc, 0, 0, BRANCHES_BITMAP_WIDTH, BRANCHES_BITMAP_HEIGHT, hBufferDC, 0, 0, SRCCOPY); +} + +void BOOKMARKS::MouseMove(int new_x, int new_y) +{ + mouse_x = new_x; + mouse_y = new_y; + must_redraw_branches_tree = true; +} +// ---------------------------------------------------------------------------------------- void BOOKMARKS::GetDispInfo(NMLVDISPINFO* nmlvDispInfo) { LVITEM& item = nmlvDispInfo->item; @@ -267,7 +704,10 @@ void BOOKMARKS::GetDispInfo(NMLVDISPINFO* nmlvDispInfo) { case BOOKMARKS_COLUMN_ICON: { - item.iImage = (item.iItem + 1) % TOTAL_BOOKMARKS; + if ((item.iItem + 1) % TOTAL_BOOKMARKS == current_branch) + item.iImage = ((item.iItem + 1) % TOTAL_BOOKMARKS) + TOTAL_BOOKMARKS; + else + item.iImage = (item.iItem + 1) % TOTAL_BOOKMARKS; break; } case BOOKMARKS_COLUMN_FRAME: @@ -396,11 +836,280 @@ void BOOKMARKS::RightClick(LPNMITEMACTIVATE info) int BOOKMARKS::FindBookmarkAtFrame(int frame) { + if (current_branch >= 0 && bookmarks_array[current_branch].snapshot.jump_frame == frame) return current_branch + TOTAL_BOOKMARKS; // blue digit + for (int i = 0; i < TOTAL_BOOKMARKS; ++i) { - if (bookmarks_array[i].snapshot.jump_frame == frame) return i; + if (bookmarks_array[i].snapshot.jump_frame == frame) return i; // green digit } return -1; } +void BOOKMARKS::ChangesMadeSinceBranch() +{ + bool prev_changes_since_current_branch = changes_since_current_branch; + changes_since_current_branch = true; + SetCurrentPosTime(); + // recalculate branch tree if previous_changes = false + if (!prev_changes_since_current_branch) + must_recalculate_branches_tree = true; + else if (edit_mode == EDIT_MODE_BRANCHES && item_under_mouse == TOTAL_BOOKMARKS) + // redraw displayed time if it's currently shown + must_redraw_branches_tree = true; +} + +void BOOKMARKS::SetCurrentPosTime() +{ + time_t raw_time; + time(&raw_time); + struct tm * timeinfo = localtime(&raw_time); + strftime(current_pos_time, TIME_DESC_LENGTH, "%H:%M:%S", timeinfo); +} + +void BOOKMARKS::RecalculateBranchesTree() +{ + // save previous values + for (int i = TOTAL_BOOKMARKS; i >= 0; i--) + { + BranchPrevX[i] = (BranchX[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevX[i] * transition_phase) / BRANCHES_TRANSITION_MAX; + BranchPrevY[i] = (BranchY[i] * (BRANCHES_TRANSITION_MAX - transition_phase) + BranchPrevY[i] * transition_phase) / BRANCHES_TRANSITION_MAX; + } + CloudPrevX = (CloudX * (BRANCHES_TRANSITION_MAX - transition_phase) + CloudPrevX * transition_phase) / BRANCHES_TRANSITION_MAX; + CursorPrevX = (CursorX * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevX * transition_phase) / BRANCHES_TRANSITION_MAX; + CursorPrevY = (CursorY * (BRANCHES_TRANSITION_MAX - transition_phase) + CursorPrevY * transition_phase) / BRANCHES_TRANSITION_MAX; + transition_phase = BRANCHES_TRANSITION_MAX; + + // 0. Prepare arrays + GridX.resize(0); + GridY.resize(0); + Children.resize(0); + GridHeight.resize(0); + GridX.resize(TOTAL_BOOKMARKS+1); + GridY.resize(TOTAL_BOOKMARKS+1); + Children.resize(TOTAL_BOOKMARKS+2); // 0th subvector is for cloud's children + GridHeight.resize(TOTAL_BOOKMARKS+1); + for (int i = TOTAL_BOOKMARKS; i >= 0; i--) + GridHeight[i] = 1; + + // 1. Define GridX of branches (distribute to levels) and GridHeight of branches + int current_grid_x = 0; + std::vector> BranchesLevels; + + std::vector UndistributedBranches; + UndistributedBranches.resize(TOTAL_BOOKMARKS); + for (int i = UndistributedBranches.size()-1; i >= 0; i--) + UndistributedBranches[i] = i; + // remove all empty branches + for (int i = UndistributedBranches.size()-1; i >= 0; i--) + { + if (!bookmarks_array[UndistributedBranches[i]].not_empty) + UndistributedBranches.erase(UndistributedBranches.begin() + i); + } + // highest level: cloud (id = -1) + BranchesLevels.resize(current_grid_x+1); + BranchesLevels[current_grid_x].resize(1); + BranchesLevels[current_grid_x][0] = -1; + // go lower until all branches are arranged to levels + int current_parent; + while(UndistributedBranches.size()) + { + current_grid_x++; + BranchesLevels.resize(current_grid_x+1); + BranchesLevels[current_grid_x].resize(0); + for (int t = BranchesLevels[current_grid_x-1].size()-1; t >= 0; t--) + { + current_parent = BranchesLevels[current_grid_x-1][t]; + for (int i = UndistributedBranches.size()-1; i >= 0; i--) + { + if (bookmarks_array[UndistributedBranches[i]].parent_branch == current_parent) + { + // assign this branch to current level + GridX[UndistributedBranches[i]] = current_grid_x; + BranchesLevels[current_grid_x].push_back(UndistributedBranches[i]); + // also add it to parent's Children array + Children[current_parent+1].push_back(UndistributedBranches[i]); + UndistributedBranches.erase(UndistributedBranches.begin() + i); + } + } + if (current_parent >= 0) + { + GridHeight[current_parent] = Children[current_parent+1].size(); + if (Children[current_parent+1].size() > 1) + RecursiveAddHeight(bookmarks_array[current_parent].parent_branch, GridHeight[current_parent] - 1); + else + GridHeight[current_parent] = 1; // its own height + } + } + } + if (changes_since_current_branch) + { + // also define "current_pos" GridX + if (current_branch >= 0) + { + if (Children[current_branch+1].size() < MAX_NUM_CHILDREN) + { + // "current_pos" becomes a child of current_branch + GridX[TOTAL_BOOKMARKS] = GridX[current_branch] + 1; + if ((int)BranchesLevels.size() <= GridX[TOTAL_BOOKMARKS]) + BranchesLevels.resize(GridX[TOTAL_BOOKMARKS] + 1); + BranchesLevels[GridX[TOTAL_BOOKMARKS]].push_back(TOTAL_BOOKMARKS); // ID of "current_pos" = number of bookmarks + Children[current_branch+1].push_back(TOTAL_BOOKMARKS); + if (Children[current_branch+1].size() > 1) + RecursiveAddHeight(current_branch, 1); + } else + { + // special case 0: if there's too many items on one level (more than canvas can show) + // "current_pos" becomes special branch above current_branch + GridX[TOTAL_BOOKMARKS] = GridX[current_branch]; + GridY[TOTAL_BOOKMARKS] = GridY[current_branch] - 7; + } + } else + { + // special case 1: one and (presumably) only child of "cloud" + GridX[TOTAL_BOOKMARKS] = 1; + GridY[TOTAL_BOOKMARKS] = 0; + if ((int)BranchesLevels.size() <= GridX[TOTAL_BOOKMARKS]) + BranchesLevels.resize(GridX[TOTAL_BOOKMARKS] + 1); + BranchesLevels[GridX[TOTAL_BOOKMARKS]].push_back(TOTAL_BOOKMARKS); + } + } + // define grid_width + int grid_width, cloud_prefix = 0; + if (BranchesLevels.size()-1 > 0) + { + grid_width = BRANCHES_CANVAS_WIDTH / (BranchesLevels.size()-1); + if (grid_width < BRANCHES_GRID_MIN_WIDTH) + grid_width = BRANCHES_GRID_MIN_WIDTH; + else if (grid_width > BRANCHES_GRID_MAX_WIDTH) + grid_width = BRANCHES_GRID_MAX_WIDTH; + } else grid_width = BRANCHES_GRID_MAX_WIDTH; + if (grid_width < MIN_CLOUD_LINE_LENGTH) + cloud_prefix = MIN_CLOUD_LINE_LENGTH - grid_width; + + // 2. Define GridY of branches + RecursiveSetYPos(-1, 0); + // define grid_halfheight + int grid_halfheight; + int totalHeight = 0; + for (int i = Children[0].size()-1; i >= 0; i--) + totalHeight += GridHeight[Children[0][i]]; + if (totalHeight) + { + grid_halfheight = BRANCHES_CANVAS_HEIGHT / (2 * totalHeight); + if (grid_halfheight < BRANCHES_GRID_MIN_HALFHEIGHT) + grid_halfheight = BRANCHES_GRID_MIN_HALFHEIGHT; + else if (grid_halfheight > BRANCHES_GRID_MAX_HALFHEIGHT) + grid_halfheight = BRANCHES_GRID_MAX_HALFHEIGHT; + } else grid_halfheight = BRANCHES_GRID_MAX_HALFHEIGHT; + // special case 2: if chain of branches is too long, last item (normally it's fireball) goes up + if (changes_since_current_branch) + { + if (GridX[TOTAL_BOOKMARKS] > MAX_CHAIN_LEN) + { + GridX[TOTAL_BOOKMARKS] = MAX_CHAIN_LEN; + GridY[TOTAL_BOOKMARKS] -= 2; + } + } + // special case 3: if some branch crosses upper or lower border + int parent; + for (int t = TOTAL_BOOKMARKS; t >= 0; t--) + { + if (GridY[t] > MAX_GRID_Y_POS) + { + if (t < TOTAL_BOOKMARKS) + parent = bookmarks_array[t].parent_branch; + else + parent = current_branch; + int pos = MAX_GRID_Y_POS; + for (int i = 0; i < (int)Children[parent+1].size(); ++i) + { + GridY[Children[parent+1][i]] = pos; + pos -= 2; + } + } else if (GridY[t] < -MAX_GRID_Y_POS) + { + if (t < TOTAL_BOOKMARKS) + parent = bookmarks_array[t].parent_branch; + else + parent = current_branch; + int pos = -MAX_GRID_Y_POS; + for (int i = Children[parent+1].size()-1; i >= 0; i--) + { + GridY[Children[parent+1][i]] = pos; + pos += 2; + } + } + } + + // 3. Set pixel positions of branches + int max_x = 0; + for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--) + { + if (bookmarks_array[i].not_empty) + { + BranchX[i] = cloud_prefix + GridX[i] * grid_width; + BranchY[i] = BRANCHES_CLOUD_Y + GridY[i] * grid_halfheight; + } else + { + BranchX[i] = EMPTY_BRANCHES_X; + BranchY[i] = EMPTY_BRANCHES_Y_BASE + EMPTY_BRANCHES_Y_FACTOR * ((i + TOTAL_BOOKMARKS - 1) % TOTAL_BOOKMARKS); + } + if (max_x < BranchX[i]) max_x = BranchX[i]; + } + if (changes_since_current_branch) + { + // also set pixel position of "current_pos" + BranchX[TOTAL_BOOKMARKS] = cloud_prefix + GridX[TOTAL_BOOKMARKS] * grid_width; + BranchY[TOTAL_BOOKMARKS] = BRANCHES_CLOUD_Y + GridY[TOTAL_BOOKMARKS] * grid_halfheight; + } else if (current_branch >= 0) + { + BranchX[TOTAL_BOOKMARKS] = cloud_prefix + GridX[current_branch] * grid_width; + BranchY[TOTAL_BOOKMARKS] = BRANCHES_CLOUD_Y + GridY[current_branch] * grid_halfheight; + } else + { + BranchX[TOTAL_BOOKMARKS] = 0; + BranchY[TOTAL_BOOKMARKS] = BRANCHES_CLOUD_Y; + } + if (max_x < BranchX[TOTAL_BOOKMARKS]) max_x = BranchX[TOTAL_BOOKMARKS]; + // align whole tree horizontally + CloudX = (BRANCHES_BITMAP_WIDTH + 1 - max_x) / 2; + if (CloudX < 0) CloudX = 0; + for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--) + if (bookmarks_array[i].not_empty) + BranchX[i] += CloudX; + BranchX[TOTAL_BOOKMARKS] += CloudX; + // target cursor + CursorX = BranchX[TOTAL_BOOKMARKS]; + CursorY = BranchY[TOTAL_BOOKMARKS]; + // finished recalculating + must_recalculate_branches_tree = false; + must_redraw_branches_tree = true; +} +void BOOKMARKS::RecursiveAddHeight(int branch_num, int amount) +{ + if (branch_num >= 0) + { + GridHeight[branch_num] += amount; + if (bookmarks_array[branch_num].parent_branch >= 0) + RecursiveAddHeight(bookmarks_array[branch_num].parent_branch, amount); + } +} +void BOOKMARKS::RecursiveSetYPos(int parent, int parentY) +{ + if (Children[parent+1].size()) + { + // find total height of children + int totalHeight = 0; + for (int i = Children[parent+1].size()-1; i >= 0; i--) + totalHeight += GridHeight[Children[parent+1][i]]; + // set Y of children and subchildren + for (int i = Children[parent+1].size()-1; i >= 0; i--) + { + int child_id = Children[parent+1][i]; + GridY[child_id] = parentY + GridHeight[child_id] - totalHeight; + RecursiveSetYPos(child_id, GridY[child_id]); + parentY += 2 * GridHeight[child_id]; + } + } +} diff --git a/src/drivers/win/taseditlib/bookmarks.h b/src/drivers/win/taseditlib/bookmarks.h index 5d5bf3c7..7a1d1ec9 100644 --- a/src/drivers/win/taseditlib/bookmarks.h +++ b/src/drivers/win/taseditlib/bookmarks.h @@ -4,20 +4,89 @@ #define TOTAL_BOOKMARKS 10 -#define BOOKMARKS_FLASH_TICK 50 // in milliseconds +#define EDIT_MODE_BOOKMARKS 0 +#define EDIT_MODE_BOTH 1 +#define EDIT_MODE_BRANCHES 2 +#define ITEM_UNDER_MOUSE_NONE -2 +#define ITEM_UNDER_MOUSE_CLOUD -1 + +#define BOOKMARKS_FLASH_TICK 100 // in milliseconds +#define BRANCHES_ANIMATION_TICK 50 // animate at 20FPS +#define BRANCHES_TRANSITION_MAX 8 + +// branches bitmap +#define BRANCHES_BITMAP_WIDTH 170 +#define BRANCHES_BITMAP_HEIGHT 145 +#define BRANCHES_ANIMATION_FRAMES 12 +// constants for drawing branches tree +#define BRANCHES_CANVAS_WIDTH 146 +#define BRANCHES_CANVAS_HEIGHT 130 +#define BRANCHES_CLOUD_X 14 +#define BRANCHES_CLOUD_Y 72 +#define BRANCHES_GRID_MIN_WIDTH 14 +#define BRANCHES_GRID_MAX_WIDTH 30 +#define MIN_CLOUD_LINE_LENGTH 19 +#define BRANCHES_GRID_MIN_HALFHEIGHT 8 +#define BRANCHES_GRID_MAX_HALFHEIGHT 12 +#define EMPTY_BRANCHES_X -6 +#define EMPTY_BRANCHES_Y_BASE 8 +#define EMPTY_BRANCHES_Y_FACTOR 14 +#define MAX_NUM_CHILDREN 9 +#define MAX_CHAIN_LEN 10 +#define MAX_GRID_Y_POS 8 +// spritesheet +#define DIGIT_BITMAP_WIDTH 9 +#define DIGIT_BITMAP_HALFWIDTH DIGIT_BITMAP_WIDTH/2 +#define DIGIT_BITMAP_HEIGHT 13 +#define DIGIT_BITMAP_HALFHEIGHT DIGIT_BITMAP_HEIGHT/2 +#define BLUE_DIGITS_SPRITESHEET_DX DIGIT_BITMAP_WIDTH*TOTAL_BOOKMARKS +#define MOUSEOVER_DIGITS_SPRITESHEET_DY DIGIT_BITMAP_HEIGHT +#define DIGIT_RECT_WIDTH 11 +#define DIGIT_RECT_HALFWIDTH DIGIT_RECT_WIDTH/2 +#define DIGIT_RECT_HEIGHT 15 +#define DIGIT_RECT_HALFHEIGHT DIGIT_RECT_HEIGHT/2 +#define BRANCHES_CLOUD_WIDTH 26 +#define BRANCHES_CLOUD_HALFWIDTH BRANCHES_CLOUD_WIDTH/2 +#define BRANCHES_CLOUD_HEIGHT 15 +#define BRANCHES_CLOUD_HALFHEIGHT BRANCHES_CLOUD_HEIGHT/2 +#define BRANCHES_CLOUD_SPRITESHEET_X 180 +#define BRANCHES_CLOUD_SPRITESHEET_Y 0 +#define BRANCHES_FIREBALL_WIDTH 10 +#define BRANCHES_FIREBALL_HALFWIDTH BRANCHES_FIREBALL_WIDTH/2 +#define BRANCHES_FIREBALL_HEIGHT 10 +#define BRANCHES_FIREBALL_HALFHEIGHT BRANCHES_FIREBALL_HEIGHT/2 +#define BRANCHES_FIREBALL_SPRITESHEET_X 0 +#define BRANCHES_FIREBALL_SPRITESHEET_Y 26 +#define BRANCHES_FIREBALL_MAX_SIZE 5 +#define BRANCHES_FIREBALL_SPRITESHEET_END_X 160 +#define BRANCHES_CORNER_WIDTH 7 +#define BRANCHES_CORNER_HALFWIDTH BRANCHES_CORNER_WIDTH/2 +#define BRANCHES_CORNER_HEIGHT 7 +#define BRANCHES_CORNER_HALFHEIGHT BRANCHES_CORNER_HEIGHT/2 +#define BRANCHES_CORNER1_SPRITESHEET_X 206 +#define BRANCHES_CORNER1_SPRITESHEET_Y 0 +#define BRANCHES_CORNER2_SPRITESHEET_X 213 +#define BRANCHES_CORNER2_SPRITESHEET_Y 0 +#define BRANCHES_CORNER3_SPRITESHEET_X 206 +#define BRANCHES_CORNER3_SPRITESHEET_Y 7 +#define BRANCHES_CORNER4_SPRITESHEET_X 213 +#define BRANCHES_CORNER4_SPRITESHEET_Y 7 +#define BRANCHES_CORNER_BASE_SHIFT 6 // listview columns #define BOOKMARKS_COLUMN_ICON 0 #define BOOKMARKS_COLUMN_FRAME 1 #define BOOKMARKS_COLUMN_TIME 2 #define BOOKMARKS_ID_LEN 10 +#define TIME_DESC_LENGTH 9 // "HH:MM:SS" class BOOKMARKS { public: BOOKMARKS(); void init(); + void reset(); void free(); void update(); @@ -40,10 +109,66 @@ public: void RedrawChangedBookmarks(int frame); void RedrawBookmarksRow(int index); + void RedrawBranchesTree(); + void PaintBranchesBitmap(HDC hdc); + + void MouseMove(int new_x, int new_y); + + void ChangesMadeSinceBranch(); + + void RecalculateBranchesTree(); + void RecursiveAddHeight(int branch_num, int amount); + void RecursiveSetYPos(int parent, int parentY); + std::vector bookmarks_array; + // not saved vars + bool mouse_over_bitmap; + TRACKMOUSEEVENT tme; + private: - HFONT hBookmarksFont; + void SetCurrentPosTime(); + + // also saved vars + int current_branch; + bool changes_since_current_branch; + char cloud_time[TIME_DESC_LENGTH]; + char current_pos_time[TIME_DESC_LENGTH]; + + // not saved vars int check_flash_shedule; + int edit_mode; + int animation_frame; // 0-13 + int next_animation_time; + bool must_redraw_branches_tree; + bool must_recalculate_branches_tree; + std::vector BranchX; // in pixels + std::vector BranchY; + std::vector BranchPrevX; + std::vector BranchPrevY; + std::vector BranchCurrX; + std::vector BranchCurrY; + int CloudX, CloudPrevX; + int CursorX, CursorPrevX, CursorY, CursorPrevY; + int transition_phase; + int fireball_size; + int mouse_x, mouse_y; + int item_under_mouse; + + // GDI stuff + HFONT hBookmarksFont; + HBRUSH normal_brush; + RECT temp_rect; + HPEN normal_pen, select_pen; + HBITMAP branches_hbitmap, hOldBitmap, buffer_hbitmap, hOldBitmap1, branchesSpritesheet, hOldBitmap2; + HDC hBitmapDC, hBufferDC, hSpritesheetDC; + + + // temps + std::vector GridX; // in grid units + std::vector GridY; + std::vector GridHeight; + std::vector> Children; + }; diff --git a/src/drivers/win/taseditlib/greenzone.cpp b/src/drivers/win/taseditlib/greenzone.cpp index 7f7ec6d2..9f23517e 100644 --- a/src/drivers/win/taseditlib/greenzone.cpp +++ b/src/drivers/win/taseditlib/greenzone.cpp @@ -35,9 +35,13 @@ void GREENZONE::reset() } void GREENZONE::update() { + if ((int)savestates.size() < greenZoneCount) + savestates.resize(greenZoneCount); + if ((int)lag_history.size() < greenZoneCount) + lag_history.resize(greenZoneCount); + if (clock() > next_cleaning_time) GreenzoneCleaning(); - } void GREENZONE::TryDumpIncremental(bool lagFlag) @@ -151,7 +155,7 @@ void GREENZONE::GreenzoneCleaning() } } finish: - if (changed) RedrawList(); + if (changed) RedrawListAndBookmarks(); // shedule next cleaning next_cleaning_time = clock() + TIME_BETWEEN_CLEANINGS; } @@ -334,7 +338,7 @@ void GREENZONE::InvalidateAndCheck(int after) } } // redraw list even if greenzone didn't change - RedrawList(); + RedrawListAndBookmarks(); } // This version doesn't restore playback, may be used only by Branching functions! void GREENZONE::Invalidate(int after) @@ -349,7 +353,7 @@ void GREENZONE::Invalidate(int after) } } // redraw list even if greenzone didn't change - RedrawList(); + RedrawListAndBookmarks(); } int GREENZONE::FindBeginningOfGreenZone(int starting_index) diff --git a/src/drivers/win/taseditlib/inputhistory.cpp b/src/drivers/win/taseditlib/inputhistory.cpp index 9f28e3d5..a5a7d6cb 100644 --- a/src/drivers/win/taseditlib/inputhistory.cpp +++ b/src/drivers/win/taseditlib/inputhistory.cpp @@ -10,10 +10,11 @@ extern void FCEU_printf(char *format, ...); extern HWND hwndHistoryList; extern bool TASEdit_bind_markers; +extern MARKERS markers; +extern BOOKMARKS bookmarks; extern PLAYBACK playback; extern GREENZONE greenzone; extern TASEDIT_PROJECT project; -extern MARKERS markers; char history_save_id[HISTORY_ID_LEN] = "HISTORY"; char modCaptions[36][20] = {" Init", @@ -89,7 +90,8 @@ void INPUT_HISTORY::free() void INPUT_HISTORY::update() { // update undo_hint - if (old_undo_hint_pos != undo_hint_pos && old_undo_hint_pos >= 0) RedrawRow(old_undo_hint_pos); + if (old_undo_hint_pos != undo_hint_pos && old_undo_hint_pos >= 0) + RedrawRow(old_undo_hint_pos); // not changing bookmarks list old_undo_hint_pos = undo_hint_pos; old_show_undo_hint = show_undo_hint; show_undo_hint = false; @@ -100,7 +102,8 @@ void INPUT_HISTORY::update() else undo_hint_pos = -1; // finished hinting } - if (old_show_undo_hint != show_undo_hint) RedrawRow(undo_hint_pos); + if (old_show_undo_hint != show_undo_hint) + RedrawRow(undo_hint_pos); // not changing bookmarks list @@ -145,9 +148,11 @@ int INPUT_HISTORY::jump(int new_pos) { currMovieData.records.resize(input_snapshots[real_pos].size); input_snapshots[real_pos].toMovie(currMovieData, first_change); + bookmarks.ChangesMadeSinceBranch(); } else if (markers_changed) { markers.update(); + bookmarks.ChangesMadeSinceBranch(); RedrawList(); } @@ -231,6 +236,7 @@ int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end) strcat(inp.description, framenum); } AddInputSnapshotToHistory(inp); + bookmarks.ChangesMadeSinceBranch(); return -1; } else { @@ -294,6 +300,7 @@ int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end) strcat(inp.description, framenum); } AddInputSnapshotToHistory(inp); + bookmarks.ChangesMadeSinceBranch(); } return first_changes; } diff --git a/src/drivers/win/taseditlib/markers.cpp b/src/drivers/win/taseditlib/markers.cpp index 6851b7ae..947256fd 100644 --- a/src/drivers/win/taseditlib/markers.cpp +++ b/src/drivers/win/taseditlib/markers.cpp @@ -47,14 +47,14 @@ void MARKERS::save(EMUFILE *os) // returns true if couldn't load bool MARKERS::load(EMUFILE *is) { - markers_array.resize(currMovieData.getNumRecords()); // 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_save_id, save_id)) goto error; // string is not valid int size; - if (read32le((uint32 *)&size, is) && size == currMovieData.getNumRecords()) + if (read32le((uint32 *)&size, is) && size >= currMovieData.getNumRecords()) { + markers_array.resize(size); // read and uncompress array int comprlen; uLongf destlen = size; @@ -89,3 +89,10 @@ void MARKERS::insertEmpty(int at, int frames) } } +void MARKERS::truncateAt(int frame) +{ + markers_array.resize(frame); +} + + + diff --git a/src/drivers/win/taseditlib/markers.h b/src/drivers/win/taseditlib/markers.h index 63a0472f..7d1e088d 100644 --- a/src/drivers/win/taseditlib/markers.h +++ b/src/drivers/win/taseditlib/markers.h @@ -17,6 +17,7 @@ public: void ToggleMarker(int frame); void insertEmpty(int at, int frames); + void truncateAt(int frame); std::vector markers_array; diff --git a/src/drivers/win/taseditlib/playback.cpp b/src/drivers/win/taseditlib/playback.cpp index 6d0f6859..b56236d7 100644 --- a/src/drivers/win/taseditlib/playback.cpp +++ b/src/drivers/win/taseditlib/playback.cpp @@ -46,7 +46,7 @@ void PLAYBACK::update() SeekingStop(); // update flashing pauseframe - if (old_pauseframe != pauseframe && old_pauseframe) RedrawRow(old_pauseframe-1); + if (old_pauseframe != pauseframe && old_pauseframe) RedrawRowAndBookmark(old_pauseframe-1); old_pauseframe = pauseframe; old_show_pauseframe = show_pauseframe; if (pauseframe) @@ -56,7 +56,7 @@ void PLAYBACK::update() else show_pauseframe = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD_SEEKING) & 1; } else show_pauseframe = false; - if (old_show_pauseframe != show_pauseframe) RedrawRow(pauseframe-1); + if (old_show_pauseframe != show_pauseframe) RedrawRowAndBookmark(pauseframe-1); // update seeking progressbar old_emu_paused = emu_paused; @@ -81,8 +81,8 @@ void PLAYBACK::update() { FollowPlayback(); //update the old and new rows - RedrawRow(lastCursor); - RedrawRow(currFrameCounter); + RedrawRowAndBookmark(lastCursor); + RedrawRowAndBookmark(currFrameCounter); UpdateWindow(hwndList); lastCursor = currFrameCounter; } diff --git a/vc/vc10_fceux.vcxproj b/vc/vc10_fceux.vcxproj index a7ecae63..ce049208 100644 --- a/vc/vc10_fceux.vcxproj +++ b/vc/vc10_fceux.vcxproj @@ -843,10 +843,22 @@ + + + + + + + + + + + + @@ -872,8 +884,20 @@ + + + + + + + + + + + + diff --git a/vc/vc10_fceux.vcxproj.filters b/vc/vc10_fceux.vcxproj.filters index b15f6b74..0061fa0a 100644 --- a/vc/vc10_fceux.vcxproj.filters +++ b/vc/vc10_fceux.vcxproj.filters @@ -1414,6 +1414,30 @@ + + + + + + + + + + + + + + + + + + + + + + + +