* Taseditor: "Deselect" option in menus

* Taseditor: fixed some bugs with hotchanges
This commit is contained in:
ansstuff 2012-02-27 20:20:57 +00:00
parent 79ee86d1b6
commit 5b9df13cc5
15 changed files with 355 additions and 209 deletions

View File

@ -240,6 +240,7 @@ BEGIN
MENUITEM "Selection Undo\tCtrl+Q", ID_EDIT_SELECTIONUNDO,MFT_STRING,MFS_ENABLED
MENUITEM "Selection Redo\tCtrl+W", ID_EDIT_SELECTIONREDO,MFT_STRING,MFS_ENABLED
MENUITEM MFT_SEPARATOR
MENUITEM "Deselect", ID_EDIT_DESELECT,MFT_STRING,MFS_ENABLED
MENUITEM "Select All", ID_EDIT_SELECTALL,MFT_STRING,MFS_ENABLED
MENUITEM "Select between Markers\tCtrl+A", ID_EDIT_SELECTMIDMARKERS,MFT_STRING,MFS_ENABLED
MENUITEM "Reselect Clipboard\tCtrl+B", ID_EDIT_RESELECTCLIPBOARD,MFT_STRING,MFS_ENABLED
@ -389,6 +390,8 @@ BEGIN
BEGIN
MENUITEM "Set Marker", ID_SELECTED_SETMARKER
MENUITEM "Remove Marker", ID_SELECTED_REMOVEMARKER
MENUITEM SEPARATOR
MENUITEM "Deselect", ID_SELECTED_DESELECT
MENUITEM "Select between Markers", ID_SELECTED_SELECTMIDMARKERS
MENUITEM SEPARATOR
MENUITEM "Clear", ID_CONTEXT_SELECTED_CLEARFRAMES
@ -1438,18 +1441,18 @@ BEGIN
CONTROL " Use pattern",IDC_USEPATTERN,"Button",BS_AUTOCHECKBOX,261,96,53,10
END
IDD_TASEDITOR_ABOUT DIALOGEX 0, 0, 208, 70
IDD_TASEDITOR_ABOUT DIALOGEX 0, 0, 238, 78
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDCANCEL,78,49,50,14
ICON IDI_ICON4,IDC_STATIC,11,10,20,20
LTEXT "TAS Editor",IDC_STATIC,46,9,49,11
LTEXT "Version 1.0",IDC_STATIC,45,22,37,8
LTEXT "Created by AnS",IDC_STATIC,107,9,52,8
LTEXT "Based on TASEdit v0.1",IDC_STATIC,107,22,83,9,SS_NOPREFIX
LTEXT "made by zeromus & adelikat",IDC_STATIC,107,31,96,9,SS_NOPREFIX
DEFPUSHBUTTON "OK",IDCANCEL,94,55,50,14
ICON IDI_ICON4,IDC_STATIC,11,11,20,20
LTEXT "TAS Editor",IDC_TASEDITOR_NAME,43,8,83,13
LTEXT "Version 1.0",IDC_STATIC,63,25,37,8
LTEXT "Created by AnS",IDC_STATIC,138,12,52,8
LTEXT "Based on TASEdit v0.1",IDC_STATIC,138,25,83,9,SS_NOPREFIX
LTEXT "made by zeromus & adelikat",IDC_STATIC,138,35,96,9,SS_NOPREFIX
END
IDD_TASEDITOR_EXPORT DIALOGEX 0, 0, 158, 86

View File

@ -508,7 +508,7 @@
#define IDC_CHECK_SELECTION 1208
#define IDC_C_RESET 1209
#define IDC_CHECK8 1209
#define IDC_CHECK_PIANO_ROLL 1209
#define IDC_CHECK_PIANO_ROLL 1209
#define IDC_C_ELIMINATE 1210
#define IDC_LESSTHAN 1211
#define IDC_MORETHAN 1212
@ -588,6 +588,7 @@
#define IDC_SPLICER_BOX 1277
#define IDC_LUA_BOX 1278
#define IDC_HISTORY_BOX 1279
#define IDC_TASEDITOR_NAME 1280
#define MENU_NETWORK 40040
#define MENU_PALETTE 40041
#define MENU_SOUND 40042
@ -991,6 +992,8 @@
#define ID_PATTERN40533 40533
#define ID_PATTERN_TEST 40534
#define ID_CONFIG_COLUMNSETPATTERNSKIPSLAG 40535
#define ID_EDIT_DESELECT 40536
#define ID_SELECTED_DESELECT 40537
#define IDC_DEBUGGER_ICONTRAY 55535
#define MW_ValueLabel2 65423
#define MW_ValueLabel1 65426
@ -1000,8 +1003,8 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 206
#define _APS_NEXT_COMMAND_VALUE 40536
#define _APS_NEXT_CONTROL_VALUE 1280
#define _APS_NEXT_COMMAND_VALUE 40538
#define _APS_NEXT_CONTROL_VALUE 1281
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -532,16 +532,21 @@ void SaveCompact_GetCheckboxes(HWND hwndDlg)
taseditor_config.savecompact_selection = (SendDlgItemMessage(hwndDlg, IDC_CHECK_SELECTION, BM_GETCHECK, 0, 0) == BST_CHECKED);
}
BOOL CALLBACK AboutProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
BOOL CALLBACK AboutProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
SendMessage(GetDlgItem(hWnd, IDC_TASEDITOR_NAME), WM_SETFONT, (WPARAM)piano_roll.hTaseditorAboutFont, 0);
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, 0);
EndDialog(hWnd, 0);
return TRUE;
}
break;
@ -833,7 +838,7 @@ void SetInputType(MovieData& md, int new_input_type)
// this getter contains formula to decide whether to record or replay movie
bool TaseditorIsRecording()
{
if (movie_readonly || turbo || playback.pause_frame > currFrameCounter)
if (movie_readonly || playback.pause_frame > currFrameCounter)
return false; // replay
return true; // record
}

