* observing Piano Roll by dragging cursor outside

* dragging blue arrow (moving Playback cursor)
* moving Markers by drag'n'drop, "Marker Drag" and "Marker Swap" operations
* Config->Doubleclick on Frame# affects Playback
* Config->Draw Input by dragging
This commit is contained in:
ansstuff 2012-03-13 20:03:37 +00:00
parent a484b4eb15
commit 1af2f936ff
19 changed files with 728 additions and 110 deletions

View File

@ -348,6 +348,8 @@ static CFGSTRUCT fceuconfig[] = {
AC(taseditor_config.findnote_matchcase), AC(taseditor_config.findnote_matchcase),
AC(taseditor_config.findnote_search_up), AC(taseditor_config.findnote_search_up),
AC(taseditor_config.deselect_on_doubleclick), AC(taseditor_config.deselect_on_doubleclick),
AC(taseditor_config.doubleclick_affects_playback),
AC(taseditor_config.draw_input),
AC(taseditor_config.silent_autosave), AC(taseditor_config.silent_autosave),
AC(taseditor_config.tooltips), AC(taseditor_config.tooltips),
AC(taseditor_config.current_pattern), AC(taseditor_config.current_pattern),

View File

@ -71,6 +71,10 @@
#include "utils/xstring.h" #include "utils/xstring.h"
#include <string.h> #include <string.h>
#include "taseditor/taseditor_window.h" #include "taseditor/taseditor_window.h"
#include "taseditor/piano_roll.h"
extern TASEDITOR_WINDOW taseditor_window;
extern PIANO_ROLL piano_roll;
//--------------------------- //---------------------------
//mbg merge 6/29/06 - new aboutbox //mbg merge 6/29/06 - new aboutbox
@ -308,7 +312,6 @@ int BlockingCheck()
{ {
//other accelerator capable dialogs could be added here //other accelerator capable dialogs could be added here
extern HWND hwndMemWatch; extern HWND hwndMemWatch;
extern TASEDITOR_WINDOW taseditor_window;
int handled = 0; int handled = 0;
@ -336,12 +339,14 @@ int BlockingCheck()
} }
} }
if(!handled && taseditor_window.hwndTasEditor) if(!handled && taseditor_window.hwndTasEditor)
{ {
if(IsChild(taseditor_window.hwndTasEditor, msg.hwnd)) if(IsChild(taseditor_window.hwndTasEditor, msg.hwnd))
{
handled = TranslateAccelerator(taseditor_window.hwndTasEditor, fceu_hAccel, &msg); handled = TranslateAccelerator(taseditor_window.hwndTasEditor, fceu_hAccel, &msg);
if (handled)
piano_roll.AcceleratorDispatched();
}
} }
if(!handled && taseditor_window.hwndFindNote) if(!handled && taseditor_window.hwndFindNote)
{ {

View File

@ -292,6 +292,8 @@ BEGIN
MENUITEM MFT_SEPARATOR MENUITEM MFT_SEPARATOR
MENUITEM "Autofire Pattern skips Lag", ID_CONFIG_COLUMNSETPATTERNSKIPSLAG,MFT_STRING,MFS_ENABLED MENUITEM "Autofire Pattern skips Lag", ID_CONFIG_COLUMNSETPATTERNSKIPSLAG,MFT_STRING,MFS_ENABLED
MENUITEM "Deselect on doubleclick", ID_CONFIG_DESELECTONDOUBLECLICK,MFT_STRING,MFS_ENABLED MENUITEM "Deselect on doubleclick", ID_CONFIG_DESELECTONDOUBLECLICK,MFT_STRING,MFS_ENABLED
MENUITEM "Doubleclick on Frame# affects Playback", ID_CONFIG_DOUBLECLICKONFRAME,MFT_STRING,MFS_ENABLED
MENUITEM "Draw Input by dragging", ID_CONFIG_DRAWINPUTBYDRAGGING,MFT_STRING,MFS_ENABLED
MENUITEM MFT_SEPARATOR MENUITEM MFT_SEPARATOR
MENUITEM "Silent Autosave", ID_CONFIG_SILENTAUTOSAVE,MFT_STRING,MFS_ENABLED MENUITEM "Silent Autosave", ID_CONFIG_SILENTAUTOSAVE,MFT_STRING,MFS_ENABLED
MENUITEM "Mute Turbo", ID_CONFIG_MUTETURBO,MFT_STRING,MFS_ENABLED MENUITEM "Mute Turbo", ID_CONFIG_MUTETURBO,MFT_STRING,MFS_ENABLED
@ -1391,56 +1393,56 @@ BEGIN
EDITTEXT IDC_LABEL_NEWPPUUSED,76,166,155,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP EDITTEXT IDC_LABEL_NEWPPUUSED,76,166,155,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
END END
TASEDITOR DIALOGEX 0, 0, 323, 351 TASEDITOR DIALOGEX 0, 0, 325, 353
STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "TAS Editor" CAPTION "TAS Editor"
MENU TASEDITORMENU MENU TASEDITORMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
CONTROL "",IDC_PROGRESS_BUTTON,"Button",BS_OWNERDRAW,199,36,116,12 CONTROL "",IDC_PROGRESS_BUTTON,"Button",BS_OWNERDRAW,200,36,116,12
CONTROL "",IDC_BRANCHES_BUTTON,"Button",BS_OWNERDRAW,206,167,104,11 CONTROL "",IDC_BRANCHES_BUTTON,"Button",BS_OWNERDRAW,207,167,104,11
CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER,4,13,187,320 CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER,5,13,187,320
GROUPBOX " Playback ",IDC_PLAYBACK_BOX,196,0,123,62,BS_CENTER,WS_EX_RIGHT GROUPBOX " Playback ",IDC_PLAYBACK_BOX,197,0,123,62,BS_CENTER,WS_EX_RIGHT
GROUPBOX " Recorder ",IDC_RECORDER_BOX,196,63,123,46,BS_CENTER,WS_EX_RIGHT GROUPBOX " Recorder ",IDC_RECORDER_BOX,197,63,123,46,BS_CENTER,WS_EX_RIGHT
GROUPBOX " Splicer ",IDC_SPLICER_BOX,196,110,123,30,BS_CENTER,WS_EX_RIGHT GROUPBOX " Splicer ",IDC_SPLICER_BOX,197,110,123,30,BS_CENTER,WS_EX_RIGHT
GROUPBOX " Lua ",IDC_LUA_BOX,196,141,123,26,BS_CENTER,WS_EX_RIGHT GROUPBOX " Lua ",IDC_LUA_BOX,197,141,123,26,BS_CENTER,WS_EX_RIGHT
GROUPBOX " Bookmarks ",IDC_BOOKMARKS_BOX,196,169,123,102,BS_CENTER,WS_EX_RIGHT GROUPBOX " Bookmarks ",IDC_BOOKMARKS_BOX,197,169,123,102,BS_CENTER,WS_EX_RIGHT
GROUPBOX " History ",IDC_HISTORY_BOX,196,272,123,56,BS_CENTER,WS_EX_RIGHT GROUPBOX " History ",IDC_HISTORY_BOX,197,272,123,56,BS_CENTER,WS_EX_RIGHT
PUSHBUTTON "<<",TASEDITOR_REWIND_FULL,200,9,23,14,NOT WS_TABSTOP PUSHBUTTON "<<",TASEDITOR_REWIND_FULL,201,9,23,14,NOT WS_TABSTOP
PUSHBUTTON "<",TASEDITOR_REWIND,223,9,23,14,NOT WS_TABSTOP PUSHBUTTON "<",TASEDITOR_REWIND,224,9,23,14,NOT WS_TABSTOP
PUSHBUTTON "||",TASEDITOR_PLAYSTOP,246,9,23,14,NOT WS_TABSTOP PUSHBUTTON "||",TASEDITOR_PLAYSTOP,247,9,23,14,NOT WS_TABSTOP
PUSHBUTTON ">",TASEDITOR_FORWARD,269,9,23,14,NOT WS_TABSTOP PUSHBUTTON ">",TASEDITOR_FORWARD,270,9,23,14,NOT WS_TABSTOP
PUSHBUTTON ">>",TASEDITOR_FORWARD_FULL,292,9,23,14,NOT WS_TABSTOP PUSHBUTTON ">>",TASEDITOR_FORWARD_FULL,293,9,23,14,NOT WS_TABSTOP
CONTROL "",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | WS_BORDER,200,39,115,6 CONTROL "",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | WS_BORDER,201,39,115,6
CONTROL " Follow cursor",CHECK_FOLLOW_CURSOR,"Button",BS_AUTOCHECKBOX,202,25,56,12 CONTROL " Follow cursor",CHECK_FOLLOW_CURSOR,"Button",BS_AUTOCHECKBOX,203,25,56,12
CONTROL " Auto-restore last position",CHECK_AUTORESTORE_PLAYBACK, CONTROL " Auto-restore last position",CHECK_AUTORESTORE_PLAYBACK,
"Button",BS_AUTOCHECKBOX,202,48,105,12 "Button",BS_AUTOCHECKBOX,203,48,105,12
CONTROL "",IDC_BOOKMARKSLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | NOT WS_VISIBLE | WS_BORDER,201,178,113,89 CONTROL "",IDC_BOOKMARKSLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | NOT WS_VISIBLE | WS_BORDER,202,178,113,89
CONTROL "",IDC_HISTORYLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,201,282,113,42 CONTROL "",IDC_HISTORYLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,202,282,113,42
CONTROL " All",IDC_RADIO_ALL,"Button",BS_AUTORADIOBUTTON,290,71,24,10 CONTROL " All",IDC_RADIO_ALL,"Button",BS_AUTORADIOBUTTON,291,71,24,10
CONTROL " 1P",IDC_RADIO_1P,"Button",BS_AUTORADIOBUTTON,202,83,25,10 CONTROL " 1P",IDC_RADIO_1P,"Button",BS_AUTORADIOBUTTON,203,83,25,10
CONTROL " 2P",IDC_RADIO_2P,"Button",BS_AUTORADIOBUTTON,231,83,25,10 CONTROL " 2P",IDC_RADIO_2P,"Button",BS_AUTORADIOBUTTON,232,83,25,10
CONTROL " 3P",IDC_RADIO_3P,"Button",BS_AUTORADIOBUTTON,261,83,24,10 CONTROL " 3P",IDC_RADIO_3P,"Button",BS_AUTORADIOBUTTON,262,83,24,10
CONTROL " 4P",IDC_RADIO_4P,"Button",BS_AUTORADIOBUTTON,290,83,24,10 CONTROL " 4P",IDC_RADIO_4P,"Button",BS_AUTORADIOBUTTON,291,83,24,10
CONTROL " Superimpose",IDC_SUPERIMPOSE,"Button",BS_AUTO3STATE,202,96,55,10 CONTROL " Superimpose",IDC_SUPERIMPOSE,"Button",BS_AUTO3STATE,203,96,55,10
PUSHBUTTON "<<",TASEDITOR_PREV_MARKER,201,332,23,14,NOT WS_TABSTOP PUSHBUTTON "<<",TASEDITOR_PREV_MARKER,202,332,23,14,NOT WS_TABSTOP
PUSHBUTTON "Similar",TASEDITOR_FIND_BEST_SIMILAR_MARKER,224,332,34,14,NOT WS_TABSTOP PUSHBUTTON "Similar",TASEDITOR_FIND_BEST_SIMILAR_MARKER,225,332,34,14,NOT WS_TABSTOP
PUSHBUTTON "More",TASEDITOR_FIND_NEXT_SIMILAR_MARKER,258,332,34,14,NOT WS_TABSTOP PUSHBUTTON "More",TASEDITOR_FIND_NEXT_SIMILAR_MARKER,259,332,34,14,NOT WS_TABSTOP
PUSHBUTTON ">>",TASEDITOR_NEXT_MARKER,291,332,23,14,NOT WS_TABSTOP PUSHBUTTON ">>",TASEDITOR_NEXT_MARKER,292,332,23,14,NOT WS_TABSTOP
CONTROL "",IDC_JUMP_PLAYBACK_BUTTON,"Button",BS_OWNERDRAW,4,0,59,13 CONTROL "",IDC_JUMP_PLAYBACK_BUTTON,"Button",BS_OWNERDRAW,5,0,59,13
EDITTEXT IDC_PLAYBACK_MARKER_EDIT,64,0,127,13,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP EDITTEXT IDC_PLAYBACK_MARKER_EDIT,65,0,127,13,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP
RTEXT "Marker 0",IDC_PLAYBACK_MARKER,3,2,58,10,0,WS_EX_RIGHT RTEXT "Marker 0",IDC_PLAYBACK_MARKER,4,2,58,10,0,WS_EX_RIGHT
CONTROL "",IDC_JUMP_SELECTION_BUTTON,"Button",BS_OWNERDRAW,4,333,59,13 CONTROL "",IDC_JUMP_SELECTION_BUTTON,"Button",BS_OWNERDRAW,5,333,59,13
EDITTEXT IDC_SELECTION_MARKER_EDIT,64,333,127,13,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP EDITTEXT IDC_SELECTION_MARKER_EDIT,65,333,127,13,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP
RTEXT "Marker 99999",IDC_SELECTION_MARKER,3,335,58,10,0,WS_EX_RIGHT RTEXT "Marker 99999",IDC_SELECTION_MARKER,4,335,58,10,0,WS_EX_RIGHT
CONTROL "",IDC_BRANCHES_BITMAP,"Static",SS_OWNERDRAW | SS_NOTIFY | SS_REALSIZEIMAGE | NOT WS_VISIBLE,201,178,113,89 CONTROL "",IDC_BRANCHES_BITMAP,"Static",SS_OWNERDRAW | SS_NOTIFY | SS_REALSIZEIMAGE | NOT WS_VISIBLE,202,178,113,89
CONTROL " Turbo seek",CHECK_TURBO_SEEK,"Button",BS_AUTOCHECKBOX,262,25,50,12 CONTROL " Turbo seek",CHECK_TURBO_SEEK,"Button",BS_AUTOCHECKBOX,263,25,50,12
LTEXT "Selection: 0 rows, 16 columns",IDC_TEXT_SELECTION,203,118,112,10 LTEXT "Selection: 0 rows, 16 columns",IDC_TEXT_SELECTION,204,118,112,10
LTEXT "Clipboard: 0 rows, 16 columns",IDC_TEXT_CLIPBOARD,202,128,114,10 LTEXT "Clipboard: 0 rows, 16 columns",IDC_TEXT_CLIPBOARD,203,128,114,10
CONTROL " Recording",IDC_RECORDING,"Button",BS_AUTO3STATE,202,71,64,10 CONTROL " Recording",IDC_RECORDING,"Button",BS_AUTO3STATE,203,71,64,10
PUSHBUTTON "Run function",TASEDITOR_RUN_MANUAL,201,150,54,14,WS_DISABLED | NOT WS_TABSTOP PUSHBUTTON "Run function",TASEDITOR_RUN_MANUAL,202,150,54,14,WS_DISABLED | NOT WS_TABSTOP
CONTROL "Auto function",IDC_RUN_AUTO,"Button",BS_AUTOCHECKBOX,260,152,55,10 CONTROL "Auto function",IDC_RUN_AUTO,"Button",BS_AUTOCHECKBOX,261,152,55,10
CONTROL " Use pattern",IDC_USEPATTERN,"Button",BS_AUTOCHECKBOX,261,96,53,10 CONTROL " Use pattern",IDC_USEPATTERN,"Button",BS_AUTOCHECKBOX,262,96,53,10
END END
IDD_TASEDITOR_ABOUT DIALOGEX 0, 0, 238, 78 IDD_TASEDITOR_ABOUT DIALOGEX 0, 0, 238, 78
@ -1982,6 +1984,8 @@ BEGIN
"TASEDITOR", DIALOG "TASEDITOR", DIALOG
BEGIN BEGIN
RIGHTMARGIN, 323
BOTTOMMARGIN, 351
END END
IDD_TASEDITOR_ABOUT, DIALOG IDD_TASEDITOR_ABOUT, DIALOG

View File

@ -995,6 +995,8 @@
#define ID_EDIT_DESELECT 40536 #define ID_EDIT_DESELECT 40536
#define ID_SELECTED_DESELECT 40537 #define ID_SELECTED_DESELECT 40537
#define ID_CONFIG_DESELECTONDOUBLECLICK 40538 #define ID_CONFIG_DESELECTONDOUBLECLICK 40538
#define ID_CONFIG_DRAWINPUTBYDRAGGING 40539
#define ID_CONFIG_DOUBLECLICKONFRAME 40540
#define IDC_DEBUGGER_ICONTRAY 55535 #define IDC_DEBUGGER_ICONTRAY 55535
#define MW_ValueLabel2 65423 #define MW_ValueLabel2 65423
#define MW_ValueLabel1 65426 #define MW_ValueLabel1 65426
@ -1004,7 +1006,7 @@
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 206 #define _APS_NEXT_RESOURCE_VALUE 206
#define _APS_NEXT_COMMAND_VALUE 40539 #define _APS_NEXT_COMMAND_VALUE 40541
#define _APS_NEXT_CONTROL_VALUE 1281 #define _APS_NEXT_CONTROL_VALUE 1281
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif

View File

@ -290,10 +290,10 @@ void UpdateTasEditor()
// update all modules that need to be updated every frame // update all modules that need to be updated every frame
taseditor_window.update(); taseditor_window.update();
greenzone.update();
recorder.update(); recorder.update();
piano_roll.update(); piano_roll.update();
markers_manager.update(); markers_manager.update();
greenzone.update();
playback.update(); playback.update();
bookmarks.update(); bookmarks.update();
popup_display.update(); popup_display.update();

View File

@ -83,7 +83,9 @@ char modCaptions[MODTYPES_TOTAL][20] = {" Init Project",
" Marker Unset", " Marker Unset",
" Marker Pattern", " Marker Pattern",
" Marker Rename", " Marker Rename",
" Marker Move", " Marker Drag",
" Marker Swap",
" Marker Shift",
" LUA Marker Set", " LUA Marker Set",
" LUA Marker Unset", " LUA Marker Unset",
" LUA Marker Rename", " LUA Marker Rename",
@ -445,10 +447,15 @@ void HISTORY::RegisterMarkersChange(int mod_type, int start, int end, const char
_itoa(start, framenum, 10); _itoa(start, framenum, 10);
strcat(inp.description, " "); strcat(inp.description, " ");
strcat(inp.description, framenum); strcat(inp.description, framenum);
if (end > start) if (end > start || mod_type == MODTYPE_MARKER_DRAG || mod_type == MODTYPE_MARKER_SWAP)
{ {
if (mod_type == MODTYPE_MARKER_DRAG)
strcat(inp.description, "=>");
else if (mod_type == MODTYPE_MARKER_SWAP)
strcat(inp.description, "<=>");
else
strcat(inp.description, "-");
_itoa(end, framenum, 10); _itoa(end, framenum, 10);
strcat(inp.description, "-");
strcat(inp.description, framenum); strcat(inp.description, framenum);
} }
// add comment if there is one specified // add comment if there is one specified
@ -838,8 +845,13 @@ bool HISTORY::CursorOverHistoryList()
POINT p; POINT p;
if (GetCursorPos(&p)) if (GetCursorPos(&p))
{ {
RECT wrect;
GetWindowRect(hwndHistoryList, &wrect);
ScreenToClient(hwndHistoryList, &p); ScreenToClient(hwndHistoryList, &p);
if (p.x >= 0 && p.y >= 0 && p.x < window_items[HISTORYLIST_IN_WINDOWITEMS].width && p.y < (taseditor_config.wndheight + window_items[HISTORYLIST_IN_WINDOWITEMS].height - window_items[HISTORYLIST_IN_WINDOWITEMS].y)) if (p.x >= 0
&& p.y >= 0
&& p.x < window_items[HISTORYLIST_IN_WINDOWITEMS].width
&& p.y < (wrect.bottom - wrect.top))
return true; return true;
} }
return false; return false;

View File

@ -44,7 +44,9 @@ enum
MODTYPE_MARKER_UNSET, MODTYPE_MARKER_UNSET,
MODTYPE_MARKER_PATTERN, MODTYPE_MARKER_PATTERN,
MODTYPE_MARKER_RENAME, MODTYPE_MARKER_RENAME,
MODTYPE_MARKER_MOVE, MODTYPE_MARKER_DRAG,
MODTYPE_MARKER_SWAP,
MODTYPE_MARKER_SHIFT,
MODTYPE_LUA_MARKER_SET, MODTYPE_LUA_MARKER_SET,
MODTYPE_LUA_MARKER_UNSET, MODTYPE_LUA_MARKER_UNSET,
MODTYPE_LUA_MARKER_RENAME, MODTYPE_LUA_MARKER_RENAME,
@ -54,7 +56,6 @@ enum
}; };
#define HISTORY_NORMAL_COLOR 0x000000 #define HISTORY_NORMAL_COLOR 0x000000
#define HISTORYLIST_IN_WINDOWITEMS 18
#define WM_MOUSEWHEEL_RESENT WM_APP+123 #define WM_MOUSEWHEEL_RESENT WM_APP+123
#define HISTORY_ID_LEN 8 #define HISTORY_ID_LEN 8

View File

@ -185,7 +185,7 @@ void MARKERS_MANAGER::ClearMarker(int frame)
{ {
// erase corresponding note // erase corresponding note
markers.notes.erase(markers.notes.begin() + markers.markers_array[frame]); markers.notes.erase(markers.notes.begin() + markers.markers_array[frame]);
// erase marker // clear marker
markers.markers_array[frame] = 0; markers.markers_array[frame] = 0;
// decrease following markers' ids // decrease following markers' ids
int size = markers.markers_array.size(); int size = markers.markers_array.size();

View File

@ -10,7 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
Piano Roll - Piano Roll interface Piano Roll - Piano Roll interface
[Singleton] [Singleton]
* implements the working of Piano Roll List: creating, redrawing, scrolling, clicks * implements the working of Piano Roll List: creating, redrawing, scrolling, mouseover, clicks, drag
* on demand: scrolls visible area of the List to any given item: to Playback Cursor, to Selection Cursor, to "undo pointer", to a Marker * on demand: scrolls visible area of the List to any given item: to Playback Cursor, to Selection Cursor, to "undo pointer", to a Marker
* saves and loads current position of vertical scrolling from a project file. On error: scrolls the List to the beginning * saves and loads current position of vertical scrolling from a project file. On error: scrolls the List to the beginning
* implements the working of Piano Roll List Header: creating, redrawing, animating, mouseover, clicks * implements the working of Piano Roll List Header: creating, redrawing, animating, mouseover, clicks
@ -18,6 +18,7 @@ Piano Roll - Piano Roll interface
* regularly updates the size of the List according to current movie input, also updates lights in the List Header according to button presses data from Recorder and Alt key state * regularly updates the size of the List according to current movie input, also updates lights in the List Header according to button presses data from Recorder and Alt key state
* implements the working of mouse wheel: List scrolling, Playback cursor movement, Selection cursor movement * implements the working of mouse wheel: List scrolling, Playback cursor movement, Selection cursor movement
* implements context menu on Right-click * implements context menu on Right-click
* updates mouse cursor icon depending on item under cursor
* stores resources: save id, ids of columns, widths of columns, tables of colors, gradient of Hot Changes, gradient of Header flashings, timings of flashes, all fonts used in TAS Editor, images * stores resources: save id, ids of columns, widths of columns, tables of colors, gradient of Hot Changes, gradient of Header flashings, timings of flashes, all fonts used in TAS Editor, images
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
@ -43,21 +44,48 @@ extern HISTORY history;
extern MARKERS_MANAGER markers_manager; extern MARKERS_MANAGER markers_manager;
extern SELECTION selection; extern SELECTION selection;
extern Window_items_struct window_items[];
extern int GetInputType(MovieData& md); extern int GetInputType(MovieData& md);
LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT APIENTRY HeaderWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC hwndList_oldWndProc = 0, hwndHeader_oldWndproc = 0; WNDPROC hwndList_oldWndProc = 0, hwndHeader_oldWndproc = 0;
LRESULT APIENTRY MarkerDragBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
// resources // resources
char piano_roll_save_id[PIANO_ROLL_ID_LEN] = "PIANO_ROLL"; char piano_roll_save_id[PIANO_ROLL_ID_LEN] = "PIANO_ROLL";
char piano_roll_skipsave_id[PIANO_ROLL_ID_LEN] = "PIANO_ROLX"; char piano_roll_skipsave_id[PIANO_ROLL_ID_LEN] = "PIANO_ROLX";
COLORREF hot_changes_colors[16] = { 0x0, 0x5c4c44, 0x854604, 0xab2500, 0xc20006, 0xd6006f, 0xd40091, 0xba00a4, 0x9500ba, 0x7a00cc, 0x5800d4, 0x0045e2, 0x0063ea, 0x0079f4, 0x0092fa, 0x00aaff }; COLORREF hot_changes_colors[16] = { 0x0, 0x5c4c44, 0x854604, 0xab2500, 0xc20006, 0xd6006f, 0xd40091, 0xba00a4, 0x9500ba, 0x7a00cc, 0x5800d4, 0x0045e2, 0x0063ea, 0x0079f4, 0x0092fa, 0x00aaff };
//COLORREF hot_changes_colors[16] = { 0x0, 0x661212, 0x842B4E, 0x652C73, 0x48247D, 0x383596, 0x2947AE, 0x1E53C1, 0x135DD2, 0x116EDA, 0x107EE3, 0x0F8EEB, 0x209FF4, 0x3DB1FD, 0x51C2FF, 0x4DCDFF }; //COLORREF hot_changes_colors[16] = { 0x0, 0x661212, 0x842B4E, 0x652C73, 0x48247D, 0x383596, 0x2947AE, 0x1E53C1, 0x135DD2, 0x116EDA, 0x107EE3, 0x0F8EEB, 0x209FF4, 0x3DB1FD, 0x51C2FF, 0x4DCDFF };
COLORREF header_lights_colors[11] = { 0x0, 0x007313, 0x009100, 0x1daf00, 0x42c700, 0x65d900, 0x91e500, 0xb0f000, 0xdaf700, 0xf0fc7c, 0xfcffba }; COLORREF header_lights_colors[11] = { 0x0, 0x007313, 0x009100, 0x1daf00, 0x42c700, 0x65d900, 0x91e500, 0xb0f000, 0xdaf700, 0xf0fc7c, 0xfcffba };
char markerDragBoxClassName[] = "MarkerDragBox";
PIANO_ROLL::PIANO_ROLL() PIANO_ROLL::PIANO_ROLL()
{ {
hwndMarkerDragBox = 0;
// register MARKER_DRAG_BOX window class
wincl.hInstance = fceu_hInstance;
wincl.lpszClassName = markerDragBoxClassName;
wincl.lpfnWndProc = MarkerDragBoxWndProc;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = 0;
wincl.lpszMenuName = 0;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = 0;
if(!RegisterClassEx(&wincl))
FCEU_printf("Error registering MARKER_DRAG_BOX window class\n");
// create blendfunction
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = 0;
blend.SourceConstantAlpha = 255;
} }
void PIANO_ROLL::init() void PIANO_ROLL::init()
@ -97,6 +125,8 @@ void PIANO_ROLL::init()
"Arial"); /*font name*/ "Arial"); /*font name*/
bg_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); bg_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
marker_drag_box_brush = CreateSolidBrush(MARKED_FRAMENUM_COLOR);
marker_drag_box_brush_bind = CreateSolidBrush(BINDMARKED_FRAMENUM_COLOR);
hwndList = GetDlgItem(taseditor_window.hwndTasEditor, IDC_LIST1); hwndList = GetDlgItem(taseditor_window.hwndTasEditor, IDC_LIST1);
// prepare the main listview // prepare the main listview
@ -183,6 +213,20 @@ void PIANO_ROLL::init()
lvc.mask = LVCF_WIDTH; lvc.mask = LVCF_WIDTH;
lvc.cx = COLUMN_ICONS_WIDTH; lvc.cx = COLUMN_ICONS_WIDTH;
ListView_InsertColumn(hwndList, 0, &lvc); ListView_InsertColumn(hwndList, 0, &lvc);
// find rows top/height (for mouseover hittest calculations)
ListView_SetItemCountEx(hwndList, 1, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
RECT temp_rect;
if (ListView_GetSubItemRect(hwndList, 0, 0, LVIR_BOUNDS, &temp_rect) && temp_rect.bottom != temp_rect.top)
{
list_row_top = temp_rect.top;
list_row_height = temp_rect.bottom - temp_rect.top;
} else
{
// couldn't get rect, set default values
list_row_top = 20;
list_row_height = 14;
}
ListView_SetItemCountEx(hwndList, 0, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
hrmenu = LoadMenu(fceu_hInstance,"TASEDITORCONTEXTMENUS"); hrmenu = LoadMenu(fceu_hInstance,"TASEDITORCONTEXTMENUS");
header_colors.resize(TOTAL_COLUMNS); header_colors.resize(TOTAL_COLUMNS);
@ -190,7 +234,7 @@ void PIANO_ROLL::init()
tme.cbSize = sizeof(tme); tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE; tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwndHeader; tme.hwndTrack = hwndHeader;
drag_mode = DRAG_MODE_NONE;
} }
void PIANO_ROLL::free() void PIANO_ROLL::free()
{ {
@ -224,6 +268,21 @@ void PIANO_ROLL::free()
DeleteObject(bg_brush); DeleteObject(bg_brush);
bg_brush = 0; bg_brush = 0;
} }
if (marker_drag_box_brush)
{
DeleteObject(marker_drag_box_brush);
marker_drag_box_brush = 0;
}
if (marker_drag_box_brush_bind)
{
DeleteObject(marker_drag_box_brush_bind);
marker_drag_box_brush_bind = 0;
}
if (bg_brush)
{
DeleteObject(bg_brush);
bg_brush = 0;
}
if (himglist) if (himglist)
{ {
ImageList_Destroy(himglist); ImageList_Destroy(himglist);
@ -233,6 +292,7 @@ void PIANO_ROLL::free()
} }
void PIANO_ROLL::reset() void PIANO_ROLL::reset()
{ {
must_check_item_under_mouse = true;
vk_shift_release_time = vk_control_release_time = 0; vk_shift_release_time = vk_control_release_time = 0;
next_header_update_time = header_item_under_mouse = 0; next_header_update_time = header_item_under_mouse = 0;
// delete all columns except 0th // delete all columns except 0th
@ -274,7 +334,136 @@ void PIANO_ROLL::update()
if(currLVItemCount != movie_size) if(currLVItemCount != movie_size)
ListView_SetItemCountEx(hwndList, movie_size, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL); ListView_SetItemCountEx(hwndList, movie_size, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
// once per 40 milliseconds update colors alpha // update dragging
if (drag_mode != DRAG_MODE_NONE)
{
// check if user released left button
if (GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) >= 0)
FinishDrag();
}
// also scroll Piano Roll if user is dragging cursor outside
if (drag_mode != DRAG_MODE_NONE)
{
POINT p;
if (GetCursorPos(&p))
{
int scroll_dx = 0, scroll_dy = 0;
RECT wrect;
GetWindowRect(hwndList, &wrect);
ScreenToClient(hwndList, &p);
if (p.x < 0)
scroll_dx = p.x;
else if (p.x > (wrect.right - wrect.left))
scroll_dx = p.x - (wrect.right - wrect.left);
if (p.y < 0)
scroll_dy = p.y;
else if (p.y > (wrect.bottom - wrect.top))
scroll_dy = p.y - (wrect.bottom - wrect.top);
if (scroll_dx || scroll_dy)
ListView_Scroll(hwndList, scroll_dx, scroll_dy);
}
}
// perform drag
switch (drag_mode)
{
case DRAG_MODE_PLAYBACK:
{
if (!playback.pause_frame)
DragPlaybackCursor();
break;
}
case DRAG_MODE_MARKER:
{
// if suddenly source frame lost its Marker, abort drag
if (!markers_manager.GetMarker(marker_drag_framenum))
{
if (hwndMarkerDragBox)
{
DestroyWindow(hwndMarkerDragBox);
hwndMarkerDragBox = 0;
}
drag_mode = DRAG_MODE_NONE;
break;
}
// when dragging, always show semi-transparent yellow rectangle under mouse
POINT p = {0, 0};
GetCursorPos(&p);
int window_x = p.x - marker_drag_box_dx;
int window_y = p.y - marker_drag_box_dy;
if (!hwndMarkerDragBox)
{
hwndMarkerDragBox = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, markerDragBoxClassName, markerDragBoxClassName, WS_POPUP, window_x, window_y, COLUMN_FRAMENUM_WIDTH, list_row_height, taseditor_window.hwndTasEditor, NULL, fceu_hInstance, NULL);
ShowWindow(hwndMarkerDragBox, SW_SHOWNA);
SetLayeredWindowAttributes(hwndMarkerDragBox, 0, MARKER_DRAG_BOX_ALPHA, LWA_ALPHA);
UpdateLayeredWindow(hwndMarkerDragBox, 0, 0, 0, 0, 0, 0, &blend, ULW_ALPHA);
} else
{
SetWindowPos(hwndMarkerDragBox, 0, window_x, window_y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
}
// force dragging cursor icon
SetCursor(LoadCursor(0, IDC_ARROW));
must_check_item_under_mouse = false;
break;
}
case DRAG_MODE_SET:
case DRAG_MODE_UNSET:
{
POINT p;
if (GetCursorPos(&p))
{
RECT wrect;
GetWindowRect(hwndList, &wrect);
ScreenToClient(hwndList, &p);
int drawing_current_x = p.x + GetScrollPos(hwndList, SB_HORZ);
int drawing_current_y = p.y + GetScrollPos(hwndList, SB_VERT) * list_row_height;
// draw (or erase) line from [drawing_current_x, drawing_current_y] to (drawing_last_x, drawing_last_y)
int total_dx = drawing_last_x - drawing_current_x, total_dy = drawing_last_y - drawing_current_y;
double total_len = sqrt((double)(total_dx * total_dx + total_dy * total_dy));
LVHITTESTINFO info;
int row_index, column_index, joy, bit;
int min_row_index = currMovieData.getNumRecords(), max_row_index = -1;
bool changes_made = false;
for (double len = 0; len < total_len; len += DRAWING_MIN_LINE_LEN)
{
// perform hit test
info.pt.x = p.x + (len / total_len) * total_dx;
info.pt.y = p.y + (len / total_len) * total_dy;
ListView_SubItemHitTest(hwndList, &info);
row_index = info.iItem;
column_index = info.iSubItem;
if (row_index >= 0 && column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
{
joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
bit = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
if (drag_mode == DRAG_MODE_SET && !currMovieData.records[row_index].checkBit(joy, bit))
{
currMovieData.records[row_index].setBit(joy, bit);
changes_made = true;
if (min_row_index > row_index) min_row_index = row_index;
if (max_row_index < row_index) max_row_index = row_index;
} else if (drag_mode == DRAG_MODE_UNSET && currMovieData.records[row_index].checkBit(joy, bit))
{
currMovieData.records[row_index].clearBit(joy, bit);
changes_made = true;
if (min_row_index > row_index) min_row_index = row_index;
if (max_row_index < row_index) max_row_index = row_index;
}
}
}
if (changes_made)
{
if (drag_mode == DRAG_MODE_SET)
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_SET, min_row_index, max_row_index));
else
greenzone.InvalidateAndCheck(history.RegisterChanges(MODTYPE_UNSET, min_row_index, max_row_index));
}
drawing_last_x = drawing_current_x;
drawing_last_y = drawing_current_y;
}
break;
}
}
// once per 40 milliseconds update colors alpha in the Header
if (clock() > next_header_update_time) if (clock() > next_header_update_time)
{ {
next_header_update_time = clock() + HEADER_LIGHT_UPDATE_TICK; next_header_update_time = clock() + HEADER_LIGHT_UPDATE_TICK;
@ -283,7 +472,7 @@ void PIANO_ROLL::update()
// 1 - update Frame# columns' heads // 1 - update Frame# columns' heads
if (GetAsyncKeyState(VK_MENU) & 0x8000) if (GetAsyncKeyState(VK_MENU) & 0x8000)
light_value = HEADER_LIGHT_HOLD; light_value = HEADER_LIGHT_HOLD;
else if (header_item_under_mouse == COLUMN_FRAMENUM || header_item_under_mouse == COLUMN_FRAMENUM2) else if (drag_mode == DRAG_MODE_NONE && (header_item_under_mouse == COLUMN_FRAMENUM || header_item_under_mouse == COLUMN_FRAMENUM2))
light_value = (selection.GetCurrentSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER; light_value = (selection.GetCurrentSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER;
if (header_colors[COLUMN_FRAMENUM] < light_value) if (header_colors[COLUMN_FRAMENUM] < light_value)
{ {
@ -303,7 +492,7 @@ void PIANO_ROLL::update()
light_value = 0; light_value = 0;
if (recorder.current_joy[(i - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS] & (1 << ((i - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS))) if (recorder.current_joy[(i - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS] & (1 << ((i - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS)))
light_value = HEADER_LIGHT_HOLD; light_value = HEADER_LIGHT_HOLD;
else if (header_item_under_mouse == i) else if (drag_mode == DRAG_MODE_NONE && header_item_under_mouse == i)
light_value = (selection.GetCurrentSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER; light_value = (selection.GetCurrentSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER;
if (header_colors[i] < light_value) if (header_colors[i] < light_value)
{ {
@ -319,6 +508,56 @@ void PIANO_ROLL::update()
if (changes_made) if (changes_made)
RedrawHeader(); RedrawHeader();
} }
// change mouse cursor depending on what it points at
if (must_check_item_under_mouse)
{
LPCSTR cursor_icon = IDC_ARROW;
switch (drag_mode)
{
case DRAG_MODE_NONE:
{
// normal mouseover
POINT p;
if (GetCursorPos(&p))
{
RECT wrect;
GetWindowRect(hwndList, &wrect);
ScreenToClient(hwndList, &p);
if (p.x >= 0 && p.y >= 0 && p.x < (wrect.right - wrect.left) && p.y < (wrect.bottom - wrect.top))
{
// perform hit test
LVHITTESTINFO info;
info.pt.x = p.x;
info.pt.y = p.y;
ListView_SubItemHitTest(hwndList, &info);
int row_index = info.iItem;
int column_index = info.iSubItem;
if (row_index >= 0
&& (column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
&& markers_manager.GetMarker(row_index))
cursor_icon = IDC_SIZEALL;
}
}
break;
}
case DRAG_MODE_PLAYBACK:
{
// dragging Playback cursor - show either normal arrow or arrow+wait
if (playback.pause_frame)
cursor_icon = IDC_APPSTARTING;
break;
}
case DRAG_MODE_MARKER:
case DRAG_MODE_OBSERVE:
case DRAG_MODE_SET:
case DRAG_MODE_UNSET:
// show normal arrow
break;
}
SetCursor(LoadCursor(0, cursor_icon));
must_check_item_under_mouse = false;
}
} }
void PIANO_ROLL::save(EMUFILE *os, bool really_save) void PIANO_ROLL::save(EMUFILE *os, bool really_save)
@ -370,6 +609,7 @@ error:
void PIANO_ROLL::RedrawList() void PIANO_ROLL::RedrawList()
{ {
InvalidateRect(hwndList, 0, FALSE); InvalidateRect(hwndList, 0, FALSE);
must_check_item_under_mouse = true;
} }
void PIANO_ROLL::RedrawRow(int index) void PIANO_ROLL::RedrawRow(int index)
{ {
@ -483,6 +723,111 @@ void PIANO_ROLL::SetHeaderColumnLight(int column, int level)
} }
} }
void PIANO_ROLL::DragPlaybackCursor()
{
POINT p;
if (GetCursorPos(&p))
{
ScreenToClient(hwndList, &p);
// perform hit test
LVHITTESTINFO info;
info.pt.x = p.x;
info.pt.y = p.y;
ListView_SubItemHitTest(hwndList, &info);
int row_index = info.iItem;
if (row_index < 0)
row_index = ListView_GetTopIndex(hwndList) + (p.y - list_row_top) / list_row_height;
// send Playback there
if (currFrameCounter != row_index)
{
int lastCursor = currFrameCounter;
playback.jump(row_index);
if (lastCursor != currFrameCounter)
{
// redraw row where Playback cursor was (in case there's two or more drags before playback.update())
RedrawRow(lastCursor);
bookmarks.RedrawChangedBookmarks(lastCursor);
}
}
}
}
void PIANO_ROLL::FinishDrag()
{
switch (drag_mode)
{
case DRAG_MODE_MARKER:
{
// place Marker here
if (markers_manager.GetMarker(marker_drag_framenum))
{
POINT p;
if (GetCursorPos(&p))
{
ScreenToClient(hwndList, &p);
// perform hit test
LVHITTESTINFO info;
info.pt.x = p.x;
info.pt.y = p.y;
ListView_SubItemHitTest(hwndList, &info);
int row_index = info.iItem;
int column_index = info.iSubItem;
if (row_index >= 0 && row_index != marker_drag_framenum && (column_index <= COLUMN_FRAMENUM || column_index >= COLUMN_FRAMENUM2))
{
if (markers_manager.GetMarker(row_index))
{
int dragged_marker_id = markers_manager.GetMarker(marker_drag_framenum);
int destination_marker_id = markers_manager.GetMarker(row_index);
// swap Notes of these Markers
char dragged_marker_note[MAX_NOTE_LEN];
strcpy(dragged_marker_note, markers_manager.GetNote(dragged_marker_id).c_str());
if (strcmp(markers_manager.GetNote(destination_marker_id).c_str(), dragged_marker_note))
{
// notes are different, swap them
markers_manager.SetNote(dragged_marker_id, markers_manager.GetNote(destination_marker_id).c_str());
markers_manager.SetNote(destination_marker_id, dragged_marker_note);
history.RegisterMarkersChange(MODTYPE_MARKER_SWAP, marker_drag_framenum, row_index);
selection.must_find_current_marker = playback.must_find_current_marker = true;
SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
}
} else
{
// move Marker
int new_marker_id = markers_manager.SetMarker(row_index);
if (new_marker_id)
{
markers_manager.SetNote(new_marker_id, markers_manager.GetNote(markers_manager.GetMarker(marker_drag_framenum)).c_str());
// and delete it from old frame
markers_manager.ClearMarker(marker_drag_framenum);
RedrawRow(marker_drag_framenum);
RedrawRow(row_index);
history.RegisterMarkersChange(MODTYPE_MARKER_DRAG, marker_drag_framenum, row_index, markers_manager.GetNote(markers_manager.GetMarker(row_index)).c_str());
selection.must_find_current_marker = playback.must_find_current_marker = true;
SetHeaderColumnLight(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
}
}
}
}
}
if (hwndMarkerDragBox)
{
DestroyWindow(hwndMarkerDragBox);
hwndMarkerDragBox = 0;
}
break;
}
}
drag_mode = DRAG_MODE_NONE;
must_check_item_under_mouse = true;
}
void PIANO_ROLL::AcceleratorDispatched()
{
// hack for tapping Ctrl twice - if first was accelerator, then it won't count as first tap
vk_control_release_time = -1;
}
void PIANO_ROLL::GetDispInfo(NMLVDISPINFO* nmlvDispInfo) void PIANO_ROLL::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
{ {
LVITEM& item = nmlvDispInfo->item; LVITEM& item = nmlvDispInfo->item;
@ -1063,6 +1408,18 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_CHAR: case WM_CHAR:
case WM_KILLFOCUS: case WM_KILLFOCUS:
return 0; return 0;
case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT)
{
piano_roll.must_check_item_under_mouse = true;
return true;
}
break;
case WM_MOUSEMOVE:
{
piano_roll.must_check_item_under_mouse = true;
return 0;
}
case WM_NOTIFY: case WM_NOTIFY:
{ {
if (((LPNMHDR)lParam)->hwndFrom == piano_roll.hwndHeader) if (((LPNMHDR)lParam)->hwndFrom == piano_roll.hwndHeader)
@ -1082,9 +1439,18 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_KEYUP: case WM_KEYUP:
{ {
if (wParam == VK_SHIFT) if (wParam == VK_SHIFT)
piano_roll.vk_shift_release_time = clock(); {
else if (wParam == VK_CONTROL) if (piano_roll.vk_shift_release_time >= 0)
piano_roll.vk_control_release_time = clock(); piano_roll.vk_shift_release_time = clock();
else // this was accelerator
piano_roll.vk_shift_release_time = 0;
} else if (wParam == VK_CONTROL)
{
if (piano_roll.vk_control_release_time >= 0)
piano_roll.vk_control_release_time = clock();
else // this was accelerator
piano_roll.vk_control_release_time = 0;
}
break; break;
} }
case WM_KEYDOWN: case WM_KEYDOWN:
@ -1092,19 +1458,21 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
if (wParam == VK_SHIFT) if (wParam == VK_SHIFT)
{ {
// double-tap of Shift key // double-tap of Shift key
if (piano_roll.vk_shift_release_time + GetDoubleClickTime() > clock()) if ((int)(piano_roll.vk_shift_release_time + GetDoubleClickTime()) > clock())
piano_roll.FollowPlayback(); piano_roll.FollowPlayback();
} else if (wParam == VK_CONTROL) } else if (wParam == VK_CONTROL)
{ {
// double-tap of Ctrl key // double-tap of Ctrl key
if (piano_roll.vk_control_release_time + GetDoubleClickTime() > clock()) if ((int)(piano_roll.vk_control_release_time + GetDoubleClickTime()) > clock())
piano_roll.FollowSelection(); piano_roll.FollowSelection();
} }
// only allow 8 keys // only allow 8 keys
if (taseditor_config.keyboard_for_piano_roll && (wParam == VK_LEFT || wParam == VK_UP || wParam == VK_RIGHT || wParam == VK_DOWN || wParam == VK_END || wParam == VK_HOME || wParam == VK_PRIOR || wParam == VK_NEXT)) if (taseditor_config.keyboard_for_piano_roll && (wParam == VK_LEFT || wParam == VK_UP || wParam == VK_RIGHT || wParam == VK_DOWN || wParam == VK_END || wParam == VK_HOME || wParam == VK_PRIOR || wParam == VK_NEXT))
{
piano_roll.must_check_item_under_mouse = true;
break; break;
else }
return 0; return 0;
} }
case WM_TIMER: case WM_TIMER:
// disable timer of entering edit mode (there's no edit mode anyway) // disable timer of entering edit mode (there's no edit mode anyway)
@ -1118,25 +1486,32 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
LVHITTESTINFO info; LVHITTESTINFO info;
info.pt.x = GET_X_LPARAM(lParam); info.pt.x = GET_X_LPARAM(lParam);
info.pt.y = GET_Y_LPARAM(lParam); info.pt.y = GET_Y_LPARAM(lParam);
ListView_SubItemHitTest(hWnd, (LPARAM)&info); ListView_SubItemHitTest(hWnd, &info);
int row_index = info.iItem; int row_index = info.iItem;
int column_index = info.iSubItem; int column_index = info.iSubItem;
if(row_index >= 0) if(column_index == COLUMN_ICONS)
{ {
if(column_index == COLUMN_ICONS) // click on the "icons" column
piano_roll.DragPlaybackCursor();
if (piano_roll.drag_mode == DRAG_MODE_NONE)
piano_roll.drag_mode = DRAG_MODE_PLAYBACK;
} else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
{
// clicked on the "Frame#" column
if (msg == WM_LBUTTONDBLCLK && !alt_pressed)
{ {
// click on the "icons" column - jump to the frame // doubleclick - jump to the frame
playback.jump(row_index); if (taseditor_config.deselect_on_doubleclick)
} else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2) selection.ClearSelection();
{ if (taseditor_config.doubleclick_affects_playback)
// clicked on the "Frame#" column
if (msg == WM_LBUTTONDBLCLK && !alt_pressed)
{ {
// doubleclick - jump to the frame piano_roll.DragPlaybackCursor();
if (taseditor_config.deselect_on_doubleclick) if (piano_roll.drag_mode == DRAG_MODE_NONE)
selection.ClearSelection(); piano_roll.drag_mode = DRAG_MODE_PLAYBACK;
playback.jump(row_index); }
} else } else
{
if (row_index >= 0)
{ {
// set marker if clicked with Alt // set marker if clicked with Alt
if (alt_pressed) if (alt_pressed)
@ -1148,14 +1523,39 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
else else
history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, row_index); history.RegisterMarkersChange(MODTYPE_MARKER_UNSET, row_index);
piano_roll.RedrawRow(row_index); piano_roll.RedrawRow(row_index);
} else if (piano_roll.drag_mode == DRAG_MODE_NONE)
{
// check if user clicked on a Marker
if (markers_manager.GetMarker(row_index))
{
// start dragging the Marker
RECT temp_rect;
if (ListView_GetSubItemRect(piano_roll.hwndList, row_index, column_index, LVIR_BOUNDS, &temp_rect))
{
piano_roll.marker_drag_box_dx = GET_X_LPARAM(lParam) - temp_rect.left;
piano_roll.marker_drag_box_dy = GET_Y_LPARAM(lParam) - temp_rect.top;
} else
{
piano_roll.marker_drag_box_dx = 0;
piano_roll.marker_drag_box_dy = 0;
}
piano_roll.drag_mode = DRAG_MODE_MARKER;
piano_roll.marker_drag_framenum = row_index;
} else
{
piano_roll.drag_mode = DRAG_MODE_OBSERVE;
}
} }
// also select the row by calling hwndList_oldWndProc // also select the row by calling hwndList_oldWndProc
PostMessage(hWnd, WM_LBUTTONUP, 0, 0); // ensure that oldWndProc will exit its modal message loop immediately PostMessage(hWnd, WM_LBUTTONUP, 0, 0); // ensure that oldWndProc will exit its modal message loop immediately
CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam); CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam);
} }
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R) }
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
{
// clicked on input
if (row_index >= 0)
{ {
// clicked on input
// first call old wndproc to set selection on the row // first call old wndproc to set selection on the row
if (alt_pressed) if (alt_pressed)
wParam |= MK_SHIFT; // Alt should select region, just like Shift wParam |= MK_SHIFT; // Alt should select region, just like Shift
@ -1170,6 +1570,25 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
} else } else
{ {
piano_roll.ToggleJoypadBit(column_index, row_index, GET_KEYSTATE_WPARAM(wParam)); piano_roll.ToggleJoypadBit(column_index, row_index, GET_KEYSTATE_WPARAM(wParam));
if (piano_roll.drag_mode == DRAG_MODE_NONE)
{
if (taseditor_config.draw_input)
{
// if clicked on empty cell - start drawing, else start erasing
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
int bit = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
if (currMovieData.records[row_index].checkBit(joy, bit))
piano_roll.drag_mode = DRAG_MODE_SET;
else
piano_roll.drag_mode = DRAG_MODE_UNSET;
piano_roll.drawing_last_x = GET_X_LPARAM(lParam) + GetScrollPos(piano_roll.hwndList, SB_HORZ);
piano_roll.drawing_last_y = GET_Y_LPARAM(lParam) + GetScrollPos(piano_roll.hwndList, SB_VERT) * piano_roll.list_row_height;
} else
{
piano_roll.drag_mode = DRAG_MODE_OBSERVE;
}
}
} }
} }
} }
@ -1195,7 +1614,6 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
playback.ForwardFull(-zDelta / 120); playback.ForwardFull(-zDelta / 120);
else if (zDelta > 0) else if (zDelta > 0)
playback.RewindFull(zDelta / 120); playback.RewindFull(zDelta / 120);
return 0;
} else if (fwKeys & MK_CONTROL) } else if (fwKeys & MK_CONTROL)
{ {
// Ctrl + wheel = Selection rewind full(speed)/forward full(speed) // Ctrl + wheel = Selection rewind full(speed)/forward full(speed)
@ -1203,7 +1621,6 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
selection.JumpNextMarker(-zDelta / 120); selection.JumpNextMarker(-zDelta / 120);
else if (zDelta > 0) else if (zDelta > 0)
selection.JumpPrevMarker(zDelta / 120); selection.JumpPrevMarker(zDelta / 120);
return 0;
} else if (alt_pressed || fwKeys & MK_RBUTTON) } else if (alt_pressed || fwKeys & MK_RBUTTON)
{ {
// Right button + wheel = Alt + wheel = rewind/forward // Right button + wheel = Alt + wheel = rewind/forward
@ -1220,12 +1637,15 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
piano_roll.RedrawRow(lastCursor); piano_roll.RedrawRow(lastCursor);
bookmarks.RedrawChangedBookmarks(lastCursor); bookmarks.RedrawChangedBookmarks(lastCursor);
} }
return 0;
} else if (history.CursorOverHistoryList()) } else if (history.CursorOverHistoryList())
{ {
return SendMessage(history.hwndHistoryList, WM_MOUSEWHEEL_RESENT, wParam, lParam); return SendMessage(history.hwndHistoryList, WM_MOUSEWHEEL_RESENT, wParam, lParam);
} else
{
// normal scrolling
CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam);
} }
break; return 0;
} }
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
@ -1238,17 +1658,78 @@ LRESULT APIENTRY ListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
LVHITTESTINFO info; LVHITTESTINFO info;
info.pt.x = GET_X_LPARAM(lParam); info.pt.x = GET_X_LPARAM(lParam);
info.pt.y = GET_Y_LPARAM(lParam); info.pt.y = GET_Y_LPARAM(lParam);
ListView_SubItemHitTest(hWnd, (LPARAM)&info); ListView_SubItemHitTest(hWnd, &info);
// show context menu if user right-clicked on Frame# // show context menu if user right-clicked on Frame#
if(info.iSubItem <= COLUMN_FRAMENUM || info.iSubItem >= COLUMN_FRAMENUM2) if(info.iSubItem <= COLUMN_FRAMENUM || info.iSubItem >= COLUMN_FRAMENUM2)
piano_roll.RightClick(info); piano_roll.RightClick(info);
return 0; return 0;
} }
case WM_MOUSEACTIVATE: case WM_NCLBUTTONDOWN:
{
if (wParam == HTBORDER)
{
POINT p;
p.x = GET_X_LPARAM(lParam);
p.y = GET_Y_LPARAM(lParam);
ScreenToClient(piano_roll.hwndList, &p);
if (p.x <= 0)
{
// user clicked on left border of the Piano Roll
// consider this as a "misclick" on Piano Roll's first column
piano_roll.DragPlaybackCursor();
if (piano_roll.drag_mode == DRAG_MODE_NONE)
piano_roll.drag_mode = DRAG_MODE_PLAYBACK;
return 0;
}
}
break;
}
case WM_MOUSEACTIVATE:
{
if (GetFocus() != hWnd) if (GetFocus() != hWnd)
SetFocus(hWnd); SetFocus(hWnd);
break; break;
}
case LVM_ENSUREVISIBLE:
{
piano_roll.must_check_item_under_mouse = true;
break;
}
} }
return CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam); return CallWindowProc(hwndList_oldWndProc, hWnd, msg, wParam, lParam);
} }
// ----------------------------------------------------------------------------------------
LRESULT APIENTRY MarkerDragBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
extern PIANO_ROLL piano_roll;
switch(message)
{
case WM_CREATE:
{
// create static bitmap placeholder
char framenum[DIGITS_IN_FRAMENUM + 1];
U32ToDecStr(framenum, piano_roll.marker_drag_framenum, DIGITS_IN_FRAMENUM);
piano_roll.hwndMarkerDragBoxText = CreateWindow(WC_STATIC, framenum, SS_CENTER| WS_CHILD | WS_VISIBLE, 0, 0, COLUMN_FRAMENUM_WIDTH, piano_roll.list_row_height, hwnd, NULL, NULL, NULL);
SendMessage(piano_roll.hwndMarkerDragBoxText, WM_SETFONT, (WPARAM)piano_roll.hMainListSelectFont, 0);
return 0;
}
case WM_CTLCOLORSTATIC:
{
// change color of static text fields
if ((HWND)lParam == piano_roll.hwndMarkerDragBoxText)
{
SetTextColor((HDC)wParam, NORMAL_TEXT_COLOR);
SetBkMode((HDC)wParam, TRANSPARENT);
if (taseditor_config.bind_markers)
return (LRESULT)(piano_roll.marker_drag_box_brush_bind);
else
return (LRESULT)(piano_roll.marker_drag_box_brush);
}
break;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

View File

@ -19,6 +19,9 @@
#define BOOST_WHEN_BOTH_RIGHTBUTTON_AND_ALT_PRESSED 4 #define BOOST_WHEN_BOTH_RIGHTBUTTON_AND_ALT_PRESSED 4
#define MARKER_DRAG_BOX_ALPHA 175
#define DRAWING_MIN_LINE_LEN 14 // = min(list_row_width, list_row_height) in pixels
enum enum
{ {
COLUMN_ICONS, COLUMN_ICONS,
@ -60,6 +63,16 @@ enum
TOTAL_COLUMNS TOTAL_COLUMNS
}; };
enum DRAG_MODES
{
DRAG_MODE_NONE,
DRAG_MODE_OBSERVE,
DRAG_MODE_PLAYBACK,
DRAG_MODE_MARKER,
DRAG_MODE_SET,
DRAG_MODE_UNSET,
};
// when there's too many button columns, there's need for 2nd Frame# column at the end // when there's too many button columns, there's need for 2nd Frame# column at the end
#define NUM_COLUMNS_NEED_2ND_FRAMENUM COLUMN_JOYPAD4_R #define NUM_COLUMNS_NEED_2ND_FRAMENUM COLUMN_JOYPAD4_R
@ -139,6 +152,11 @@ public:
void SetHeaderColumnLight(int column, int level); void SetHeaderColumnLight(int column, int level);
void DragPlaybackCursor();
void FinishDrag();
void AcceleratorDispatched();
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo); void GetDispInfo(NMLVDISPINFO* nmlvDispInfo);
LONG CustomDraw(NMLVCUSTOMDRAW* msg); LONG CustomDraw(NMLVCUSTOMDRAW* msg);
LONG HeaderCustomDraw(NMLVCUSTOMDRAW* msg); LONG HeaderCustomDraw(NMLVCUSTOMDRAW* msg);
@ -158,13 +176,22 @@ public:
HWND hwndList, hwndHeader; HWND hwndList, hwndHeader;
TRACKMOUSEEVENT tme; TRACKMOUSEEVENT tme;
unsigned int drag_mode;
int list_row_top, list_row_height;
int marker_drag_box_dx, marker_drag_box_dy;
int marker_drag_framenum;
int drawing_last_x, drawing_last_y;
bool must_check_item_under_mouse;
int vk_shift_release_time; int vk_shift_release_time;
int vk_control_release_time; int vk_control_release_time;
HWND hwndMarkerDragBox, hwndMarkerDragBoxText;
// GDI stuff // GDI stuff
HIMAGELIST himglist; HIMAGELIST himglist;
HFONT hMainListFont, hMainListSelectFont, hMarkersFont, hMarkersEditFont, hTaseditorAboutFont; HFONT hMainListFont, hMainListSelectFont, hMarkersFont, hMarkersEditFont, hTaseditorAboutFont;
HBRUSH bg_brush; HBRUSH bg_brush, marker_drag_box_brush, marker_drag_box_brush_bind;
private: private:
void CenterListAt(int frame); void CenterListAt(int frame);
@ -175,4 +202,7 @@ private:
HMENU hrmenu; HMENU hrmenu;
WNDCLASSEX wincl;
BLENDFUNCTION blend;
}; };