View File

@ -1068,27 +1068,21 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
}
}
void BOOKMARKS::LeftClick(LPNMITEMACTIVATE info)
void BOOKMARKS::LeftClick(int column_index, int row_index)
{
int cell_x = info->iSubItem;
int cell_y = info->iItem;
if (cell_y >= 0 && cell_x >= 0)
if (row_index >= 0 && column_index >= 0)
{
if (cell_x <= BOOKMARKS_COLUMN_FRAME || (taseditor_config.branch_only_when_rec && movie_readonly))
command(COMMAND_JUMP, (cell_y + 1) % TOTAL_BOOKMARKS);
else if (cell_x == BOOKMARKS_COLUMN_TIME && (!taseditor_config.branch_only_when_rec || !movie_readonly))
command(COMMAND_DEPLOY, (cell_y + 1) % TOTAL_BOOKMARKS);
if (column_index <= BOOKMARKS_COLUMN_FRAME || (taseditor_config.branch_only_when_rec && movie_readonly))
command(COMMAND_JUMP, (row_index + 1) % TOTAL_BOOKMARKS);
else if (column_index == BOOKMARKS_COLUMN_TIME && (!taseditor_config.branch_only_when_rec || !movie_readonly))
command(COMMAND_DEPLOY, (row_index + 1) % TOTAL_BOOKMARKS);
}
// remove selection
ListView_SetItemState(hwndBookmarksList, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
}
void BOOKMARKS::RightClick(LPNMITEMACTIVATE info)
void BOOKMARKS::RightClick(int column_index, int row_index)
{
int cell_y = info->iItem;
if (cell_y >= 0)
command(COMMAND_SET, (cell_y + 1) % TOTAL_BOOKMARKS);
// remove selection
ListView_SetItemState(hwndBookmarksList, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
// set Bookmark
if (row_index >= 0)
command(COMMAND_SET, (row_index + 1) % TOTAL_BOOKMARKS);
}
int BOOKMARKS::FindBookmarkAtFrame(int frame)
@ -1433,9 +1427,37 @@ LRESULT APIENTRY BookmarksListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
bookmarks.MouseMove(-1, -1);
break;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
// perform hit test
LVHITTESTINFO info;
info.pt.x = GET_X_LPARAM(lParam);
info.pt.y = GET_Y_LPARAM(lParam);
ListView_SubItemHitTest(hWnd, (LPARAM)&info);
bookmarks.LeftClick(info.iSubItem, info.iItem);
return 0;
}
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
// perform hit test
LVHITTESTINFO info;
info.pt.x = GET_X_LPARAM(lParam);
info.pt.y = GET_Y_LPARAM(lParam);
ListView_SubItemHitTest(hWnd, (LPARAM)&info);
bookmarks.RightClick(info.iSubItem, info.iItem);
return 0;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}
@ -1475,9 +1497,20 @@ LRESULT APIENTRY BranchesBitmapWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARA
EndPaint(hWnd, &ps);
return 0;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
return 0;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}

View File

@ -118,8 +118,8 @@ public:
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo);
LONG CustomDraw(NMLVCUSTOMDRAW* msg);
void LeftClick(LPNMITEMACTIVATE info);
void RightClick(LPNMITEMACTIVATE info);
void LeftClick(int column_index, int row_index);
void RightClick(int column_index, int row_index);
int FindBookmarkAtFrame(int frame);
int GetCurrentBranch();

View File