View File

@ -68,7 +68,7 @@ void PLAYBACK::reset()
{ {
must_find_current_marker = true; must_find_current_marker = true;
shown_marker = 0; shown_marker = 0;
lastCursor = -1; lastCursor = currFrameCounter;
lost_position_frame = pause_frame = old_pauseframe = 0; lost_position_frame = pause_frame = old_pauseframe = 0;
old_show_pauseframe = show_pauseframe = false; old_show_pauseframe = show_pauseframe = false;
old_rewind_button_state = rewind_button_state = false; old_rewind_button_state = rewind_button_state = false;
@ -172,17 +172,29 @@ void PLAYBACK::update()
emu_paused = (FCEUI_EmulationPaused() != 0); emu_paused = (FCEUI_EmulationPaused() != 0);
if (pause_frame) if (pause_frame)
{ {
if (old_show_pauseframe != show_pauseframe) if (old_show_pauseframe != show_pauseframe) // update progressbar from time to time
SetProgressbar(currFrameCounter - seeking_start_frame, pause_frame - seeking_start_frame); SetProgressbar(currFrameCounter - seeking_start_frame, pause_frame - seeking_start_frame);
} else if (old_emu_paused != emu_paused) } else if (old_emu_paused != emu_paused)
{ {
// emulator got paused/unpaused externally // emulator got paused/unpaused externally
if (old_emu_paused && !emu_paused) if (old_emu_paused && !emu_paused)
// externally unpaused - progressbar should be empty {
SetProgressbar(0, 1); // externally unpaused
else if (currFrameCounter < currMovieData.getNumRecords()-1)
{
// don't forget to stop at the end of the movie
pause_frame = currMovieData.getNumRecords();
seeking_start_frame = currFrameCounter;
} else
{
// unlimited emulation, appending the movie - progressbar should be empty
SetProgressbar(0, 1);
}
} else
{
// externally paused - progressbar should be full // externally paused - progressbar should be full
SetProgressbar(1, 1); SetProgressbar(1, 1);
}
} }
// update the playback cursor // update the playback cursor
@ -278,6 +290,17 @@ void PLAYBACK::SeekingStart(int finish_frame)
turbo = true; turbo = true;
UnpauseEmulation(); UnpauseEmulation();
} }
void PLAYBACK::SeekingContinue()
{
if (pause_frame)
{
if (taseditor_config.turbo_seek)
turbo = true;
UnpauseEmulation();
}
}
void PLAYBACK::SeekingStop() void PLAYBACK::SeekingStop()
{ {
pause_frame = 0; pause_frame = 0;
@ -388,10 +411,16 @@ bool PLAYBACK::JumpToFrame(int index)
// Returns true if a jump to the frame is made, false if started seeking outside greenzone or if nothing's done // Returns true if a jump to the frame is made, false if started seeking outside greenzone or if nothing's done
if (index < 0) return false; if (index < 0) return false;
if (index+1 == pause_frame && emu_paused)
{
SeekingContinue();
return false;
}
if (index >= greenzone.greenZoneCount) if (index >= greenzone.greenZoneCount)
{ {
// handle jump outside greenzone // handle jump outside greenzone
if (currFrameCounter == greenzone.greenZoneCount-1 || JumpToFrame(greenzone.greenZoneCount-1)) if (currFrameCounter >= greenzone.greenZoneCount-1 || JumpToFrame(greenzone.greenZoneCount-1))
// seek from the end of greenzone // seek from the end of greenzone
SeekingStart(index+1); SeekingStart(index+1);
return false; return false;

View File

@ -21,6 +21,7 @@ public:
void updateProgressbar(); void updateProgressbar();
void SeekingStart(int finish_frame); void SeekingStart(int finish_frame);
void SeekingContinue();
void SeekingStop(); void SeekingStop();
void ToggleEmulationPause(); void ToggleEmulationPause();
void PauseEmulation(); void PauseEmulation();
@ -43,6 +44,7 @@ public:
bool JumpToFrame(int index); bool JumpToFrame(int index);
int lastCursor; // but for currentCursor we use external variable currFrameCounter
int lost_position_frame; int lost_position_frame;
int pause_frame; int pause_frame;
bool must_find_current_marker; bool must_find_current_marker;
@ -53,7 +55,6 @@ public:
private: private:
int lastCursor; // but for currentCursor we use external variable currFrameCounter
bool old_emu_paused, emu_paused; bool old_emu_paused, emu_paused;
int old_pauseframe; int old_pauseframe;
bool old_show_pauseframe, show_pauseframe; bool old_show_pauseframe, show_pauseframe;

View File

@ -26,7 +26,7 @@ extern PIANO_ROLL piano_roll;
extern MARKERS_MANAGER markers_manager; extern MARKERS_MANAGER markers_manager;
LRESULT CALLBACK ScrBmpWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK ScrBmpWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT APIENTRY MarkerNoteTooltipWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT APIENTRY MarkerNoteDescrWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
// resources // resources
char szClassName[] = "ScrBmp"; char szClassName[] = "ScrBmp";
@ -34,6 +34,8 @@ char szClassName2[] = "MarketNoteTooltip";
POPUP_DISPLAY::POPUP_DISPLAY() POPUP_DISPLAY::POPUP_DISPLAY()
{ {
hwndScrBmp = 0;
hwndMarkerNoteTooltip = 0;
// create BITMAPINFO // create BITMAPINFO
scr_bmi = (LPBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); // 256 color in palette scr_bmi = (LPBITMAPINFO)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); // 256 color in palette
scr_bmi->bmiHeader.biSize = sizeof(scr_bmi->bmiHeader); scr_bmi->bmiHeader.biSize = sizeof(scr_bmi->bmiHeader);
@ -44,7 +46,7 @@ POPUP_DISPLAY::POPUP_DISPLAY()
scr_bmi->bmiHeader.biCompression = BI_RGB; scr_bmi->bmiHeader.biCompression = BI_RGB;
scr_bmi->bmiHeader.biSizeImage = 0; scr_bmi->bmiHeader.biSizeImage = 0;
// register MarketNoteTooltip window class // register SCREENSHOT_DISPLAY window class
wincl1.hInstance = fceu_hInstance; wincl1.hInstance = fceu_hInstance;
wincl1.lpszClassName = szClassName; wincl1.lpszClassName = szClassName;
wincl1.lpfnWndProc = ScrBmpWndProc; wincl1.lpfnWndProc = ScrBmpWndProc;
@ -60,10 +62,10 @@ POPUP_DISPLAY::POPUP_DISPLAY()
if(!RegisterClassEx(&wincl1)) if(!RegisterClassEx(&wincl1))
FCEU_printf("Error registering SCREENSHOT_DISPLAY window class\n"); FCEU_printf("Error registering SCREENSHOT_DISPLAY window class\n");
// register ScrBmp window class // register MARKER_NOTE_DESCRIPTION window class
wincl2.hInstance = fceu_hInstance; wincl2.hInstance = fceu_hInstance;
wincl2.lpszClassName = szClassName2; wincl2.lpszClassName = szClassName2;
wincl2.lpfnWndProc = MarkerNoteTooltipWndProc; wincl2.lpfnWndProc = MarkerNoteDescrWndProc;
wincl2.style = CS_DBLCLKS; wincl2.style = CS_DBLCLKS;
wincl2.cbSize = sizeof(WNDCLASSEX); wincl2.cbSize = sizeof(WNDCLASSEX);
wincl2.hIcon = 0; wincl2.hIcon = 0;
@ -74,7 +76,7 @@ POPUP_DISPLAY::POPUP_DISPLAY()
wincl2.cbWndExtra = 0; wincl2.cbWndExtra = 0;
wincl2.hbrBackground = 0; wincl2.hbrBackground = 0;
if(!RegisterClassEx(&wincl2)) if(!RegisterClassEx(&wincl2))
FCEU_printf("Error registering MARKER_NOTE_TOOLTIP window class\n"); FCEU_printf("Error registering MARKER_NOTE_DESCRIPTION window class\n");
// create blendfunction // create blendfunction
blend.BlendOp = AC_SRC_OVER; blend.BlendOp = AC_SRC_OVER;
@ -272,7 +274,7 @@ LRESULT APIENTRY ScrBmpWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lP
return DefWindowProc(hwnd, message, wParam, lParam); return DefWindowProc(hwnd, message, wParam, lParam);
} }
} }
LRESULT APIENTRY MarkerNoteTooltipWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT APIENTRY MarkerNoteDescrWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
extern POPUP_DISPLAY popup_display; extern POPUP_DISPLAY popup_display;
switch(message) switch(message)

View File

@ -144,7 +144,7 @@ void SPLICER::CloneFrames()
greenzone.InvalidateAndCheck(first_changes); greenzone.InvalidateAndCheck(first_changes);
} else if (markers_changed) } else if (markers_changed)
{ {
history.RegisterMarkersChange(MODTYPE_MARKER_MOVE, *current_selection->begin()); history.RegisterMarkersChange(MODTYPE_MARKER_SHIFT, *current_selection->begin());
piano_roll.RedrawList(); piano_roll.RedrawList();
} }
if (markers_changed) if (markers_changed)
@ -191,7 +191,7 @@ void SPLICER::InsertFrames()
greenzone.InvalidateAndCheck(first_changes); greenzone.InvalidateAndCheck(first_changes);
} else if (markers_changed) } else if (markers_changed)
{ {
history.RegisterMarkersChange(MODTYPE_MARKER_MOVE, *current_selection->begin()); history.RegisterMarkersChange(MODTYPE_MARKER_SHIFT, *current_selection->begin());
piano_roll.RedrawList(); piano_roll.RedrawList();
} }
if (markers_changed) if (markers_changed)
@ -239,7 +239,7 @@ void SPLICER::InsertNumFrames()
greenzone.InvalidateAndCheck(first_changes); greenzone.InvalidateAndCheck(first_changes);
} else if (markers_changed) } else if (markers_changed)
{ {
history.RegisterMarkersChange(MODTYPE_MARKER_MOVE, index); history.RegisterMarkersChange(MODTYPE_MARKER_SHIFT, index);
piano_roll.RedrawList(); piano_roll.RedrawList();
} }
if (markers_changed) if (markers_changed)
@ -287,7 +287,7 @@ void SPLICER::DeleteFrames()
else else
piano_roll.RedrawList(); piano_roll.RedrawList();
if (markers_changed) if (markers_changed)
history.RegisterMarkersChange(MODTYPE_MARKER_MOVE, start_index); history.RegisterMarkersChange(MODTYPE_MARKER_SHIFT, start_index);
} }
} }
@ -652,7 +652,7 @@ bool SPLICER::PasteInsert()
greenzone.InvalidateAndCheck(first_changes); greenzone.InvalidateAndCheck(first_changes);
} else if (markers_changed) } else if (markers_changed)
{ {
history.RegisterMarkersChange(MODTYPE_MARKER_MOVE, *current_selection->begin()); history.RegisterMarkersChange(MODTYPE_MARKER_SHIFT, *current_selection->begin());
piano_roll.RedrawList(); piano_roll.RedrawList();
} }
if (markers_changed) if (markers_changed)

View File

@ -71,6 +71,8 @@ TASEDITOR_CONFIG::TASEDITOR_CONFIG()
findnote_search_up = false; findnote_search_up = false;
enable_auto_function = true; enable_auto_function = true;
deselect_on_doubleclick = false; deselect_on_doubleclick = false;
doubleclick_affects_playback = true;
draw_input = true;
silent_autosave = true; silent_autosave = true;
tooltips = true; tooltips = true;
current_pattern = 0; current_pattern = 0;

View File

@ -69,6 +69,8 @@ public:
bool findnote_search_up; bool findnote_search_up;
bool enable_auto_function; bool enable_auto_function;
bool deselect_on_doubleclick; bool deselect_on_doubleclick;
bool doubleclick_affects_playback;
bool draw_input;
bool silent_autosave; bool silent_autosave;
bool tooltips; bool tooltips;
int current_pattern; int current_pattern;

View File

@ -60,7 +60,7 @@ void TASEDITOR_PROJECT::reset()
void TASEDITOR_PROJECT::update() void TASEDITOR_PROJECT::update()
{ {
// if it's time to autosave - pop Save As dialog // if it's time to autosave - pop Save As dialog
if (changed && taseditor_config.autosave_period && clock() >= next_save_shedule) if (changed && taseditor_config.autosave_period && clock() >= next_save_shedule && piano_roll.drag_mode == DRAG_MODE_NONE)
{ {
if (taseditor_config.silent_autosave) if (taseditor_config.silent_autosave)
SaveProject(); SaveProject();
@ -123,6 +123,8 @@ bool TASEDITOR_PROJECT::save(const char* different_name, bool save_binary, bool
ofs = FCEUD_UTF8_fstream(GetProjectFile().c_str(), "wb"); ofs = FCEUD_UTF8_fstream(GetProjectFile().c_str(), "wb");
if (ofs) if (ofs)
{ {
// change cursor to hourglass
SetCursor(LoadCursor(0, IDC_WAIT));
currMovieData.loadFrameCount = currMovieData.records.size(); currMovieData.loadFrameCount = currMovieData.records.size();
currMovieData.emuVersion = FCEU_VERSION_NUMERIC; currMovieData.emuVersion = FCEU_VERSION_NUMERIC;
currMovieData.dump(ofs, save_binary); currMovieData.dump(ofs, save_binary);
@ -146,6 +148,8 @@ bool TASEDITOR_PROJECT::save(const char* different_name, bool save_binary, bool
// also reset autosave period if we saved the project to its current filename // also reset autosave period if we saved the project to its current filename
if (!different_name) if (!different_name)
this->reset(); this->reset();
// restore cursor
piano_roll.must_check_item_under_mouse = true;
return true; return true;
} else } else
{ {
@ -162,6 +166,8 @@ bool TASEDITOR_PROJECT::load(char* fullname)
return false; return false;
} }
// change cursor to hourglass
SetCursor(LoadCursor(0, IDC_WAIT));
MovieData tempMovieData = MovieData(); MovieData tempMovieData = MovieData();
extern bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader); extern bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader);
if (LoadFM2(tempMovieData, &ifs, ifs.size(), false)) if (LoadFM2(tempMovieData, &ifs, ifs.size(), false))
@ -227,6 +233,8 @@ bool TASEDITOR_PROJECT::load(char* fullname)
popup_display.reset(); popup_display.reset();
reset(); reset();
RenameProject(fullname); RenameProject(fullname);
// restore cursor
piano_roll.must_check_item_under_mouse = true;
return true; return true;
} }

View File

@ -12,6 +12,7 @@ Window - User Interface
* implements all operations with TAS Editor window: creating, redrawing, resizing, moving, tooltips, clicks * implements all operations with TAS Editor window: creating, redrawing, resizing, moving, tooltips, clicks
* processes OS messages and sends signals from user to TAS Editor modules (also implements some minor commands on-site, like Greenzone capacity dialog and such) * processes OS messages and sends signals from user to TAS Editor modules (also implements some minor commands on-site, like Greenzone capacity dialog and such)
* regularly checks if Shift or Ctrl key is held and sets keyboard focus to Piano Roll
* switches off/on emulator's keyboard input when the window loses/gains focus * switches off/on emulator's keyboard input when the window loses/gains focus
* on demand: updates the window caption * on demand: updates the window caption
* updates all checkboxes and menu items when some settings change * updates all checkboxes and menu items when some settings change
@ -449,6 +450,8 @@ void TASEDITOR_WINDOW::UpdateCheckedItems()
CheckMenuItem(hmenu, ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE, taseditor_config.superimpose_affects_paste?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_SUPERIMPOSE_AFFECTS_PASTE, taseditor_config.superimpose_affects_paste?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_COLUMNSETPATTERNSKIPSLAG, taseditor_config.pattern_skips_lag?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_COLUMNSETPATTERNSKIPSLAG, taseditor_config.pattern_skips_lag?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_DESELECTONDOUBLECLICK, taseditor_config.deselect_on_doubleclick?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_DESELECTONDOUBLECLICK, taseditor_config.deselect_on_doubleclick?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_DOUBLECLICKONFRAME, taseditor_config.doubleclick_affects_playback?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_DRAWINPUTBYDRAGGING, taseditor_config.draw_input?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_SILENTAUTOSAVE, taseditor_config.silent_autosave?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_SILENTAUTOSAVE, taseditor_config.silent_autosave?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_CONFIG_MUTETURBO, muteTurbo?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_CONFIG_MUTETURBO, muteTurbo?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, ID_HELP_TOOLTIPS, taseditor_config.tooltips?MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hmenu, ID_HELP_TOOLTIPS, taseditor_config.tooltips?MF_CHECKED : MF_UNCHECKED);
@ -694,6 +697,9 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
case LVN_ODSTATECHANGED: case LVN_ODSTATECHANGED:
selection.ItemRangeChanged((LPNMLVODSTATECHANGE) lParam); selection.ItemRangeChanged((LPNMLVODSTATECHANGE) lParam);
break; break;
case LVN_ENDSCROLL:
piano_roll.must_check_item_under_mouse = true;
break;
} }
break; break;
case IDC_BOOKMARKSLIST: case IDC_BOOKMARKSLIST:
@ -1064,6 +1070,14 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
taseditor_config.deselect_on_doubleclick ^= 1; taseditor_config.deselect_on_doubleclick ^= 1;
taseditor_window.UpdateCheckedItems(); taseditor_window.UpdateCheckedItems();
break; break;
case ID_CONFIG_DOUBLECLICKONFRAME:
taseditor_config.doubleclick_affects_playback ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_DRAWINPUTBYDRAGGING:
taseditor_config.draw_input ^= 1;
taseditor_window.UpdateCheckedItems();
break;
case ID_CONFIG_SILENTAUTOSAVE: case ID_CONFIG_SILENTAUTOSAVE:
taseditor_config.silent_autosave ^= 1; taseditor_config.silent_autosave ^= 1;
taseditor_window.UpdateCheckedItems(); taseditor_window.UpdateCheckedItems();
@ -1304,6 +1318,26 @@ BOOL CALLBACK WndprocTasEditor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
} }
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
{
// if user clicked on a narrow space to the left of Piano Roll
// consider this as a "misclick" on Piano Roll's first column
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
RECT wrect;
GetWindowRect(piano_roll.hwndList, &wrect);
if (x > 0
&& x <= window_items[PIANOROLL_IN_WINDOWITEMS].x
&& y > window_items[PIANOROLL_IN_WINDOWITEMS].y
&& y < window_items[PIANOROLL_IN_WINDOWITEMS].y + (wrect.bottom - wrect.top))
{
piano_roll.DragPlaybackCursor();
if (piano_roll.drag_mode == DRAG_MODE_NONE)
piano_roll.drag_mode = DRAG_MODE_PLAYBACK;
}
if (GetFocus() != hWnd)
SetFocus(hWnd);
break;
}
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
{ {

View File

@ -1,6 +1,9 @@
// Specification file for TASEDITOR_WINDOW class // Specification file for TASEDITOR_WINDOW class
#define TASEDITOR_WINDOW_TOTAL_ITEMS 43 #define TASEDITOR_WINDOW_TOTAL_ITEMS 43
#define PIANOROLL_IN_WINDOWITEMS 2
#define HISTORYLIST_IN_WINDOWITEMS 18
#define TOOLTIP_TEXT_MAX_LEN 80 #define TOOLTIP_TEXT_MAX_LEN 80
#define TOOLTIPS_AUTOPOP_TIMEOUT 30000 #define TOOLTIPS_AUTOPOP_TIMEOUT 30000