@ -42,11 +42,12 @@ extern int GetInputType(MovieData& md);
char history_save_id[HISTORY_ID_LEN] = "HISTORY";
char history_skipsave_id[HISTORY_ID_LEN] = "HISTORX";
char modCaptions[MODTYPES_TOTAL][20] = {" Init",
" Change",
" Undefined",
" Set",
" Unset",
" Pattern",
" Insert",
" Insert#",
" Delete",
" Truncate",
" Clear",
@ -204,13 +205,28 @@ int HISTORY::jump(int new_pos)
return first_change;
}
int HISTORY::undo()
void HISTORY::undo()
{
return jump(history_cursor_pos - 1);
int result = jump(history_cursor_pos - 1);
if (result >= 0)
{
piano_roll.update();
piano_roll.FollowUndo();
greenzone.InvalidateAndCheck(result);
}
return;
}
int HISTORY::redo()
void HISTORY::redo()
{
return jump(history_cursor_pos + 1);
int result = jump(history_cursor_pos + 1);
if (result >= 0)
{
piano_roll.update();
piano_roll.FollowUndo();
greenzone.InvalidateAndCheck(result);
}
return;
}
// ----------------------------
void HISTORY::AddSnapshotToHistory(SNAPSHOT &inp)
@ -251,7 +267,6 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
strcat(inp.description, modCaptions[mod_type]);
switch (mod_type)
{
case MODTYPE_CHANGE:
case MODTYPE_SET:
case MODTYPE_UNSET:
case MODTYPE_TRUNCATE:
@ -302,7 +317,6 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
case MODTYPE_CLONE:
inp.inheritHotChanges_InsertSelection(&snapshots[real_pos]);
break;
case MODTYPE_CHANGE:
case MODTYPE_SET:
case MODTYPE_UNSET:
case MODTYPE_CLEAR:
@ -323,6 +337,37 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
}
return first_changes;
}
int HISTORY::RegisterInsertNum(int start, int frames)
{
// create new shanshot
SNAPSHOT inp;
inp.init(currMovieData, taseditor_config.enable_hot_changes);
inp.mod_type = MODTYPE_INSERTNUM;
// 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]);
inp.jump_frame = start;
char framenum[11];
// add number of inserted frames to description
_itoa(frames, framenum, 10);
strcat(inp.description, framenum);
// add upper frame to description
_itoa(start, framenum, 10);
strcat(inp.description, " ");
strcat(inp.description, framenum);
// set hotchanges
if (taseditor_config.enable_hot_changes)
inp.inheritHotChanges_InsertNum(&snapshots[real_pos], start, frames);
AddSnapshotToHistory(inp);
bookmarks.ChangesMadeSinceBranch();
}
return first_changes;
}
int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
{
// create new shanshot
@ -781,6 +826,8 @@ LRESULT APIENTRY HistoryListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM l
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}

View File

@ -5,11 +5,12 @@
enum
{
MODTYPE_INIT,
MODTYPE_CHANGE, // deprecated
MODTYPE_UNDEFINED,
MODTYPE_SET,
MODTYPE_UNSET,
MODTYPE_PATTERN,
MODTYPE_INSERT,
MODTYPE_INSERTNUM,
MODTYPE_DELETE,
MODTYPE_TRUNCATE,
MODTYPE_CLEAR,
@ -67,11 +68,13 @@ public:
void save(EMUFILE *os, bool really_save = true);
bool load(EMUFILE *is);
int undo();
int redo();
int jump(int new_pos);
void undo();
void redo();
int RegisterChanges(int mod_type, int start = 0, int end =-1, const char* comment = 0);
int RegisterInsertNum(int start, int frames);
int RegisterPasteInsert(int start, SelectionFrames& inserted_set);
void RegisterMarkersChange(int mod_type, int start = 0, int end =-1, const char* comment = 0);
void RegisterBranching(int mod_type, int first_change, int slot);

View File

@ -89,6 +89,13 @@ void PIANO_ROLL::init()
ANSI_CHARSET, OUT_DEVICE_PRECIS, CLIP_MASK, /*charset, precision, clipping*/
DEFAULT_QUALITY, DEFAULT_PITCH, /*quality, and pitch*/
"Arial"); /*font name*/
hTaseditorAboutFont = CreateFont(24, 10, /*Height,Width*/
0, 0, /*escapement,orientation*/
FW_NORMAL, FALSE, FALSE, FALSE, /*weight, italic, underline, strikeout*/
ANSI_CHARSET, OUT_DEVICE_PRECIS, CLIP_MASK, /*charset, precision, clipping*/
DEFAULT_QUALITY, DEFAULT_PITCH, /*quality, and pitch*/
"Arial"); /*font name*/
bg_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
hwndList = GetDlgItem(taseditor_window.hwndTasEditor, IDC_LIST1);
@ -207,6 +214,11 @@ void PIANO_ROLL::free()
DeleteObject(hMarkersEditFont);
hMarkersEditFont = 0;
}
if (hTaseditorAboutFont)
{
DeleteObject(hTaseditorAboutFont);
hTaseditorAboutFont = 0;
}
if (bg_brush)
{
DeleteObject(bg_brush);
@ -1132,6 +1144,8 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}

View File

@ -159,7 +159,7 @@ public:
TRACKMOUSEEVENT tme;
// GDI stuff
HIMAGELIST himglist;
HFONT hMainListFont, hMainListSelectFont, hMarkersFont, hMarkersEditFont;
HFONT hMainListFont, hMainListSelectFont, hMarkersFont, hMarkersEditFont, hTaseditorAboutFont;
HBRUSH bg_brush;
private:

View File

@ -451,32 +451,69 @@ void PLAYBACK::ClickOnProgressbar()
// -------------------------------------------------------------------------
LRESULT APIENTRY UpperMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
extern PLAYBACK playback;
extern SELECTION selection;
switch(msg)
{
extern PLAYBACK playback;
extern SELECTION selection;
switch(msg)
case WM_SETFOCUS:
{
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_UPPER;
// enable editing
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETREADONLY, false, 0);
// disable FCEUX keyboard
taseditor_window.ClearTaseditorInput();
// scroll to the Marker
if (taseditor_config.follow_note_context)
piano_roll.FollowMarker(playback.shown_marker);
break;
}
case WM_KILLFOCUS:
{
// if we were editing, save and finish editing
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
markers_manager.UpdateMarkerNote();
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_NONE;
}
// disable editing (make the bg grayed)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETREADONLY, true, 0);
// enable FCEUX keyboard
if (taseditor_window.TASEditor_focus)
taseditor_window.SetTaseditorInput();
break;
}
case WM_CHAR:
case WM_KEYDOWN:
switch(wParam)
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
case VK_ESCAPE:
// revert text to original note text
SetWindowText(playback.hwndPlaybackMarkerEdit, markers_manager.GetNote(playback.shown_marker).c_str());
SetFocus(piano_roll.hwndList);
return 0;
case VK_RETURN:
// exit and save text changes
SetFocus(piano_roll.hwndList);
return 0;
case VK_TAB:
// switch to lower edit control (also exit and save text changes)
SetFocus(selection.hwndSelectionMarkerEdit);
return 0;
switch(wParam)
{
case VK_ESCAPE:
// revert text to original note text
SetWindowText(playback.hwndPlaybackMarkerEdit, markers_manager.GetNote(playback.shown_marker).c_str());
SetFocus(piano_roll.hwndList);
return 0;
case VK_RETURN:
// exit and save text changes
SetFocus(piano_roll.hwndList);
return 0;
case VK_TAB:
// switch to lower edit control (also exit and save text changes)
SetFocus(selection.hwndSelectionMarkerEdit);
return 0;
}
}
break;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}
}
return CallWindowProc(playbackMarkerEdit_oldWndproc, hWnd, msg, wParam, lParam);
}

View File

@ -441,7 +441,7 @@ void SELECTION::SetRowSelection(int index)
}
void SELECTION::SetRegionSelection(int start, int end)
{
for (int i = start; i <= end; ++i)
for (int i = start; i < end; ++i)
ListView_SetItemState(piano_roll.hwndList, i, LVIS_SELECTED, LVIS_SELECTED);
}
void SELECTION::SelectBetweenMarkers()
@ -564,32 +564,68 @@ SelectionFrames& SELECTION::CurrentSelection()
// -------------------------------------------------------------------------
LRESULT APIENTRY LowerMarkerEditWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
extern PLAYBACK playback;
extern SELECTION selection;
switch(msg)
{
extern PLAYBACK playback;
extern SELECTION selection;
switch(msg)
case WM_SETFOCUS:
{
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_LOWER;
// enable editing
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETREADONLY, false, 0);
// disable FCEUX keyboard
taseditor_window.ClearTaseditorInput();
// scroll to the Marker
if (taseditor_config.follow_note_context)
piano_roll.FollowMarker(selection.shown_marker);
break;
}
case WM_KILLFOCUS:
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
markers_manager.UpdateMarkerNote();
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_NONE;
}
// disable editing (make the bg grayed)
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETREADONLY, true, 0);
// enable FCEUX keyboard
if (taseditor_window.TASEditor_focus)
taseditor_window.SetTaseditorInput();
break;
}
case WM_CHAR:
case WM_KEYDOWN:
switch(wParam)
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
case VK_ESCAPE:
// revert text to original note text
SetWindowText(selection.hwndSelectionMarkerEdit, markers_manager.GetNote(selection.shown_marker).c_str());
SetFocus(piano_roll.hwndList);
return 0;
case VK_RETURN:
// exit and save text changes
SetFocus(piano_roll.hwndList);
return 0;
case VK_TAB:
// switch to upper edit control (also exit and save text changes)
SetFocus(playback.hwndPlaybackMarkerEdit);
return 0;
switch(wParam)
{
case VK_ESCAPE:
// revert text to original note text
SetWindowText(selection.hwndSelectionMarkerEdit, markers_manager.GetNote(selection.shown_marker).c_str());
SetFocus(piano_roll.hwndList);
return 0;
case VK_RETURN:
// exit and save text changes
SetFocus(piano_roll.hwndList);
return 0;
case VK_TAB:
// switch to upper edit control (also exit and save text changes)
SetFocus(playback.hwndPlaybackMarkerEdit);
return 0;
}
}
break;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
return 0;
}
}
return CallWindowProc(selectionMarkerEdit_oldWndproc, hWnd, msg, wParam, lParam);
}

View File

@ -637,12 +637,12 @@ void SNAPSHOT::inheritHotChanges_InsertSelection(SNAPSHOT* source_of_hotchanges)
region_len = 0;
// copy hotchanges of this frame
memcpy(&hot_changes[pos], &source_of_hotchanges->hot_changes[source_pos], bytes);
FadeHotChanges(pos, pos + bytes);
source_pos += bytes;
}
pos += bytes;
frame++;
}
FadeHotChanges();
} else
{
// no old data, just fill selected lines
@ -673,7 +673,30 @@ void SNAPSHOT::inheritHotChanges_InsertSelection(SNAPSHOT* source_of_hotchanges)
frame++;
}
}
}
}
void SNAPSHOT::inheritHotChanges_InsertNum(SNAPSHOT* source_of_hotchanges, int start, int frames)
{
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
// copy hot changes from source snapshot up to "start" and from "start+frames" to end
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
{
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
int bytes_to_copy = bytes * start;
int dest_pos = 0, source_pos = 0;
if (bytes_to_copy > source_size)
bytes_to_copy = source_size;
memcpy(&hot_changes[dest_pos], &source_of_hotchanges->hot_changes[source_pos], bytes_to_copy);
dest_pos += bytes_to_copy + bytes * frames;
source_pos += bytes_to_copy;
bytes_to_copy = this_size - dest_pos;
if (bytes_to_copy > source_size - source_pos)
bytes_to_copy = source_size - source_pos;
memcpy(&hot_changes[dest_pos], &source_of_hotchanges->hot_changes[source_pos], bytes_to_copy);
FadeHotChanges();
}
// now set filled lines on frames from start to start+frames
memset(&hot_changes[bytes * start], 0xFF, bytes * frames);
}
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)
@ -696,12 +719,12 @@ void SNAPSHOT::inheritHotChanges_PasteInsert(SNAPSHOT* source_of_hotchanges, Sel
{
// copy hotchanges of this frame
memcpy(&hot_changes[pos], &source_of_hotchanges->hot_changes[source_pos], bytes);
FadeHotChanges(pos, pos + bytes);
source_pos += bytes;
}
pos += bytes;
frame++;
}
FadeHotChanges();
} else
{
// no old data, just fill selected lines
@ -745,7 +768,7 @@ void SNAPSHOT::fillHotChanges(SNAPSHOT& inp, int start, int end)
{
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
{
// set changed if found different byte, or found emptiness in inp when there's non-zero value here
// consider changed if found different byte, or found emptiness in inp when there's non-zero value here
if (frame < inp_end)
{
if (joysticks[pos] != inp.joysticks[pos])
@ -782,7 +805,7 @@ void SNAPSHOT::fillHotChanges(SNAPSHOT& inp, int start, int end)
{
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
{
// set changed if found different byte, or found emptiness in inp when there's non-zero value here
// consider changed if found different byte, or found emptiness in inp when there's non-zero value here
if (frame < inp_end)
{
if (joysticks[pos] != inp.joysticks[pos])
@ -807,7 +830,7 @@ void SNAPSHOT::fillHotChanges(SNAPSHOT& inp, int start, int end)
{
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
{
// set changed if found different byte, or found emptiness in inp when there's non-zero value here
// consider changed if found different byte, or found emptiness in inp when there's non-zero value here
if (frame < inp_end)
{
if (joysticks[pos] != inp.joysticks[pos])
@ -878,10 +901,12 @@ void SNAPSHOT::SetMaxHotChange(int frame, int absolute_button)
}
}
void SNAPSHOT::FadeHotChanges()
void SNAPSHOT::FadeHotChanges(int start_byte, int end_byte)
{
uint8 hi_half, low_half;
for (int i = hot_changes.size() - 1; i >= 0; i--)
if (end_byte < 0)
end_byte = hot_changes.size();
for (int i = end_byte - 1; i >= start_byte; i--)
{
if (hot_changes[i])
{

View File

@ -46,13 +46,14 @@ public:
void inheritHotChanges(SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_DeleteSelection(SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_InsertSelection(SNAPSHOT* source_of_hotchanges);
void inheritHotChanges_InsertNum(SNAPSHOT* source_of_hotchanges, int start, int frames);
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);
void FadeHotChanges();
void FadeHotChanges(int start_byte = 0, int end_byte = -1);
int GetHotChangeInfo(int frame, int absolute_button);

View File

@ -109,12 +109,14 @@ void SPLICER::CloneFrames()
int frames = current_selection->size();
if (!frames) return;
selection.ClearSelection(); // selection will be moved down, so that same frames are selected
bool markers_changed = false;
currMovieData.records.reserve(currMovieData.getNumRecords() + frames);
// insert frames before each selection, but consecutive selection lines are accounted as single region
frames = 1;
SelectionFrames::reverse_iterator next_it;
SelectionFrames::reverse_iterator current_selection_rend = current_selection->rend();
int shift = frames;
frames = 1;
for(SelectionFrames::reverse_iterator it(current_selection->rbegin()); it != current_selection_rend; it++)
{
next_it = it;
@ -129,9 +131,13 @@ void SPLICER::CloneFrames()
if (markers_manager.insertEmpty(*it,frames))
markers_changed = true;
}
selection.SetRegionSelection((*it) + shift, (*it) + shift + frames);
shift -= frames;
// start accumulating next region
frames = 1;
} else frames++;
}
// check and register changes
int first_changes = history.RegisterChanges(MODTYPE_CLONE, *current_selection->begin());
if (first_changes >= 0)
{
@ -151,12 +157,14 @@ void SPLICER::InsertFrames()
int frames = current_selection->size();
if (!frames) return;
selection.ClearSelection(); // selection will be moved down, so that same frames are selected
bool markers_changed = false;
currMovieData.records.reserve(currMovieData.getNumRecords() + frames);
// insert frames before each selection, but consecutive selection lines are accounted as single region
frames = 1;
SelectionFrames::reverse_iterator next_it;
SelectionFrames::reverse_iterator current_selection_rend = current_selection->rend();
int shift = frames;
frames = 1;
for(SelectionFrames::reverse_iterator it(current_selection->rbegin()); it != current_selection_rend; it++)
{
next_it = it;
@ -164,15 +172,19 @@ void SPLICER::InsertFrames()
if (next_it == current_selection_rend || (int)*next_it < ((int)*it - 1))
{
// end of current region
currMovieData.insertEmpty(*it,frames);
currMovieData.insertEmpty(*it, frames);
if (taseditor_config.bind_markers)
{
if (markers_manager.insertEmpty(*it,frames))
if (markers_manager.insertEmpty(*it, frames))
markers_changed = true;
}
selection.SetRegionSelection((*it) + shift, (*it) + shift + frames);
shift -= frames;
// start accumulating next region
frames = 1;
} else frames++;
}
// check and register changes
int first_changes = history.RegisterChanges(MODTYPE_INSERT, *current_selection->begin());
if (first_changes >= 0)
{
@ -200,7 +212,6 @@ void SPLICER::InsertNumFrames()
{
// insert at selection
index = *current_selection->begin();
selection.ClearSelection();
} else
{
// insert at playback cursor
@ -212,10 +223,17 @@ void SPLICER::InsertNumFrames()
if (markers_manager.insertEmpty(index, frames))
markers_changed = true;
}
// select inserted rows
piano_roll.update();
selection.SetRegionSelection(index, index + frames - 1);
int first_changes = history.RegisterChanges(MODTYPE_INSERT, index);
if (current_selection->size())
{
// shift selection down, so that same frames are selected
piano_roll.update();
selection.ClearSelection();
SelectionFrames::iterator current_selection_end = current_selection->end();
for(SelectionFrames::iterator it(current_selection->begin()); it != current_selection_end; it++)
selection.SetRowSelection((*it) + frames);
}
// check and register changes
int first_changes = history.RegisterInsertNum(index, frames);
if (first_changes >= 0)
{
greenzone.InvalidateAndCheck(first_changes);
@ -256,7 +274,7 @@ void SPLICER::DeleteFrames()
playback.StartFromZero();
// reduce Piano Roll
piano_roll.update();
// check and register changes
int result = history.RegisterChanges(MODTYPE_DELETE, start_index);
if (result >= 0)
{

View File

@ -49,10 +49,10 @@ extern std::vector<std::vector<uint8>> autofire_patterns;
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);
extern BOOL CALLBACK FindNoteProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
extern BOOL CALLBACK AboutProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// Recent Menu
HMENU recent_projects_menu;
@ -635,7 +635,7 @@ void TASEDITOR_WINDOW::RecheckPatternsMenu()
}
// ====================================================================================================
BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
extern TASEDITOR_WINDOW taseditor_window;
switch(uMsg)
@ -654,7 +654,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
if (!(windowpos->flags & SWP_NOSIZE))
{
// window was resized
if (!IsIconic(hwndDlg))
if (!IsIconic(hWnd))
{
taseditor_window.WindowMovedOrResized();
if (taseditor_window.ready_for_resizing)
@ -665,7 +665,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
} else if (!(windowpos->flags & SWP_NOMOVE))
{
// window was moved
if (!IsIconic(hwndDlg) && !IsZoomed(hwndDlg))
if (!IsIconic(hWnd) && !IsZoomed(hWnd))
taseditor_window.WindowMovedOrResized();
// also change coordinates of popup display (and move if it's open)
popup_display.ParentWindowMoved();
@ -688,7 +688,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
switch(((LPNMHDR)lParam)->code)
{
case NM_CUSTOMDRAW:
SetWindowLong(hwndDlg, DWL_MSGRESULT, piano_roll.CustomDraw((NMLVCUSTOMDRAW*)lParam));
SetWindowLong(hWnd, DWL_MSGRESULT, piano_roll.CustomDraw((NMLVCUSTOMDRAW*)lParam));
return TRUE;
case LVN_GETDISPINFO:
piano_roll.GetDispInfo((NMLVDISPINFO*)lParam);
@ -705,25 +705,18 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
switch(((LPNMHDR)lParam)->code)
{
case NM_CUSTOMDRAW:
SetWindowLong(hwndDlg, DWL_MSGRESULT, bookmarks.CustomDraw((NMLVCUSTOMDRAW*)lParam));
SetWindowLong(hWnd, DWL_MSGRESULT, bookmarks.CustomDraw((NMLVCUSTOMDRAW*)lParam));
return TRUE;
case LVN_GETDISPINFO:
bookmarks.GetDispInfo((NMLVDISPINFO*)lParam);
break;
case NM_CLICK:
case NM_DBLCLK:
bookmarks.LeftClick((LPNMITEMACTIVATE)lParam);
break;
case NM_RCLICK:
bookmarks.RightClick((LPNMITEMACTIVATE)lParam);
break;
}
break;
case IDC_HISTORYLIST:
switch(((LPNMHDR)lParam)->code)
{
case NM_CUSTOMDRAW:
SetWindowLong(hwndDlg, DWL_MSGRESULT, history.CustomDraw((NMLVCUSTOMDRAW*)lParam));
SetWindowLong(hWnd, DWL_MSGRESULT, history.CustomDraw((NMLVCUSTOMDRAW*)lParam));
return TRUE;
case LVN_GETDISPINFO:
history.GetDispInfo((NMLVDISPINFO*)lParam);
@ -757,6 +750,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
}
break;
case WM_CTLCOLORSTATIC:
// change color of static text fields
if ((HWND)lParam == playback.hwndPlaybackMarker)
{
SetTextColor((HDC)wParam, PLAYBACK_MARKER_COLOR);
@ -768,7 +762,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
SetBkMode((HDC)wParam, TRANSPARENT);
return (BOOL)piano_roll.bg_brush;
}
break;
case WM_COMMAND:
{
@ -790,70 +783,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
// finally check all other commands
switch(loword_wparam)
{
case IDC_PLAYBACK_MARKER_EDIT:
{
switch (HIWORD(wParam))
{
case EN_SETFOCUS:
{
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_UPPER;
// enable editing
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETREADONLY, false, 0);
// disable FCEUX keyboard
taseditor_window.ClearTaseditorInput();
if (taseditor_config.follow_note_context)
piano_roll.FollowMarker(playback.shown_marker);
break;
}
case EN_KILLFOCUS:
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
{
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)
taseditor_window.SetTaseditorInput();
break;
}
}
break;
}
case IDC_SELECTION_MARKER_EDIT:
{
switch (HIWORD(wParam))
{
case EN_SETFOCUS:
{
markers_manager.marker_note_edit = MARKER_NOTE_EDIT_LOWER;
// enable editing
SendMessage(selection.hwndSelectionMarkerEdit, EM_SETREADONLY, false, 0);
// disable FCEUX keyboard
taseditor_window.ClearTaseditorInput();
if (taseditor_config.follow_note_context)
piano_roll.FollowMarker(selection.shown_marker);
break;
}
case EN_KILLFOCUS:
{
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_LOWER)
{
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)
taseditor_window.SetTaseditorInput();
break;
}
}
break;
}
case ID_FILE_NEW:
NewProject();
break;
@ -879,6 +808,10 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
case ID_FILE_CLOSE:
ExitTasEditor();
break;
case ID_EDIT_DESELECT:
case ID_SELECTED_DESELECT:
selection.ClearSelection();
break;
case ID_EDIT_SELECTALL:
if (markers_manager.marker_note_edit == MARKER_NOTE_EDIT_UPPER)
SendMessage(playback.hwndPlaybackMarkerEdit, EM_SETSEL, 0, -1);
@ -988,7 +921,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
playback.ToggleEmulationPause();
break;
case CHECK_FOLLOW_CURSOR:
//switch "Follow playback" flag
taseditor_config.follow_playback ^= 1;
taseditor_window.UpdateCheckedItems();
// if switched off then maybe jump to target frame
@ -996,7 +928,6 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
piano_roll.FollowPauseframe();
break;
case CHECK_TURBO_SEEK:
//switch "Turbo seek" flag
taseditor_config.turbo_seek ^= 1;
taseditor_window.UpdateCheckedItems();
// if currently seeking, apply this option immediately
@ -1015,12 +946,10 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
piano_roll.RedrawList(); // no need to redraw Bookmarks, as Markers are only shown in Piano Roll
break;
case ID_VIEW_SHOWBRANCHSCREENSHOTS:
//switch "Show Branch Screenshots" flag
taseditor_config.show_branch_screenshots ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_VIEW_SHOWBRANCHTOOLTIPS:
//switch "Show Branch Screenshots" flag
taseditor_config.show_branch_descr ^= 1;
taseditor_window.UpdateCheckedItems();
break;
@ -1038,14 +967,13 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
taseditor_window.UpdateCheckedItems();
break;
case CHECK_AUTORESTORE_PLAYBACK:
//switch "Auto-restore last playback position" flag
taseditor_config.restore_position ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_SETGREENZONECAPACITY:
{
int new_capacity = taseditor_config.greenzone_capacity;
if(CWin32InputBox::GetInteger("Greenzone capacity", "Keep savestates for how many frames?\n(actual limit of savestates can be 5 times more than the number provided)", new_capacity, hwndDlg) == IDOK)
if(CWin32InputBox::GetInteger("Greenzone capacity", "Keep savestates for how many frames?\n(actual limit of savestates can be 5 times more than the number provided)", new_capacity, hWnd) == IDOK)
{
if (new_capacity < GREENZONE_CAPACITY_MIN)
new_capacity = GREENZONE_CAPACITY_MIN;
@ -1062,7 +990,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
case ID_CONFIG_SETMAXUNDOLEVELS:
{
int new_size = taseditor_config.undo_levels;
if(CWin32InputBox::GetInteger("Max undo levels", "Keep history of how many changes?", new_size, hwndDlg) == IDOK)
if(CWin32InputBox::GetInteger("Max undo levels", "Keep history of how many changes?", new_size, hWnd) == IDOK)
{
if (new_size < UNDO_LEVELS_MIN)
new_size = UNDO_LEVELS_MIN;
@ -1082,7 +1010,7 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
case ID_CONFIG_SETAUTOSAVEPERIOD:
{
int new_period = taseditor_config.autosave_period;
if(CWin32InputBox::GetInteger("Autosave period", "How many minutes may the project stay not saved after being changed?\n(0 = no autosaves)", new_period, hwndDlg) == IDOK)
if(CWin32InputBox::GetInteger("Autosave period", "How many minutes may the project stay not saved after being changed?\n(0 = no autosaves)", new_period, hWnd) == IDOK)
{
if (new_period < AUTOSAVE_PERIOD_MIN)
new_period = AUTOSAVE_PERIOD_MIN;
@ -1094,18 +1022,15 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
break;
}
case ID_CONFIG_BRANCHESRESTOREFULLMOVIE:
//switch "Branches restore entire Movie" flag
taseditor_config.branch_full_movie ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_BRANCHESWORKONLYWHENRECORDING:
//switch "Branches work only when Recording" flag
taseditor_config.branch_only_when_rec ^= 1;
taseditor_window.UpdateCheckedItems();
bookmarks.RedrawBookmarksCaption();
break;
case ID_CONFIG_HUDINBRANCHSCREENSHOTS:
//switch "HUD in Branch screenshots" flag
taseditor_config.branch_scr_hud ^= 1;
taseditor_window.UpdateCheckedItems();
break;
@ -1119,12 +1044,10 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_COMBINECONSECUTIVERECORDINGS:
//switch "Combine consecutive Recordings" flag
taseditor_config.combine_consecutive_rec ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_USE1PFORRECORDING:
//switch "Use 1P keys for single Recordings" flag
taseditor_config.use_1p_rec ^= 1;
taseditor_window.UpdateCheckedItems();
break;
@ -1156,12 +1079,11 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
playback.ClickOnProgressbar();
break;
case IDC_BRANCHES_BUTTON:
// click on "Bookmarks/Branches" - switch "View Tree of branches"
// click on "Bookmarks/Branches" - switch between Bookmarks List and Branches Tree
taseditor_config.view_branches_tree ^= 1;
bookmarks.RedrawBookmarksCaption();
break;
case IDC_RECORDING:
// toggle readonly, no need to recheck radiobuttons
FCEUI_MovieToggleReadOnly();
CheckDlgButton(taseditor_window.hwndTasEditor, IDC_RECORDING, movie_readonly?BST_UNCHECKED : BST_CHECKED);
break;
@ -1222,26 +1144,14 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
SendMessage(selection.hwndSelectionMarkerEdit, WM_UNDO, 0, 0);
} else
{
int result = history.undo();
if (result >= 0)
{
piano_roll.update();
piano_roll.FollowUndo();
greenzone.InvalidateAndCheck(result);
}
history.undo();
}
break;
}
case ACCEL_CTRL_Y:
case ID_EDIT_REDO:
{
int result = history.redo();
if (result >= 0)
{
piano_roll.update();
piano_roll.FollowUndo();
greenzone.InvalidateAndCheck(result);
}
history.redo();
break;
}
case ID_EDIT_SELECTIONUNDO:
@ -1395,9 +1305,20 @@ BOOL CALLBACK WndprocTasEditor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
}
break;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
break;
}
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
{
if (GetFocus() != hWnd)
SetFocus(hWnd);
playback.MiddleButtonClick();
break;
}