7580 lines
216 KiB
C++
7580 lines
216 KiB
C++
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2021 mjbudd77
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
// TasEditorWindow.cpp
|
|
//
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <string>
|
|
#include <zlib.h>
|
|
|
|
#include <QDir>
|
|
#include <QDrag>
|
|
#include <QString>
|
|
#include <QPainter>
|
|
#include <QSettings>
|
|
#include <QTextEdit>
|
|
#include <QHeaderView>
|
|
#include <QMessageBox>
|
|
#include <QFontMetrics>
|
|
#include <QFileDialog>
|
|
#include <QFontDialog>
|
|
#include <QInputDialog>
|
|
#include <QStandardPaths>
|
|
#include <QActionGroup>
|
|
#include <QApplication>
|
|
#include <QGuiApplication>
|
|
#include <QDesktopServices>
|
|
|
|
#include "fceu.h"
|
|
#include "movie.h"
|
|
#include "driver.h"
|
|
|
|
#include "common/vidblit.h"
|
|
#include "Qt/config.h"
|
|
#include "Qt/keyscan.h"
|
|
#include "Qt/throttle.h"
|
|
#include "Qt/fceuWrapper.h"
|
|
#include "Qt/ColorMenu.h"
|
|
#include "Qt/ConsoleWindow.h"
|
|
#include "Qt/ConsoleUtilities.h"
|
|
#include "Qt/TasEditor/TasColors.h"
|
|
#include "Qt/TasEditor/TasEditorWindow.h"
|
|
|
|
TasEditorWindow *tasWin = NULL;
|
|
TASEDITOR_PROJECT *project = NULL;
|
|
TASEDITOR_CONFIG *taseditorConfig = NULL;
|
|
TASEDITOR_LUA *taseditor_lua = NULL;
|
|
MARKERS_MANAGER *markersManager = NULL;
|
|
SELECTION *selection = NULL;
|
|
GREENZONE *greenzone = NULL;
|
|
BOOKMARKS *bookmarks = NULL;
|
|
BRANCHES *branches = NULL;
|
|
PLAYBACK *playback = NULL;
|
|
RECORDER *recorder = NULL;
|
|
HISTORY *history = NULL;
|
|
SPLICER *splicer = NULL;
|
|
|
|
// Piano Roll Definitions
|
|
enum DRAG_MODES
|
|
{
|
|
DRAG_MODE_NONE,
|
|
DRAG_MODE_OBSERVE,
|
|
DRAG_MODE_PLAYBACK,
|
|
DRAG_MODE_MARKER,
|
|
DRAG_MODE_SET,
|
|
DRAG_MODE_UNSET,
|
|
DRAG_MODE_SELECTION,
|
|
DRAG_MODE_DESELECTION,
|
|
};
|
|
#define BOOKMARKS_WITH_NO_ARROW 0x00010000
|
|
#define BOOKMARKS_WITH_BLUE_ARROW 0x00020000
|
|
#define BOOKMARKS_WITH_GREEN_ARROW 0x00040000
|
|
#define BLUE_ARROW_IMAGE_ID 0x00080000
|
|
#define GREEN_ARROW_IMAGE_ID 0x00100000
|
|
#define GREEN_BLUE_ARROW_IMAGE_ID (BLUE_ARROW_IMAGE_ID | GREEN_ARROW_IMAGE_ID)
|
|
|
|
#define MARKER_DRAG_COUNTDOWN_MAX 14
|
|
#define PIANO_ROLL_ID_LEN 11
|
|
#define PLAYBACK_WHEEL_BOOST 2
|
|
|
|
// resources
|
|
static char pianoRollSaveID[PIANO_ROLL_ID_LEN] = "PIANO_ROLL";
|
|
static char pianoRollSkipSaveID[PIANO_ROLL_ID_LEN] = "PIANO_ROLX";
|
|
static TasFindNoteWindow *findWin = NULL;
|
|
static uint64_t tasEditorTimeStamp = 0;
|
|
|
|
//----------------------------------------------------------------------------
|
|
//---- Main TAS Editor Window
|
|
//----------------------------------------------------------------------------
|
|
bool tasWindowIsOpen(void)
|
|
{
|
|
return tasWin != NULL;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void tasWindowSetFocus(bool val)
|
|
{
|
|
if ( tasWin )
|
|
{
|
|
tasWin->activateWindow();
|
|
tasWin->raise();
|
|
}
|
|
}
|
|
// this getter contains formula to decide whether to record or replay movie
|
|
bool isTaseditorRecording(void)
|
|
{
|
|
if ( tasWin == NULL )
|
|
{
|
|
return false;
|
|
}
|
|
if (movie_readonly || playback->getPauseFrame() >= 0 || (taseditorConfig->oldControlSchemeForBranching && !recorder->stateWasLoadedInReadWriteMode))
|
|
{
|
|
return false; // replay
|
|
}
|
|
return true; // record
|
|
}
|
|
|
|
uint64_t getTasEditorTime(void)
|
|
{
|
|
return tasEditorTimeStamp;
|
|
}
|
|
|
|
void recordInputByTaseditor(void)
|
|
{
|
|
if ( recorder )
|
|
{
|
|
recorder->recordInput();
|
|
}
|
|
return;
|
|
}
|
|
|
|
void applyMovieInputConfig(void)
|
|
{
|
|
// update FCEUX input config
|
|
FCEUD_SetInput(currMovieData.fourscore, currMovieData.microphone, (ESI)currMovieData.ports[0], (ESI)currMovieData.ports[1], (ESIFC)currMovieData.ports[2]);
|
|
// update PAL flag
|
|
pal_emulation = currMovieData.palFlag;
|
|
if (pal_emulation)
|
|
{
|
|
dendy = 0;
|
|
}
|
|
FCEUI_SetVidSystem(pal_emulation);
|
|
RefreshThrottleFPS();
|
|
//PushCurrentVideoSettings();
|
|
// update PPU type
|
|
newppu = currMovieData.PPUflag;
|
|
//SetMainWindowText();
|
|
// return focus to TAS Editor window
|
|
//SetFocus(taseditorWindow.hwndTASEditor);
|
|
RAMInitOption = currMovieData.RAMInitOption;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
TasEditorWindow::TasEditorWindow(QWidget *parent)
|
|
: QDialog( parent, Qt::Window ), bookmarks(this), branches(this)
|
|
{
|
|
QSettings settings;
|
|
QVBoxLayout *mainLayout;
|
|
//QHBoxLayout *hbox;
|
|
QMenuBar *menuBar;
|
|
|
|
tasWin = this;
|
|
::project = &this->project;
|
|
::taseditorConfig = &this->taseditorConfig;
|
|
::taseditor_lua = &this->taseditor_lua;
|
|
::markersManager = &this->markersManager;
|
|
::selection = &this->selection;
|
|
::greenzone = &this->greenzone;
|
|
::bookmarks = &this->bookmarks;
|
|
::playback = &this->playback;
|
|
::recorder = &this->recorder;
|
|
::history = &this->history;
|
|
::branches = &this->branches;
|
|
::splicer = &this->splicer;
|
|
|
|
this->taseditorConfig.load();
|
|
|
|
clipboard = QGuiApplication::clipboard();
|
|
|
|
setWindowTitle("TAS Editor");
|
|
//setWindowIcon( QIcon(":icons/taseditor-icon32.png") );
|
|
|
|
resize(512, 512);
|
|
|
|
mainLayout = new QVBoxLayout();
|
|
mainHBox = new TasEditorSplitter();
|
|
|
|
initPatterns();
|
|
buildPianoRollDisplay();
|
|
buildSideControlPanel();
|
|
|
|
mainHBox->addWidget( pianoRollContainerWidget );
|
|
mainHBox->addWidget( controlPanelContainerWidget );
|
|
mainLayout->addWidget(mainHBox);
|
|
|
|
mainHBox->setStretchFactor( 0, 5 );
|
|
mainHBox->setStretchFactor( 1, 1 );
|
|
|
|
menuBar = buildMenuBar();
|
|
|
|
setLayout(mainLayout);
|
|
mainLayout->setMenuBar( menuBar );
|
|
pianoRoll->setFocus();
|
|
|
|
for (int i=0; i<HK_MAX; i++)
|
|
{
|
|
hotkeyShortcut[i] = nullptr;
|
|
}
|
|
initHotKeys();
|
|
initModules();
|
|
|
|
updateCheckedItems();
|
|
updateToolTips();
|
|
|
|
// Restore Window Geometry
|
|
restoreGeometry(settings.value("tasEditor/geometry").toByteArray());
|
|
|
|
// Restore Horizontal Panel State
|
|
mainHBox->restoreState( settings.value("tasEditor/hPanelState").toByteArray() );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
TasEditorWindow::~TasEditorWindow(void)
|
|
{
|
|
QSettings settings;
|
|
|
|
printf("Destroy Tas Editor Window\n");
|
|
|
|
FCEU_WRAPPER_LOCK();
|
|
//if (!askToSaveProject()) return false;
|
|
|
|
// destroy window
|
|
taseditorConfig.save();
|
|
//taseditorWindow.exit();
|
|
//disableGeneralKeyboardInput();
|
|
// release memory
|
|
//editor.free();
|
|
//pianoRoll.free();
|
|
markersManager.free();
|
|
greenzone.free();
|
|
bookmarks.free();
|
|
branches.free();
|
|
//popupDisplay.free();
|
|
history.free();
|
|
playback.stopSeeking();
|
|
selection.free();
|
|
|
|
// switch off TAS Editor mode
|
|
movieMode = MOVIEMODE_INACTIVE;
|
|
FCEU_DispMessage("TAS Editor disengaged", 0);
|
|
FCEUMOV_CreateCleanMovie();
|
|
|
|
if ( tasWin == this )
|
|
{
|
|
tasWin = NULL;
|
|
}
|
|
|
|
::project = NULL;
|
|
::taseditorConfig = NULL;
|
|
::taseditor_lua = NULL;
|
|
::markersManager = NULL;
|
|
::selection = NULL;
|
|
::greenzone = NULL;
|
|
::bookmarks = NULL;
|
|
::playback = NULL;
|
|
::recorder = NULL;
|
|
::history = NULL;
|
|
::branches = NULL;
|
|
::splicer = NULL;
|
|
|
|
clearProjectList();
|
|
|
|
FCEU_WRAPPER_UNLOCK();
|
|
|
|
// Save Horizontal Panel State
|
|
settings.setValue("tasEditor/hPanelState", mainHBox->saveState());
|
|
|
|
// Save Window Geometry
|
|
settings.setValue("tasEditor/geometry", saveGeometry());
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
printf("Tas Editor Close Window Event\n");
|
|
|
|
if (!askToSaveProject())
|
|
{
|
|
event->ignore();
|
|
return;
|
|
}
|
|
project.reset();
|
|
|
|
done(0);
|
|
deleteLater();
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::closeWindow(void)
|
|
{
|
|
if (!askToSaveProject())
|
|
{
|
|
return;
|
|
}
|
|
project.reset();
|
|
|
|
printf("Tas Editor Close Window\n");
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int TasEditorWindow::requestWindowClose(void)
|
|
{
|
|
askToSaveProject();
|
|
|
|
project.reset();
|
|
|
|
printf("Tas Editor Close Window\n");
|
|
done(0);
|
|
deleteLater();
|
|
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
QMenuBar *TasEditorWindow::buildMenuBar(void)
|
|
{
|
|
QMenu *fileMenu, *editMenu, *viewMenu,
|
|
*confMenu, *luaMenu, *helpMenu,
|
|
*patternMenu;
|
|
QActionGroup *actGroup;
|
|
QAction *act;
|
|
ColorMenuItem *colorAct;
|
|
int useNativeMenuBar=0;
|
|
|
|
QMenuBar *menuBar = new QMenuBar(this);
|
|
|
|
// This is needed for menu bar to show up on MacOS
|
|
g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar );
|
|
|
|
menuBar->setNativeMenuBar( useNativeMenuBar ? true : false );
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Menu Start
|
|
//-----------------------------------------------------------------------
|
|
// File
|
|
fileMenu = menuBar->addMenu(tr("&File"));
|
|
|
|
// File -> New
|
|
act = new QAction(tr("&New"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Open New Project"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(createNewProject(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// File -> Open
|
|
act = new QAction(tr("&Open"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+O")));
|
|
act->setStatusTip(tr("Open Project"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_BrowserStop ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(openProject(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// File -> Save
|
|
act = new QAction(tr("&Save"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+S")));
|
|
act->setStatusTip(tr("Save Project"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_BrowserStop ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(saveProjectCb(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// File -> Save As
|
|
act = new QAction(tr("Save &As"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Shift+S")));
|
|
act->setStatusTip(tr("Save Project As"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_BrowserStop ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(saveProjectAsCb(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// File -> Save Compact
|
|
act = new QAction(tr("Save &Compact"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+Shift+S")));
|
|
act->setStatusTip(tr("Save Compact"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_BrowserStop ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(saveProjectCompactCb(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// File -> Recent
|
|
recentProjectMenu = fileMenu->addMenu( tr("&Recent") );
|
|
|
|
buildRecentProjectMenu();
|
|
recentProjectMenuReset = false;
|
|
|
|
fileMenu->addSeparator();
|
|
|
|
// File -> Import Input
|
|
act = new QAction(tr("&Import Input"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+Shift+S")));
|
|
act->setStatusTip(tr("Import Input"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_BrowserStop ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(importMovieFile(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// File -> Export to fm2
|
|
act = new QAction(tr("&Export to fm2"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+Shift+S")));
|
|
act->setStatusTip(tr("Export to fm2"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_BrowserStop ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(exportMovieFile(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
fileMenu->addSeparator();
|
|
|
|
// File -> Quit
|
|
act = new QAction(tr("&Quit Window"), this);
|
|
act->setShortcut(QKeySequence(tr("Alt+F4")));
|
|
act->setStatusTip(tr("Close Window"));
|
|
act->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
|
|
connect(act, SIGNAL(triggered()), this, SLOT(closeWindow(void)) );
|
|
|
|
fileMenu->addAction(act);
|
|
|
|
// Edit
|
|
editMenu = menuBar->addMenu(tr("&Edit"));
|
|
|
|
// Edit -> Undo
|
|
act = new QAction(tr("&Undo"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Z")));
|
|
act->setStatusTip(tr("Undo Changes"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editUndoCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Redo
|
|
act = new QAction(tr("&Redo"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Y")));
|
|
act->setStatusTip(tr("Redo Changes"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editRedoCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Selection Undo
|
|
act = new QAction(tr("Selection &Undo"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
|
act->setStatusTip(tr("Undo Selection"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editUndoSelCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Selection Redo
|
|
act = new QAction(tr("Selection &Redo"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+W")));
|
|
act->setStatusTip(tr("Redo Selection"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editRedoSelCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
editMenu->addSeparator();
|
|
|
|
// Edit -> Deselect
|
|
act = new QAction(tr("Deselect"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+W")));
|
|
act->setStatusTip(tr("Deselect"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editDeselectAll(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Select All
|
|
act = new QAction(tr("Select All"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+W")));
|
|
act->setStatusTip(tr("Select All"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editSelectAll(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Select Between Markers
|
|
act = new QAction(tr("Select Between Markers"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+A")));
|
|
act->setStatusTip(tr("Select Between Markers"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editSelBtwMkrs(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Reselect Clipboard
|
|
act = new QAction(tr("Reselect Clipboard"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+B")));
|
|
act->setStatusTip(tr("Reselect Clipboard"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editReselectClipboard(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
editMenu->addSeparator();
|
|
|
|
// Edit -> Copy
|
|
act = new QAction(tr("Copy"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+C")));
|
|
act->setStatusTip(tr("Copy"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editCopyCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Paste
|
|
act = new QAction(tr("Paste"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+V")));
|
|
act->setStatusTip(tr("Paste"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editPasteCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Paste Insert
|
|
act = new QAction(tr("Paste Insert"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Shift+V")));
|
|
act->setStatusTip(tr("Paste Insert"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editPasteInsertCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Cut
|
|
act = new QAction(tr("Cut"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+X")));
|
|
act->setStatusTip(tr("Cut"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editCutCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
editMenu->addSeparator();
|
|
|
|
// Edit -> Clear
|
|
act = new QAction(tr("Clear"), this);
|
|
act->setShortcut(QKeySequence(tr("Del")));
|
|
act->setStatusTip(tr("Clear"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editClearCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Delete
|
|
act = new QAction(tr("Delete"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Del")));
|
|
act->setStatusTip(tr("Delete"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editDeleteCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Clone
|
|
act = new QAction(tr("Clone"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Ins")));
|
|
act->setStatusTip(tr("Clone"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editCloneCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Insert
|
|
act = new QAction(tr("Insert"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Shift+Ins")));
|
|
act->setStatusTip(tr("Insert"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editInsertCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// Edit -> Insert # of Frames
|
|
act = new QAction(tr("Insert # of Frames"), this);
|
|
act->setShortcut(QKeySequence(tr("Ins")));
|
|
act->setStatusTip(tr("Insert # of Frames"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editInsertNumFramesCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
editMenu->addSeparator();
|
|
|
|
// Edit -> Truncate Movie
|
|
act = new QAction(tr("Truncate Movie"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+Ins")));
|
|
act->setStatusTip(tr("Truncate Movie"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(editTruncateMovieCB(void)) );
|
|
|
|
editMenu->addAction(act);
|
|
|
|
// View
|
|
viewMenu = menuBar->addMenu(tr("&View"));
|
|
|
|
// View -> Find Note Window
|
|
act = new QAction(tr("Find Note Window"), this);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Find Note Window"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(openFindNoteWindow(void)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
viewMenu->addSeparator();
|
|
|
|
// View -> Display Branch Screenshots
|
|
dpyBrnchScrnAct = act = new QAction(tr("Display Branch Screenshots"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Display Branch Screenshots"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(dpyBrnchScrnChanged(bool)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
// View -> Display Branch Screenshots
|
|
dpyBrnchDescAct = act = new QAction(tr("Display Branch Descriptions"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Display Branch Descriptions"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(dpyBrnchDescChanged(bool)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
// View -> Enable Hot Changes
|
|
enaHotChgAct = act = new QAction(tr("Enable Hot Changes"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Enable Hot Changes"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(enaHotChgChanged(bool)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
viewMenu->addSeparator();
|
|
|
|
// View -> Follow Undo Content
|
|
followUndoAct = act = new QAction(tr("Follow Undo Content"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Follow Undo Content"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(followUndoActChanged(bool)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
// View -> Follow Marker Note Content
|
|
followMkrAct = act = new QAction(tr("Follow Marker Note Content"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Follow Marker Note Content"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(followMkrActChanged(bool)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
viewMenu->addSeparator();
|
|
|
|
// View -> Piano Roll Font
|
|
act = new QAction(tr("Piano Roll Font..."), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Select Piano Roll Font"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(void)), this, SLOT(changePianoRollFontCB(void)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
// View -> Bookmarks Font
|
|
act = new QAction(tr("Bookmarks View Font..."), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Select Bookmarks View Font"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(void)), this, SLOT(changeBookmarksFontCB(void)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
// View -> Branches Font
|
|
act = new QAction(tr("Branches View Font..."), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+F")));
|
|
act->setStatusTip(tr("Select Branches View Font"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(void)), this, SLOT(changeBranchesFontCB(void)) );
|
|
|
|
viewMenu->addAction(act);
|
|
|
|
viewMenu->addSeparator();
|
|
|
|
// View -> Piano Roll Grid Color
|
|
colorAct = new ColorMenuItem(tr("Piano Roll Grid Color..."), "SDL.TasPianoRollGridColor", this);
|
|
colorAct->setStatusTip(tr("Select Piano Roll Grid Color"));
|
|
|
|
colorAct->connectColor( &pianoRoll->gridColor );
|
|
|
|
viewMenu->addAction(colorAct);
|
|
|
|
// Config
|
|
confMenu = menuBar->addMenu(tr("&Config"));
|
|
|
|
// Config -> Project File Saving Options
|
|
act = new QAction(tr("Project File Saving Options"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Project File Saving Options"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(openProjectSaveOptions(void)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Set Max Undo Levels
|
|
act = new QAction(tr("Set Max Undo Levels"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Set Max Undo History"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(setMaxUndoCapacity(void)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Set Greenzone Capacity
|
|
act = new QAction(tr("Set Greenzone Capacity"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Set Greenzone Capacity"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(setGreenzoneCapacity(void)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
confMenu->addSeparator();
|
|
|
|
// Config -> Enable Greenzoneing
|
|
enaGrnznAct = act = new QAction(tr("Enable Greenzoning"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Enable Greenzoning"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(enaGrnznActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Autofire Pattern skips Lag
|
|
afPtrnSkipLagAct = act = new QAction(tr("Autofire Pattern skips Lag"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Autofire Pattern skips Lag"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(afPtrnSkipLagActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Auto Adjust Input According to Lag
|
|
adjInputLagAct = act = new QAction(tr("Auto Adjust Input According to Lag"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Auto Adjust Input According to Lag"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(adjInputLagActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
confMenu->addSeparator();
|
|
|
|
// Config -> Draw Input by Dragging
|
|
drawInputDragAct = act = new QAction(tr("Draw Input by Dragging"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Draw Input by Dragging"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(drawInputDragActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Combine Consecutive Recordings/Draws
|
|
cmbRecDrawAct = act = new QAction(tr("Combine Consecutive Recordings/Draws"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Combine Consecutive Recordings/Draws"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(cmbRecDrawActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Use 1P Keys for all Single Recordings
|
|
use1PforRecAct = act = new QAction(tr("Use 1P Keys for all Single Recordings"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Use 1P Keys for all Single Recordings"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(use1PforRecActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Use Input Keys for Column Set
|
|
useInputColSetAct = act = new QAction(tr("Use Input Keys for Column Set"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Use Input Keys for Column Set"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(useInputColSetActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
confMenu->addSeparator();
|
|
|
|
// Config -> Bind Markers to Input
|
|
bindMkrInputAct = act = new QAction(tr("Bind Markers to Input"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Bind Markers to Input"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(bindMkrInputActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Empty New Marker Notes
|
|
emptyNewMkrNotesAct = act = new QAction(tr("Empty New Marker Notes"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Empty New Marker Notes"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(emptyNewMkrNotesActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
confMenu->addSeparator();
|
|
|
|
// Config -> Old Control Scheme for Branching
|
|
oldCtlBrnhSchemeAct = act = new QAction(tr("Old Control Scheme for Branching"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Old Control Scheme for Branching"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(oldCtlBrnhSchemeActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> Branches Restore Entire Movie
|
|
brnchRestoreMovieAct = act = new QAction(tr("Branches Restore Entire Movie"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Branches Restore Entire Movie"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(brnchRestoreMovieActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Config -> HUD in Branch Screenshots
|
|
hudInScrnBranchAct = act = new QAction(tr("HUD in Branch Screenshots"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("HUD in Branch Screenshots"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(hudInScrnBranchActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
confMenu->addSeparator();
|
|
|
|
// Config -> Autopause at End of Movie
|
|
pauseAtEndAct = act = new QAction(tr("Autopause at End of Movie"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Autopause at End of Movie"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(pauseAtEndActChanged(bool)) );
|
|
|
|
confMenu->addAction(act);
|
|
|
|
// Lua
|
|
luaMenu = menuBar->addMenu(tr("&Lua"));
|
|
|
|
// Lua -> Run Function
|
|
act = new QAction(tr("Run Function"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Run Function"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(manLuaRun(void)) );
|
|
|
|
luaMenu->addAction(act);
|
|
|
|
luaMenu->addSeparator();
|
|
|
|
// Lua -> Auto Function
|
|
autoLuaAct = act = new QAction(tr("Auto Function"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Auto Function"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(autoLuaRunChanged(bool)) );
|
|
|
|
luaMenu->addAction(act);
|
|
|
|
// Pattern
|
|
patternMenu = menuBar->addMenu(tr("&Pattern"));
|
|
|
|
actGroup = new QActionGroup(this);
|
|
|
|
for (size_t i=0; i<patternsNames.size(); i++)
|
|
{
|
|
// Pattern -> Names
|
|
act = new QAction(tr(patternsNames[i].c_str()), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr(patternsNames[i].c_str()));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, &QAction::triggered, [this, i] { setCurrentPattern(i); } );
|
|
|
|
actGroup->addAction(act);
|
|
patternMenu->addAction(act);
|
|
|
|
act->setChecked( static_cast<size_t>(taseditorConfig.currentPattern) == i );
|
|
}
|
|
|
|
// Help
|
|
helpMenu = menuBar->addMenu(tr("&Help"));
|
|
|
|
// Help -> Open TAS Editor Manual
|
|
act = new QAction(tr("Open TAS Editor Manual"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Open TAS Editor Manual"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(openOnlineDocs(void)) );
|
|
|
|
helpMenu->addAction(act);
|
|
|
|
// Help -> Enable Tool Tips
|
|
showToolTipsAct = act = new QAction(tr("Enable Tool Tips"), this);
|
|
act->setCheckable(true);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("Enable Tool Tips"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered(bool)), this, SLOT(showToolTipsActChanged(bool)) );
|
|
|
|
helpMenu->addAction(act);
|
|
|
|
helpMenu->addSeparator();
|
|
|
|
// Help -> About
|
|
act = new QAction(tr("About"), this);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl+N")));
|
|
act->setStatusTip(tr("About"));
|
|
//act->setIcon( style()->standardIcon( QStyle::SP_FileDialogStart ) );
|
|
connect(act, SIGNAL(triggered()), this, SLOT(openAboutWindow(void)) );
|
|
|
|
helpMenu->addAction(act);
|
|
|
|
return menuBar;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::buildPianoRollDisplay(void)
|
|
{
|
|
QVBoxLayout *vbox;
|
|
QHBoxLayout *hbox;
|
|
QGridLayout *grid;
|
|
|
|
pianoRollFrame = new QFrame();
|
|
grid = new QGridLayout();
|
|
pianoRoll = new QPianoRoll(this);
|
|
pianoRollVBar = new PianoRollScrollBar( this );
|
|
pianoRollHBar = new QScrollBar( Qt::Horizontal, this );
|
|
upperMarkerLabel = new QPushButton( tr("Marker 0") );
|
|
lowerMarkerLabel = new QPushButton( tr("Marker 0") );
|
|
upperMarkerNote = new UpperMarkerNoteEdit();
|
|
lowerMarkerNote = new LowerMarkerNoteEdit();
|
|
|
|
//upperMarkerLabel->setFlat(true);
|
|
//lowerMarkerLabel->setFlat(true);
|
|
|
|
pianoRollFrame->setLineWidth(2);
|
|
pianoRollFrame->setMidLineWidth(1);
|
|
//pianoRollFrame->setFrameShape( QFrame::StyledPanel );
|
|
pianoRollFrame->setFrameShape( QFrame::Box );
|
|
|
|
pianoRollVBar->setInvertedControls(false);
|
|
pianoRollVBar->setInvertedAppearance(false);
|
|
pianoRoll->setScrollBars( pianoRollHBar, pianoRollVBar );
|
|
connect( pianoRollHBar, SIGNAL(valueChanged(int)), pianoRoll, SLOT(hbarChanged(int)) );
|
|
connect( pianoRollVBar, SIGNAL(valueChanged(int)), pianoRoll, SLOT(vbarChanged(int)) );
|
|
//connect( pianoRollVBar, SIGNAL(actionTriggered(int)), pianoRoll, SLOT(vbarActionTriggered(int)) );
|
|
|
|
grid->addWidget( pianoRoll , 0, 0 );
|
|
grid->addWidget( pianoRollVBar, 0, 1 );
|
|
grid->addWidget( pianoRollHBar, 1, 0 );
|
|
|
|
vbox = new QVBoxLayout();
|
|
|
|
pianoRollHBar->setMinimum(0);
|
|
pianoRollHBar->setMaximum(100);
|
|
pianoRollVBar->setMinimum(0);
|
|
pianoRollVBar->setMaximum(100);
|
|
|
|
hbox = new QHBoxLayout();
|
|
hbox->addWidget( upperMarkerLabel, 1 );
|
|
hbox->addWidget( upperMarkerNote, 10 );
|
|
|
|
vbox->addLayout( hbox, 1 );
|
|
vbox->addWidget( pianoRollFrame, 100 );
|
|
//vbox->addLayout( grid, 100 );
|
|
pianoRollFrame->setLayout( grid );
|
|
|
|
hbox = new QHBoxLayout();
|
|
hbox->addWidget( lowerMarkerLabel, 1 );
|
|
hbox->addWidget( lowerMarkerNote, 10 );
|
|
|
|
vbox->addLayout( hbox, 1 );
|
|
|
|
pianoRollContainerWidget = new QWidget();
|
|
pianoRollContainerWidget->setLayout( vbox );
|
|
|
|
connect( upperMarkerLabel, SIGNAL(clicked(void)), this, SLOT(upperMarkerLabelClicked(void)) );
|
|
connect( lowerMarkerLabel, SIGNAL(clicked(void)), this, SLOT(lowerMarkerLabelClicked(void)) );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::initPatterns(void)
|
|
{
|
|
if (patterns.size() == 0)
|
|
{
|
|
FCEU_printf("Will be using default set of patterns...\n");
|
|
patterns.resize(4);
|
|
patternsNames.resize(4);
|
|
// Default Pattern 0: Alternating (1010...)
|
|
patternsNames[0] = "Alternating (1010...)";
|
|
patterns[0].resize(2);
|
|
patterns[0][0] = 1;
|
|
patterns[0][1] = 0;
|
|
// Default Pattern 1: Alternating at 30FPS (11001100...)
|
|
patternsNames[1] = "Alternating at 30FPS (11001100...)";
|
|
patterns[1].resize(4);
|
|
patterns[1][0] = 1;
|
|
patterns[1][1] = 1;
|
|
patterns[1][2] = 0;
|
|
patterns[1][3] = 0;
|
|
// Default Pattern 2: One Quarter (10001000...)
|
|
patternsNames[2] = "One Quarter (10001000...)";
|
|
patterns[2].resize(4);
|
|
patterns[2][0] = 1;
|
|
patterns[2][1] = 0;
|
|
patterns[2][2] = 0;
|
|
patterns[2][3] = 0;
|
|
// Default Pattern 3: Tap'n'Hold (1011111111111111111111111111111111111...)
|
|
patternsNames[3] = "Tap'n'Hold (101111111...)";
|
|
patterns[3].resize(1000);
|
|
patterns[3][0] = 1;
|
|
patterns[3][1] = 0;
|
|
for (int i = 2; i < 1000; ++i)
|
|
{
|
|
patterns[3][i] = 1;
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::buildSideControlPanel(void)
|
|
{
|
|
QShortcut *shortcut;
|
|
QVBoxLayout *vbox;
|
|
QHBoxLayout *hbox;
|
|
QGridLayout *grid;
|
|
QScrollArea *scrollArea1, *scrollArea2;
|
|
QTreeWidgetItem *item;
|
|
|
|
ctlPanelMainVbox = new QVBoxLayout();
|
|
|
|
playbackGBox = new QGroupBox( tr("Playback") );
|
|
recorderGBox = new QGroupBox( tr("Recorder") );
|
|
splicerGBox = new QGroupBox( tr("Splicer") );
|
|
//luaGBox = new QGroupBox( tr("Lua") );
|
|
//historyGBox = new QGroupBox( tr("History") );
|
|
bbFrame = new QFrame();
|
|
|
|
bbFrame->setFrameShape( QFrame::StyledPanel );
|
|
|
|
rewindMkrBtn = new QPushButton();
|
|
rewindFrmBtn = new QPushButton();
|
|
playPauseBtn = new QPushButton();
|
|
advFrmBtn = new QPushButton();
|
|
advMkrBtn = new QPushButton();
|
|
|
|
rewindMkrBtn->setIcon( style()->standardIcon( QStyle::SP_MediaSkipBackward ) );
|
|
rewindFrmBtn->setIcon( style()->standardIcon( QStyle::SP_MediaSeekBackward ) );
|
|
playPauseBtn->setIcon( style()->standardIcon( QStyle::SP_MediaPause ) );
|
|
advFrmBtn->setIcon( style()->standardIcon( QStyle::SP_MediaSeekForward ) );
|
|
advMkrBtn->setIcon( style()->standardIcon( QStyle::SP_MediaSkipForward ) );
|
|
|
|
progBar = new QProgressBar();
|
|
progBar->setRange( 0, 1 );
|
|
|
|
followCursorCbox = new QCheckBox( tr("Follow Cursor") );
|
|
turboSeekCbox = new QCheckBox( tr("Turbo Seek") );
|
|
autoRestoreCbox = new QCheckBox( tr("Auto-Restore Last Position") );
|
|
|
|
recRecordingCbox = new QCheckBox( tr("Recording") );
|
|
recSuperImposeCbox = new QCheckBox( tr("Superimpose") );
|
|
recUsePatternCbox = new QCheckBox( tr("Use Pattern") );
|
|
recAllBtn = new QRadioButton( tr("All") );
|
|
rec1PBtn = new QRadioButton( tr("1P") );
|
|
rec2PBtn = new QRadioButton( tr("2P") );
|
|
rec3PBtn = new QRadioButton( tr("3P") );
|
|
rec4PBtn = new QRadioButton( tr("4P") );
|
|
|
|
selectionLbl = new QLabel( tr("Empty") );
|
|
clipboardLbl = new QLabel( tr("Empty") );
|
|
|
|
//runLuaBtn = new QPushButton( tr("Run Function") );
|
|
//autoLuaCBox = new QCheckBox( tr("Auto Function") );
|
|
//runLuaBtn->setEnabled(false);
|
|
//autoLuaCBox->setChecked(true);
|
|
|
|
histTree = new QTreeWidget();
|
|
|
|
histTree->setColumnCount(1);
|
|
histTree->setSelectionMode( QAbstractItemView::SingleSelection );
|
|
histTree->setAlternatingRowColors(true);
|
|
|
|
item = new QTreeWidgetItem();
|
|
item->setText(0, QString::fromStdString("Time / Description"));
|
|
|
|
histTree->setHeaderItem(item);
|
|
|
|
prevMkrBtn = new QPushButton();
|
|
nextMkrBtn = new QPushButton();
|
|
similarBtn = new QPushButton( tr("Similar") );
|
|
moreBtn = new QPushButton( tr("More") );
|
|
|
|
prevMkrBtn->setIcon( style()->standardIcon( QStyle::SP_MediaSkipBackward ) );
|
|
nextMkrBtn->setIcon( style()->standardIcon( QStyle::SP_MediaSkipForward ) );
|
|
|
|
vbox = new QVBoxLayout();
|
|
hbox = new QHBoxLayout();
|
|
vbox->addLayout( hbox );
|
|
hbox->addWidget( rewindMkrBtn );
|
|
hbox->addWidget( rewindFrmBtn );
|
|
hbox->addWidget( playPauseBtn );
|
|
hbox->addWidget( advFrmBtn );
|
|
hbox->addWidget( advMkrBtn );
|
|
vbox->addWidget( progBar );
|
|
|
|
hbox = new QHBoxLayout();
|
|
vbox->addLayout( hbox );
|
|
hbox->addWidget( followCursorCbox );
|
|
hbox->addWidget( turboSeekCbox );
|
|
|
|
vbox->addWidget( autoRestoreCbox );
|
|
|
|
playbackGBox->setLayout( vbox );
|
|
|
|
grid = new QGridLayout();
|
|
grid->addWidget( recRecordingCbox, 0, 0, 1, 2 );
|
|
grid->addWidget( recAllBtn , 0, 3, 1, 1 );
|
|
grid->addWidget( rec1PBtn , 1, 0, 1, 1 );
|
|
grid->addWidget( rec2PBtn , 1, 1, 1, 1 );
|
|
grid->addWidget( rec3PBtn , 1, 2, 1, 1 );
|
|
grid->addWidget( rec4PBtn , 1, 3, 1, 1 );
|
|
grid->addWidget( recSuperImposeCbox, 2, 0, 1, 2 );
|
|
grid->addWidget( recUsePatternCbox , 2, 2, 1, 2 );
|
|
recorderGBox->setLayout( grid );
|
|
|
|
grid = new QGridLayout();
|
|
grid->addWidget( new QLabel( tr("Selection:") ), 0, 0, 1, 1 );
|
|
grid->addWidget( new QLabel( tr("Clipboard:") ), 1, 0, 1, 1 );
|
|
grid->addWidget( selectionLbl, 0, 1, 1, 3 );
|
|
grid->addWidget( clipboardLbl, 1, 1, 1, 3 );
|
|
splicerGBox->setLayout( grid );
|
|
|
|
//hbox = new QHBoxLayout();
|
|
//hbox->addWidget( runLuaBtn );
|
|
//hbox->addWidget( autoLuaCBox );
|
|
//luaGBox->setLayout( hbox );
|
|
|
|
scrollArea1 = new QScrollArea();
|
|
scrollArea1->setWidgetResizable(false);
|
|
scrollArea1->setSizeAdjustPolicy( QAbstractScrollArea::AdjustToContents );
|
|
scrollArea1->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
|
|
scrollArea1->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
|
|
scrollArea1->setMinimumSize( QSize( 128, 128 ) );
|
|
scrollArea1->setWidget( &bookmarks );
|
|
|
|
scrollArea2 = new QScrollArea();
|
|
scrollArea2->setWidgetResizable(true);
|
|
scrollArea2->setSizeAdjustPolicy( QAbstractScrollArea::AdjustToContents );
|
|
scrollArea2->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
|
|
scrollArea2->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
|
|
scrollArea2->setMinimumSize( QSize( 128, 128 ) );
|
|
scrollArea2->setWidget( &branches );
|
|
|
|
bkmkBrnchStack = new QTabWidget();
|
|
bkmkBrnchStack->addTab( scrollArea1, tr("Bookmarks") );
|
|
bkmkBrnchStack->addTab( scrollArea2, tr("Branches") );
|
|
bkmkBrnchStack->addTab( histTree , tr("History") );
|
|
|
|
taseditorConfig.displayBranchesTree = 0;
|
|
|
|
vbox = new QVBoxLayout();
|
|
vbox->addWidget( bkmkBrnchStack );
|
|
bbFrame->setLayout( vbox );
|
|
|
|
//vbox = new QVBoxLayout();
|
|
//vbox->addWidget( histTree );
|
|
//historyGBox->setLayout( vbox );
|
|
|
|
ctlPanelMainVbox->addWidget( playbackGBox );
|
|
ctlPanelMainVbox->addWidget( recorderGBox );
|
|
ctlPanelMainVbox->addWidget( splicerGBox );
|
|
//ctlPanelMainVbox->addWidget( luaGBox );
|
|
ctlPanelMainVbox->addWidget( bbFrame );
|
|
//ctlPanelMainVbox->addWidget( historyGBox );
|
|
|
|
hbox = new QHBoxLayout();
|
|
hbox->addWidget( prevMkrBtn );
|
|
hbox->addWidget( similarBtn );
|
|
hbox->addWidget( moreBtn );
|
|
hbox->addWidget( nextMkrBtn );
|
|
ctlPanelMainVbox->addLayout( hbox );
|
|
|
|
controlPanelContainerWidget = new QWidget();
|
|
controlPanelContainerWidget->setLayout( ctlPanelMainVbox );
|
|
|
|
recRecordingCbox->setChecked( !movie_readonly );
|
|
connect( recRecordingCbox, SIGNAL(stateChanged(int)), this, SLOT(recordingChanged(int)) );
|
|
|
|
recUsePatternCbox->setChecked( taseditorConfig.recordingUsePattern );
|
|
connect( recUsePatternCbox, SIGNAL(stateChanged(int)), this, SLOT(usePatternChanged(int)) );
|
|
|
|
recSuperImposeCbox->setTristate(true);
|
|
connect( recSuperImposeCbox, SIGNAL(stateChanged(int)), this, SLOT(superImposedChanged(int)) );
|
|
|
|
connect( recAllBtn, &QRadioButton::clicked, [ this ] { recordInputChanged( MULTITRACK_RECORDING_ALL ); } );
|
|
connect( rec1PBtn , &QRadioButton::clicked, [ this ] { recordInputChanged( MULTITRACK_RECORDING_1P ); } );
|
|
connect( rec2PBtn , &QRadioButton::clicked, [ this ] { recordInputChanged( MULTITRACK_RECORDING_2P ); } );
|
|
connect( rec3PBtn , &QRadioButton::clicked, [ this ] { recordInputChanged( MULTITRACK_RECORDING_3P ); } );
|
|
connect( rec4PBtn , &QRadioButton::clicked, [ this ] { recordInputChanged( MULTITRACK_RECORDING_4P ); } );
|
|
|
|
connect( rewindMkrBtn, SIGNAL(pressed(void)), this, SLOT(playbackFrameRewindFull(void)) );
|
|
connect( rewindFrmBtn, SIGNAL(pressed(void)), this, SLOT(playbackFrameRewind(void)) );
|
|
connect( playPauseBtn, SIGNAL(pressed(void)), this, SLOT(playbackPauseCB(void)) );
|
|
connect( advFrmBtn , SIGNAL(pressed(void)), this, SLOT(playbackFrameForward(void)) );
|
|
connect( advMkrBtn , SIGNAL(pressed(void)), this, SLOT(playbackFrameForwardFull(void)));
|
|
|
|
connect( followCursorCbox, SIGNAL(clicked(bool)), this, SLOT(playbackFollowCursorCb(bool)));
|
|
connect( turboSeekCbox , SIGNAL(clicked(bool)), this, SLOT(playbackTurboSeekCb(bool)));
|
|
connect( autoRestoreCbox , SIGNAL(clicked(bool)), this, SLOT(playbackAutoRestoreCb(bool)));
|
|
|
|
connect( prevMkrBtn, SIGNAL(clicked(void)), this, SLOT(jumpToPreviousMarker(void)) );
|
|
connect( nextMkrBtn, SIGNAL(clicked(void)), this, SLOT(jumpToNextMarker(void)) );
|
|
connect( similarBtn, SIGNAL(clicked(void)), this, SLOT(findSimilarNote(void)) );
|
|
connect( moreBtn , SIGNAL(clicked(void)), this, SLOT(findNextSimilarNote(void)) );
|
|
|
|
//shortcut = new QShortcut( QKeySequence("Pause"), this);
|
|
//connect( shortcut, SIGNAL(activated(void)), this, SLOT(playbackPauseCB(void)) );
|
|
|
|
shortcut = new QShortcut( QKeySequence("Shift+Up"), this);
|
|
connect( shortcut, SIGNAL(activated(void)), this, SLOT(playbackFrameRewind(void)) );
|
|
|
|
shortcut = new QShortcut( QKeySequence("Shift+Down"), this);
|
|
connect( shortcut, SIGNAL(activated(void)), this, SLOT(playbackFrameForward(void)) );
|
|
|
|
shortcut = new QShortcut( QKeySequence("Shift+PgUp"), this);
|
|
connect( shortcut, SIGNAL(activated(void)), this, SLOT(playbackFrameRewindFull(void)) );
|
|
|
|
shortcut = new QShortcut( QKeySequence("Shift+PgDown"), this);
|
|
connect( shortcut, SIGNAL(activated(void)), this, SLOT(playbackFrameForwardFull(void)) );
|
|
|
|
shortcut = new QShortcut( QKeySequence("Ctrl+Up"), this);
|
|
connect( shortcut, SIGNAL(activated(void)), this, SLOT(scrollSelectionUpOne(void)) );
|
|
|
|
shortcut = new QShortcut( QKeySequence("Ctrl+Down"), this);
|
|
connect( shortcut, SIGNAL(activated(void)), this, SLOT(scrollSelectionDnOne(void)) );
|
|
|
|
connect( histTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(histTreeItemActivated(QTreeWidgetItem*,int) ) );
|
|
connect( histTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(histTreeItemActivated(QTreeWidgetItem*,int) ) );
|
|
|
|
connect( bkmkBrnchStack, SIGNAL(currentChanged(int)), this, SLOT(tabViewChanged(int) ) );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::initHotKeys(void)
|
|
{
|
|
for (int i=0; i<HK_MAX; i++)
|
|
{
|
|
QKeySequence ks = Hotkeys[i].getKeySeq();
|
|
QShortcut *shortcut = Hotkeys[i].getShortcut();
|
|
|
|
//printf("HotKey: %i %s\n", i, ks.toString().toLocal8Bit().constData() );
|
|
|
|
if ( hotkeyShortcut[i] == nullptr )
|
|
{
|
|
hotkeyShortcut[i] = new QShortcut( ks, this );
|
|
|
|
if ( shortcut != nullptr )
|
|
{
|
|
connect( hotkeyShortcut[i], &QShortcut::activated, [ this, i, shortcut ] { activateHotkey( i, shortcut ); } );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hotkeyShortcut[i]->setKey( ks );
|
|
}
|
|
}
|
|
|
|
// Frame Advance uses key state directly, disable shortcut events
|
|
hotkeyShortcut[HK_FRAME_ADVANCE]->setEnabled(false);
|
|
hotkeyShortcut[HK_TURBO ]->setEnabled(false);
|
|
|
|
// Disable shortcuts that are not allowed with TAS Editor
|
|
hotkeyShortcut[HK_OPEN_ROM ]->setEnabled(false);
|
|
hotkeyShortcut[HK_CLOSE_ROM ]->setEnabled(false);
|
|
hotkeyShortcut[HK_QUIT ]->setEnabled(false);
|
|
hotkeyShortcut[HK_FULLSCREEN ]->setEnabled(false);
|
|
hotkeyShortcut[HK_MAIN_MENU_HIDE]->setEnabled(false);
|
|
hotkeyShortcut[HK_LOAD_LUA ]->setEnabled(false);
|
|
hotkeyShortcut[HK_FA_LAG_SKIP ]->setEnabled(false);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::activateHotkey( int hkIdx, QShortcut *shortcut )
|
|
{
|
|
shortcut->activated();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::updateRecordStatus(void)
|
|
{
|
|
recRecordingCbox->setChecked( !movie_readonly );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::updateCheckedItems(void)
|
|
{
|
|
|
|
followCursorCbox->setChecked( taseditorConfig.followPlaybackCursor );
|
|
autoRestoreCbox->setChecked( taseditorConfig.autoRestoreLastPlaybackPosition );
|
|
turboSeekCbox->setChecked( taseditorConfig.turboSeek );
|
|
|
|
if ( taseditorConfig.superimpose == SUPERIMPOSE_CHECKED )
|
|
{
|
|
recSuperImposeCbox->setCheckState( Qt::Checked );
|
|
}
|
|
else if ( taseditorConfig.superimpose == SUPERIMPOSE_INDETERMINATE )
|
|
{
|
|
recSuperImposeCbox->setCheckState( Qt::PartiallyChecked );
|
|
}
|
|
else
|
|
{ //taseditorConfig.superimpose == SUPERIMPOSE_UNCHECKED;
|
|
recSuperImposeCbox->setCheckState( Qt::Unchecked );
|
|
}
|
|
recRecordingCbox->setChecked( !movie_readonly );
|
|
recUsePatternCbox->setChecked( taseditorConfig.recordingUsePattern );
|
|
dpyBrnchScrnAct->setChecked( taseditorConfig.displayBranchScreenshots );
|
|
dpyBrnchDescAct->setChecked( taseditorConfig.displayBranchDescriptions );
|
|
enaHotChgAct->setChecked( taseditorConfig.enableHotChanges );
|
|
followMkrAct->setChecked( taseditorConfig.followMarkerNoteContext );
|
|
followUndoAct->setChecked( taseditorConfig.followUndoContext );
|
|
//autoLuaCBox->setChecked( taseditorConfig.enableLuaAutoFunction );
|
|
autoLuaAct->setChecked( taseditorConfig.enableLuaAutoFunction );
|
|
enaGrnznAct->setChecked( taseditorConfig.enableGreenzoning );
|
|
afPtrnSkipLagAct->setChecked( taseditorConfig.autofirePatternSkipsLag );
|
|
adjInputLagAct->setChecked( taseditorConfig.autoAdjustInputAccordingToLag );
|
|
drawInputDragAct->setChecked( taseditorConfig.drawInputByDragging );
|
|
cmbRecDrawAct->setChecked( taseditorConfig.combineConsecutiveRecordingsAndDraws );
|
|
use1PforRecAct->setChecked( taseditorConfig.use1PKeysForAllSingleRecordings );
|
|
useInputColSetAct->setChecked( taseditorConfig.useInputKeysForColumnSet );
|
|
bindMkrInputAct->setChecked( taseditorConfig.bindMarkersToInput );
|
|
emptyNewMkrNotesAct->setChecked( taseditorConfig.emptyNewMarkerNotes );
|
|
oldCtlBrnhSchemeAct->setChecked( taseditorConfig.oldControlSchemeForBranching );
|
|
brnchRestoreMovieAct->setChecked( taseditorConfig.branchesRestoreEntireMovie );
|
|
hudInScrnBranchAct->setChecked( taseditorConfig.HUDInBranchScreenshots );
|
|
pauseAtEndAct->setChecked( taseditorConfig.autopauseAtTheEndOfMovie );
|
|
showToolTipsAct->setChecked( taseditorConfig.tooltipsEnabled );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bool TasEditorWindow::updateHistoryItems(void)
|
|
{
|
|
int i, cursorPos;
|
|
QTreeWidgetItem *item;
|
|
const char *txt;
|
|
bool isVisible;
|
|
|
|
isVisible = histTree->isVisible();
|
|
|
|
if ( !isVisible )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
cursorPos = history.getCursorPos();
|
|
|
|
for (i=0; i<history.getNumItems(); i++)
|
|
{
|
|
txt = history.getItemDesc(i);
|
|
|
|
item = histTree->topLevelItem(i);
|
|
|
|
if (item == NULL)
|
|
{
|
|
item = new QTreeWidgetItem();
|
|
|
|
histTree->addTopLevelItem(item);
|
|
|
|
//histTree->setCurrentItem(item);
|
|
}
|
|
|
|
if ( txt )
|
|
{
|
|
if ( item->text(0).compare( tr(txt) ) != 0 )
|
|
{
|
|
item->setText(0, tr(txt));
|
|
|
|
//histTree->setCurrentItem(item);
|
|
}
|
|
}
|
|
if ( cursorPos == i )
|
|
{
|
|
histTree->setCurrentItem(item);
|
|
}
|
|
}
|
|
|
|
while ( (histTree->topLevelItemCount() > 0) && (history.getNumItems() < histTree->topLevelItemCount()) )
|
|
{
|
|
item = histTree->takeTopLevelItem( histTree->topLevelItemCount()-1 );
|
|
|
|
if ( item )
|
|
{
|
|
delete item;
|
|
}
|
|
}
|
|
histTree->viewport()->update();
|
|
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
QPoint TasEditorWindow::getPreviewPopupCoordinates(void)
|
|
{
|
|
return bkmkBrnchStack->mapToGlobal(QPoint(0,0));
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int TasEditorWindow::initModules(void)
|
|
{
|
|
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
|
tasEditorTimeStamp = SDL_GetTicks64();
|
|
#else
|
|
tasEditorTimeStamp = SDL_GetTicks();
|
|
#endif
|
|
// init modules
|
|
//editor.init();
|
|
//pianoRoll.init();
|
|
selection.init();
|
|
splicer.init();
|
|
playback.init();
|
|
greenzone.init();
|
|
recorder.init();
|
|
markersManager.init();
|
|
project.init();
|
|
bookmarks.init();
|
|
branches.init();
|
|
//popupDisplay.init();
|
|
history.init();
|
|
taseditor_lua.init();
|
|
// either start new movie or use current movie
|
|
if (!FCEUMOV_Mode(MOVIEMODE_RECORD|MOVIEMODE_PLAY) || currMovieData.savestate.size() != 0)
|
|
{
|
|
if (currMovieData.savestate.size() != 0)
|
|
{
|
|
FCEUD_PrintError("This version of TAS Editor doesn't work with movies starting from savestate.");
|
|
}
|
|
// create new movie
|
|
FCEUI_StopMovie();
|
|
movieMode = MOVIEMODE_TASEDITOR;
|
|
FCEUMOV_CreateCleanMovie();
|
|
playback.restartPlaybackFromZeroGround();
|
|
}
|
|
else
|
|
{
|
|
// use current movie to create a new project
|
|
FCEUI_StopMovie();
|
|
movieMode = MOVIEMODE_TASEDITOR;
|
|
}
|
|
// if movie length is less or equal to currFrame, pad it with empty frames
|
|
if (((int)currMovieData.records.size() - 1) < currFrameCounter)
|
|
{
|
|
currMovieData.insertEmpty(-1, currFrameCounter - ((int)currMovieData.records.size() - 1));
|
|
}
|
|
// ensure that movie has correct set of ports/fourscore
|
|
setInputType(currMovieData, getInputType(currMovieData));
|
|
// force the input configuration stored in the movie to apply to FCEUX config
|
|
applyMovieInputConfig();
|
|
// reset some modules that need MovieData info
|
|
pianoRoll->reset();
|
|
recorder.reset();
|
|
// create initial snapshot in history
|
|
history.reset();
|
|
// reset Taseditor variables
|
|
mustCallManualLuaFunction = false;
|
|
|
|
//SetFocus(history.hwndHistoryList); // set focus only once, to show blue selection cursor
|
|
//SetFocus(pianoRoll.hwndList);
|
|
FCEU_DispMessage("TAS Editor engaged", 0);
|
|
update();
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::frameUpdate(void)
|
|
{
|
|
FCEU_WRAPPER_LOCK();
|
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
|
tasEditorTimeStamp = SDL_GetTicks64();
|
|
#else
|
|
tasEditorTimeStamp = SDL_GetTicks();
|
|
#endif
|
|
|
|
//printf("TAS Frame Update: %zi %u\n", currMovieData.records.size(), tasEditorTimeStamp);
|
|
|
|
//taseditorWindow.update();
|
|
greenzone.update();
|
|
recorder.update();
|
|
pianoRoll->periodicUpdate();
|
|
markersManager.update();
|
|
playback.update();
|
|
bookmarks.update();
|
|
branches.update();
|
|
//popupDisplay.update();
|
|
selection.update();
|
|
splicer.update();
|
|
history.update();
|
|
project.update();
|
|
|
|
#ifdef _S9XLUA_H
|
|
// run Lua functions if needed
|
|
if (taseditorConfig.enableLuaAutoFunction)
|
|
{
|
|
TaseditorAutoFunction();
|
|
}
|
|
if (mustCallManualLuaFunction)
|
|
{
|
|
TaseditorManualFunction();
|
|
mustCallManualLuaFunction = false;
|
|
}
|
|
#endif
|
|
|
|
pianoRoll->update();
|
|
|
|
if ( recentProjectMenuReset )
|
|
{
|
|
buildRecentProjectMenu();
|
|
recentProjectMenuReset = false;
|
|
}
|
|
|
|
FCEU_WRAPPER_UNLOCK();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bool TasEditorWindow::loadProject(const char* fullname)
|
|
{
|
|
bool success = false;
|
|
|
|
FCEU_WRAPPER_LOCK();
|
|
|
|
// try to load project
|
|
if (project.load(fullname))
|
|
{
|
|
// loaded successfully
|
|
applyMovieInputConfig();
|
|
// add new file to Recent menu
|
|
addRecentProject( fullname );
|
|
updateCaption();
|
|
update();
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
// failed to load
|
|
updateCaption();
|
|
update();
|
|
}
|
|
FCEU_WRAPPER_UNLOCK();
|
|
|
|
return success;
|
|
}
|
|
bool TasEditorWindow::saveProject(bool save_compact)
|
|
{
|
|
bool ret = true;
|
|
|
|
FCEU_WRAPPER_LOCK();
|
|
|
|
if (project.getProjectFile().empty())
|
|
{
|
|
ret = saveProjectAs(save_compact);
|
|
}
|
|
else
|
|
{
|
|
if (save_compact)
|
|
{
|
|
project.save(0, taseditorConfig.saveCompact_SaveInBinary, taseditorConfig.saveCompact_SaveMarkers, taseditorConfig.saveCompact_SaveBookmarks, taseditorConfig.saveCompact_GreenzoneSavingMode, taseditorConfig.saveCompact_SaveHistory, taseditorConfig.saveCompact_SavePianoRoll, taseditorConfig.saveCompact_SaveSelection);
|
|
}
|
|
else
|
|
{
|
|
project.save(0, taseditorConfig.projectSavingOptions_SaveInBinary, taseditorConfig.projectSavingOptions_SaveMarkers, taseditorConfig.projectSavingOptions_SaveBookmarks, taseditorConfig.projectSavingOptions_GreenzoneSavingMode, taseditorConfig.projectSavingOptions_SaveHistory, taseditorConfig.projectSavingOptions_SavePianoRoll, taseditorConfig.projectSavingOptions_SaveSelection);
|
|
}
|
|
updateCaption();
|
|
}
|
|
|
|
FCEU_WRAPPER_UNLOCK();
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool TasEditorWindow::saveProjectAs(bool save_compact)
|
|
{
|
|
std::string last;
|
|
int ret, useNativeFileDialogVal;
|
|
QString filename;
|
|
std::string lastPath;
|
|
//char dir[512];
|
|
const char *base, *rom;
|
|
QFileDialog dialog(this, tr("Save TAS Editor Project As") );
|
|
QList<QUrl> urls;
|
|
QDir d;
|
|
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
|
|
dialog.setNameFilter(tr("TAS Project Files (*.fm3) ;; All files (*)"));
|
|
|
|
dialog.setViewMode(QFileDialog::List);
|
|
dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
|
|
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
|
|
|
|
base = FCEUI_GetBaseDirectory();
|
|
|
|
urls << QUrl::fromLocalFile( QDir::rootPath() );
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first());
|
|
|
|
if ( base )
|
|
{
|
|
urls << QUrl::fromLocalFile( QDir( base ).absolutePath() );
|
|
|
|
d.setPath( QString(base) + "/movies");
|
|
|
|
if ( d.exists() )
|
|
{
|
|
urls << QUrl::fromLocalFile( d.absolutePath() );
|
|
}
|
|
|
|
dialog.setDirectory( d.absolutePath() );
|
|
}
|
|
dialog.setDefaultSuffix( tr(".fm3") );
|
|
|
|
g_config->getOption ("SDL.TasProjectFilePath", &lastPath);
|
|
if ( lastPath.size() > 0 )
|
|
{
|
|
dialog.setDirectory( QString::fromStdString(lastPath) );
|
|
}
|
|
|
|
rom = getRomFile();
|
|
|
|
if ( rom )
|
|
{
|
|
char baseName[512];
|
|
getFileBaseName( rom, baseName );
|
|
|
|
if ( baseName[0] != 0 )
|
|
{
|
|
strcat( baseName, ".fm3");
|
|
|
|
dialog.selectFile(baseName);
|
|
}
|
|
}
|
|
|
|
// Check config option to use native file dialog or not
|
|
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
|
|
|
|
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
|
|
dialog.setSidebarUrls(urls);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret )
|
|
{
|
|
QStringList fileList;
|
|
fileList = dialog.selectedFiles();
|
|
|
|
if ( fileList.size() > 0 )
|
|
{
|
|
filename = fileList[0];
|
|
}
|
|
}
|
|
|
|
if ( filename.isNull() )
|
|
{
|
|
return false;
|
|
}
|
|
QFileInfo fi( filename );
|
|
|
|
if ( fi.exists() )
|
|
{
|
|
int ret;
|
|
std::string msg;
|
|
|
|
msg = "Pre-existing TAS project file will be overwritten:\n\n" +
|
|
std::string(fi.fileName().toLocal8Bit()) + "\n\nReplace file?";
|
|
|
|
ret = QMessageBox::warning( this, QObject::tr("Overwrite Warning"),
|
|
QString::fromStdString(msg), QMessageBox::Yes | QMessageBox::No, QMessageBox::No );
|
|
|
|
if ( ret == QMessageBox::No )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
//qDebug() << "selected file path : " << filename.toLocal8Bit();
|
|
|
|
project.renameProject( filename.toLocal8Bit().constData(), true);
|
|
if (save_compact)
|
|
{
|
|
project.save( filename.toLocal8Bit().constData(), taseditorConfig.saveCompact_SaveInBinary, taseditorConfig.saveCompact_SaveMarkers, taseditorConfig.saveCompact_SaveBookmarks, taseditorConfig.saveCompact_GreenzoneSavingMode, taseditorConfig.saveCompact_SaveHistory, taseditorConfig.saveCompact_SavePianoRoll, taseditorConfig.saveCompact_SaveSelection);
|
|
}
|
|
else
|
|
{
|
|
project.save( filename.toLocal8Bit().constData(), taseditorConfig.projectSavingOptions_SaveInBinary, taseditorConfig.projectSavingOptions_SaveMarkers, taseditorConfig.projectSavingOptions_SaveBookmarks, taseditorConfig.projectSavingOptions_GreenzoneSavingMode, taseditorConfig.projectSavingOptions_SaveHistory, taseditorConfig.projectSavingOptions_SavePianoRoll, taseditorConfig.projectSavingOptions_SaveSelection);
|
|
}
|
|
addRecentProject( filename.toLocal8Bit().constData() );
|
|
// saved successfully - remove * mark from caption
|
|
project.reset();
|
|
updateCaption();
|
|
return true;
|
|
}
|
|
|
|
// returns false if user doesn't want to exit
|
|
bool TasEditorWindow::askToSaveProject(void)
|
|
{
|
|
bool changesFound = false;
|
|
if (project.getProjectChanged())
|
|
{
|
|
changesFound = true;
|
|
}
|
|
|
|
// ask saving project
|
|
if (changesFound)
|
|
{
|
|
int ans = QMessageBox::question( this, tr("TAS Editor"), tr("Save project changes?"),
|
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes );
|
|
|
|
//int answer = MessageBox(taseditorWindow.hwndTASEditor, "Save Project changes?", "TAS Editor", MB_YESNOCANCEL);
|
|
if (ans == QMessageBox::Yes)
|
|
{
|
|
return saveProject();
|
|
}
|
|
return (ans != QMessageBox::Cancel);
|
|
}
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::openProject(void)
|
|
{
|
|
std::string last;
|
|
int ret, useNativeFileDialogVal;
|
|
QString filename;
|
|
std::string lastPath;
|
|
//char dir[512];
|
|
const char *base, *rom;
|
|
QFileDialog dialog(this, tr("Open TAS Editor Project") );
|
|
QList<QUrl> urls;
|
|
QDir d;
|
|
|
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
|
|
|
dialog.setNameFilter(tr("TAS Project Files (*.fm3) ;; All files (*)"));
|
|
|
|
dialog.setViewMode(QFileDialog::List);
|
|
dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
|
|
dialog.setLabelText( QFileDialog::Accept, tr("Open") );
|
|
|
|
base = FCEUI_GetBaseDirectory();
|
|
|
|
urls << QUrl::fromLocalFile( QDir::rootPath() );
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first());
|
|
|
|
if ( base )
|
|
{
|
|
urls << QUrl::fromLocalFile( QDir( base ).absolutePath() );
|
|
|
|
d.setPath( QString(base) + "/movies");
|
|
|
|
if ( d.exists() )
|
|
{
|
|
urls << QUrl::fromLocalFile( d.absolutePath() );
|
|
}
|
|
|
|
dialog.setDirectory( d.absolutePath() );
|
|
}
|
|
dialog.setDefaultSuffix( tr(".fm3") );
|
|
|
|
g_config->getOption ("SDL.TasProjectFilePath", &lastPath);
|
|
if ( lastPath.size() > 0 )
|
|
{
|
|
dialog.setDirectory( QString::fromStdString(lastPath) );
|
|
}
|
|
|
|
rom = getRomFile();
|
|
|
|
if ( rom )
|
|
{
|
|
char baseName[512];
|
|
getFileBaseName( rom, baseName );
|
|
|
|
if ( baseName[0] != 0 )
|
|
{
|
|
dialog.selectFile(baseName);
|
|
}
|
|
}
|
|
|
|
// Check config option to use native file dialog or not
|
|
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
|
|
|
|
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
|
|
dialog.setSidebarUrls(urls);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret )
|
|
{
|
|
QStringList fileList;
|
|
fileList = dialog.selectedFiles();
|
|
|
|
if ( fileList.size() > 0 )
|
|
{
|
|
filename = fileList[0];
|
|
}
|
|
}
|
|
|
|
if ( filename.isNull() )
|
|
{
|
|
return;
|
|
}
|
|
//qDebug() << "selected file path : " << filename.toLocal8Bit();
|
|
|
|
loadProject( filename.toLocal8Bit().constData());
|
|
|
|
return;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::createNewProject(void)
|
|
{
|
|
int ret;
|
|
QDialog dialog(this);
|
|
QGroupBox *gbox;
|
|
QVBoxLayout *mainLayout, *vbox;
|
|
QHBoxLayout *hbox;
|
|
QPushButton *okButton, *cancelButton;
|
|
QRadioButton *p1, *p2, *p4;
|
|
QCheckBox *copyInput, *copyMarkers;
|
|
QLineEdit *authorEdit;
|
|
static struct NewProjectParameters params;
|
|
|
|
if (!askToSaveProject())
|
|
{
|
|
return;
|
|
}
|
|
|
|
params.inputType = getInputType(currMovieData);
|
|
params.copyCurrentInput = params.copyCurrentMarkers = false;
|
|
if (strlen(taseditorConfig.lastAuthorName) > 0)
|
|
{
|
|
int i=0;
|
|
// convert UTF8 char* string to Unicode wstring
|
|
wchar_t savedAuthorName[AUTHOR_NAME_MAX_LEN] = {0};
|
|
|
|
while ( taseditorConfig.lastAuthorName[i] != 0 )
|
|
{
|
|
savedAuthorName[i] = taseditorConfig.lastAuthorName[i]; i++;
|
|
}
|
|
savedAuthorName[i] = 0;
|
|
params.authorName = savedAuthorName;
|
|
}
|
|
else
|
|
{
|
|
params.authorName = L"";
|
|
}
|
|
|
|
mainLayout = new QVBoxLayout();
|
|
hbox = new QHBoxLayout();
|
|
vbox = new QVBoxLayout();
|
|
gbox = new QGroupBox( tr("Input Type") );
|
|
|
|
mainLayout->addLayout( hbox );
|
|
hbox->addWidget( gbox );
|
|
gbox->setLayout( vbox );
|
|
|
|
p1 = new QRadioButton( tr("1 Player") );
|
|
p2 = new QRadioButton( tr("2 Players") );
|
|
p4 = new QRadioButton( tr("4 Score") );
|
|
|
|
p1->setChecked( params.inputType == INPUT_TYPE_1P );
|
|
p2->setChecked( params.inputType == INPUT_TYPE_2P );
|
|
p4->setChecked( params.inputType == INPUT_TYPE_FOURSCORE );
|
|
|
|
vbox->addWidget( p1 );
|
|
vbox->addWidget( p2 );
|
|
vbox->addWidget( p4 );
|
|
|
|
vbox = new QVBoxLayout();
|
|
hbox->addLayout( vbox );
|
|
|
|
copyInput = new QCheckBox( tr("Copy Input") );
|
|
copyMarkers = new QCheckBox( tr("Copy Markers") );
|
|
|
|
vbox->addWidget( copyInput );
|
|
vbox->addWidget( copyMarkers );
|
|
|
|
hbox = new QHBoxLayout();
|
|
mainLayout->addLayout( hbox );
|
|
|
|
authorEdit = new QLineEdit();
|
|
hbox->addWidget( new QLabel( tr("Author") ), 1 );
|
|
hbox->addWidget( authorEdit, 5 );
|
|
|
|
hbox = new QHBoxLayout();
|
|
mainLayout->addLayout( hbox );
|
|
|
|
okButton = new QPushButton( tr("Ok") );
|
|
cancelButton = new QPushButton( tr("Cancel") );
|
|
|
|
hbox->addWidget( cancelButton, 1 );
|
|
hbox->addStretch( 5 );
|
|
hbox->addWidget( okButton , 1 );
|
|
|
|
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogApplyButton ) );
|
|
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
|
|
|
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
|
|
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
|
|
|
|
dialog.setLayout( mainLayout );
|
|
|
|
dialog.setWindowTitle( tr("Create New Project") );
|
|
|
|
okButton->setDefault(true);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( p4->isChecked() )
|
|
{
|
|
params.inputType = INPUT_TYPE_FOURSCORE;
|
|
}
|
|
else if ( p2->isChecked() )
|
|
{
|
|
params.inputType = INPUT_TYPE_2P;
|
|
}
|
|
else
|
|
{
|
|
params.inputType = INPUT_TYPE_1P;
|
|
}
|
|
params.copyCurrentInput = copyInput->isChecked();
|
|
params.copyCurrentMarkers = copyMarkers->isChecked();
|
|
params.authorName = authorEdit->text().toStdWString();
|
|
|
|
FCEU_WRAPPER_LOCK();
|
|
|
|
if ( QDialog::Accepted == ret )
|
|
{
|
|
FCEUMOV_CreateCleanMovie();
|
|
// apply selected options
|
|
setInputType(currMovieData, params.inputType);
|
|
applyMovieInputConfig();
|
|
if (params.copyCurrentInput)
|
|
{
|
|
// copy Input from current snapshot (from history)
|
|
history.getCurrentSnapshot().inputlog.toMovie(currMovieData);
|
|
}
|
|
if (!params.copyCurrentMarkers)
|
|
{
|
|
markersManager.reset();
|
|
}
|
|
if (params.authorName != L"") currMovieData.comments.push_back(L"author " + params.authorName);
|
|
|
|
// reset Taseditor
|
|
project.init(); // new project has blank name
|
|
greenzone.reset();
|
|
if (params.copyCurrentInput)
|
|
{
|
|
// copy LagLog from current snapshot (from history)
|
|
greenzone.lagLog = history.getCurrentSnapshot().laglog;
|
|
}
|
|
playback.reset();
|
|
playback.restartPlaybackFromZeroGround();
|
|
bookmarks.reset();
|
|
branches.reset();
|
|
history.reset();
|
|
pianoRoll->reset();
|
|
selection.reset();
|
|
//editor.reset();
|
|
splicer.reset();
|
|
recorder.reset();
|
|
//popupDisplay.reset();
|
|
//taseditorWindow.redraw();
|
|
updateCaption();
|
|
update();
|
|
}
|
|
FCEU_WRAPPER_UNLOCK();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::importMovieFile( const char *path )
|
|
{
|
|
EMUFILE_FILE ifs( path, "rb");
|
|
|
|
// Load Input to temporary moviedata
|
|
MovieData md;
|
|
if (LoadFM2(md, &ifs, ifs.size(), false))
|
|
{
|
|
QFileInfo fi( path );
|
|
// loaded successfully, now register Input changes
|
|
//char drv[512], dir[512], name[1024], ext[512];
|
|
//splitpath(filename.toLocal8Bit().constData(), drv, dir, name, ext);
|
|
//strcat(name, ext);
|
|
int result = history.registerImport(md, fi.fileName().toLocal8Bit().constData() );
|
|
if (result >= 0)
|
|
{
|
|
greenzone.invalidateAndUpdatePlayback(result);
|
|
greenzone.lagLog.invalidateFromFrame(result);
|
|
// keep current snapshot laglog in touch
|
|
history.getCurrentSnapshot().laglog.invalidateFromFrame(result);
|
|
}
|
|
else
|
|
{
|
|
//MessageBox(taseditorWindow.hwndTASEditor, "Imported movie has the same Input.\nNo changes were made.", "TAS Editor", MB_OK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FCEUD_PrintError("Error loading movie data!");
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::importMovieFile(void)
|
|
{
|
|
std::string last;
|
|
int ret, useNativeFileDialogVal;
|
|
QString filename;
|
|
std::string lastPath;
|
|
//char dir[512];
|
|
const char *base, *rom;
|
|
QFileDialog dialog(this, tr("Import Movie File") );
|
|
QList<QUrl> urls;
|
|
QDir d;
|
|
|
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
|
|
|
dialog.setNameFilter(tr("FCEUX Movie Files (*.fm2) ;; TAS Project Files (*.fm3) ;; All files (*)"));
|
|
|
|
dialog.setViewMode(QFileDialog::List);
|
|
dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
|
|
dialog.setLabelText( QFileDialog::Accept, tr("Import") );
|
|
|
|
base = FCEUI_GetBaseDirectory();
|
|
|
|
urls << QUrl::fromLocalFile( QDir::rootPath() );
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first());
|
|
|
|
if ( base )
|
|
{
|
|
urls << QUrl::fromLocalFile( QDir( base ).absolutePath() );
|
|
|
|
d.setPath( QString(base) + "/movies");
|
|
|
|
if ( d.exists() )
|
|
{
|
|
urls << QUrl::fromLocalFile( d.absolutePath() );
|
|
}
|
|
|
|
dialog.setDirectory( d.absolutePath() );
|
|
}
|
|
dialog.setDefaultSuffix( tr(".fm2") );
|
|
|
|
g_config->getOption ("SDL.TasProjectFilePath", &lastPath);
|
|
if ( lastPath.size() > 0 )
|
|
{
|
|
dialog.setDirectory( QString::fromStdString(lastPath) );
|
|
}
|
|
|
|
rom = getRomFile();
|
|
|
|
if ( rom )
|
|
{
|
|
char baseName[512];
|
|
getFileBaseName( rom, baseName );
|
|
|
|
if ( baseName[0] != 0 )
|
|
{
|
|
dialog.selectFile(baseName);
|
|
}
|
|
}
|
|
|
|
// Check config option to use native file dialog or not
|
|
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
|
|
|
|
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
|
|
dialog.setSidebarUrls(urls);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret )
|
|
{
|
|
QStringList fileList;
|
|
fileList = dialog.selectedFiles();
|
|
|
|
if ( fileList.size() > 0 )
|
|
{
|
|
filename = fileList[0];
|
|
}
|
|
}
|
|
|
|
if ( filename.isNull() )
|
|
{
|
|
return;
|
|
}
|
|
//qDebug() << "selected file path : " << filename.toLocal8Bit();
|
|
|
|
importMovieFile( filename.toLocal8Bit().constData() );
|
|
|
|
//EMUFILE_FILE ifs( filename.toLocal8Bit().constData(), "rb");
|
|
|
|
//// Load Input to temporary moviedata
|
|
//MovieData md;
|
|
//if (LoadFM2(md, &ifs, ifs.size(), false))
|
|
//{
|
|
// QFileInfo fi( filename );
|
|
// // loaded successfully, now register Input changes
|
|
// //char drv[512], dir[512], name[1024], ext[512];
|
|
// //splitpath(filename.toLocal8Bit().constData(), drv, dir, name, ext);
|
|
// //strcat(name, ext);
|
|
// int result = history.registerImport(md, fi.fileName().toLocal8Bit().constData() );
|
|
// if (result >= 0)
|
|
// {
|
|
// greenzone.invalidateAndUpdatePlayback(result);
|
|
// greenzone.lagLog.invalidateFromFrame(result);
|
|
// // keep current snapshot laglog in touch
|
|
// history.getCurrentSnapshot().laglog.invalidateFromFrame(result);
|
|
// }
|
|
// else
|
|
// {
|
|
// //MessageBox(taseditorWindow.hwndTASEditor, "Imported movie has the same Input.\nNo changes were made.", "TAS Editor", MB_OK);
|
|
// }
|
|
//}
|
|
//else
|
|
//{
|
|
// FCEUD_PrintError("Error loading movie data!");
|
|
//}
|
|
|
|
return;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::exportMovieFile(void)
|
|
{
|
|
std::string last;
|
|
int ret, useNativeFileDialogVal;
|
|
QString filename;
|
|
std::string lastPath;
|
|
//char dir[512];
|
|
const char *base, *rom;
|
|
QFileDialog dialog(this, tr("Export to FM2 File") );
|
|
QList<QUrl> urls;
|
|
QDir d;
|
|
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
|
|
dialog.setNameFilter(tr("FCEUX Movie File (*.fm2) ;; All files (*)"));
|
|
|
|
dialog.setViewMode(QFileDialog::List);
|
|
dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
|
|
dialog.setLabelText( QFileDialog::Accept, tr("Export") );
|
|
|
|
base = FCEUI_GetBaseDirectory();
|
|
|
|
urls << QUrl::fromLocalFile( QDir::rootPath() );
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first());
|
|
|
|
if ( base )
|
|
{
|
|
urls << QUrl::fromLocalFile( QDir( base ).absolutePath() );
|
|
|
|
d.setPath( QString(base) + "/movies");
|
|
|
|
if ( d.exists() )
|
|
{
|
|
urls << QUrl::fromLocalFile( d.absolutePath() );
|
|
}
|
|
|
|
dialog.setDirectory( d.absolutePath() );
|
|
}
|
|
dialog.setDefaultSuffix( tr(".fm2") );
|
|
|
|
g_config->getOption ("SDL.TasProjectFilePath", &lastPath);
|
|
if ( lastPath.size() > 0 )
|
|
{
|
|
dialog.setDirectory( QString::fromStdString(lastPath) );
|
|
}
|
|
|
|
rom = getRomFile();
|
|
|
|
if ( rom )
|
|
{
|
|
char baseName[512];
|
|
getFileBaseName( rom, baseName );
|
|
|
|
if ( baseName[0] != 0 )
|
|
{
|
|
dialog.selectFile(baseName);
|
|
}
|
|
}
|
|
|
|
// Check config option to use native file dialog or not
|
|
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
|
|
|
|
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
|
|
dialog.setSidebarUrls(urls);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret )
|
|
{
|
|
QStringList fileList;
|
|
fileList = dialog.selectedFiles();
|
|
|
|
if ( fileList.size() > 0 )
|
|
{
|
|
filename = fileList[0];
|
|
}
|
|
}
|
|
|
|
if ( filename.isNull() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
EMUFILE* osRecordingMovie = FCEUD_UTF8_fstream( filename.toLocal8Bit().constData(), "wb");
|
|
// create copy of current movie data
|
|
MovieData temp_md = currMovieData;
|
|
// modify the copy according to selected type of export
|
|
setInputType(temp_md, taseditorConfig.lastExportedInputType);
|
|
temp_md.loadFrameCount = -1;
|
|
// also add subtitles if needed
|
|
if (taseditorConfig.lastExportedSubtitlesStatus)
|
|
{
|
|
// convert Marker Notes to Movie Subtitles
|
|
char framenum[16];
|
|
std::string subtitle;
|
|
int markerID;
|
|
for (int i = 0; i < markersManager.getMarkersArraySize(); ++i)
|
|
{
|
|
markerID = markersManager.getMarkerAtFrame(i);
|
|
if (markerID)
|
|
{
|
|
snprintf( framenum, sizeof(framenum), "%i ", i );
|
|
//_itoa(i, framenum, 10);
|
|
//strcat(framenum, " ");
|
|
subtitle = framenum;
|
|
subtitle.append(markersManager.getNoteCopy(markerID));
|
|
temp_md.subtitles.push_back(subtitle);
|
|
}
|
|
}
|
|
}
|
|
// dump to disk
|
|
temp_md.dump(osRecordingMovie, false);
|
|
delete osRecordingMovie;
|
|
osRecordingMovie = 0;
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::updateCaption(void)
|
|
{
|
|
char newCaption[300];
|
|
strcpy(newCaption, "TAS Editor");
|
|
if (!movie_readonly)
|
|
{
|
|
strcat(newCaption, recorder.getRecordingCaption());
|
|
}
|
|
// add project name
|
|
std::string projectname = project.getProjectName();
|
|
if (!projectname.empty())
|
|
{
|
|
strcat(newCaption, " - ");
|
|
strcat(newCaption, projectname.c_str());
|
|
}
|
|
// and * if project has unsaved changes
|
|
if (project.getProjectChanged())
|
|
{
|
|
strcat(newCaption, "*");
|
|
}
|
|
setWindowTitle( tr(newCaption) );
|
|
//SetWindowText(hwndTASEditor, newCaption);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::clearProjectList(void)
|
|
{
|
|
std::list <std::string*>::iterator it;
|
|
|
|
for (it=projList.begin(); it != projList.end(); it++)
|
|
{
|
|
delete *it;
|
|
}
|
|
projList.clear();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::buildRecentProjectMenu(void)
|
|
{
|
|
QAction *act;
|
|
std::string s;
|
|
std::string *sptr;
|
|
char buf[128];
|
|
|
|
clearProjectList();
|
|
recentProjectMenu->clear();
|
|
|
|
for (int i=0; i<10; i++)
|
|
{
|
|
snprintf(buf, sizeof(buf), "SDL.RecentTasProject%02i", i);
|
|
|
|
g_config->getOption( buf, &s);
|
|
|
|
//printf("Recent Rom:%i '%s'\n", i, s.c_str() );
|
|
|
|
if ( s.size() > 0 )
|
|
{
|
|
act = new TasRecentProjectAction( tr(s.c_str()), recentProjectMenu);
|
|
|
|
recentProjectMenu->addAction( act );
|
|
|
|
connect(act, SIGNAL(triggered()), act, SLOT(activateCB(void)) );
|
|
|
|
sptr = new std::string();
|
|
|
|
sptr->assign( s.c_str() );
|
|
|
|
projList.push_front( sptr );
|
|
}
|
|
}
|
|
recentProjectMenu->setEnabled( !recentProjectMenu->isEmpty() );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void TasEditorWindow::saveRecentProjectMenu(void)
|
|
{
|
|
int i;
|
|
std::string *s;
|
|
std::list <std::string*>::iterator it;
|
|
char buf[128];
|
|
|
|
i = projList.size() - 1;
|
|
|
|
for (it=projList.begin(); it != projList.end(); it++)
|
|
{
|
|
s = *it;
|
|
snprintf(buf, sizeof(buf), "SDL.RecentTasProject%02i", i);
|
|
|
|
g_config->setOption( buf, s->c_str() );
|
|
|
|
//printf("Recent Rom:%u '%s'\n", i, s->c_str() );
|
|
i--;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void TasEditorWindow::addRecentProject( const char *proj )
|
|
{
|
|
std::string *s;
|
|
std::list <std::string*>::iterator match_it;
|
|
|
|
for (match_it=projList.begin(); match_it != projList.end(); match_it++)
|
|
{
|
|
s = *match_it;
|
|
|
|
if ( s->compare( proj ) == 0 )
|
|
{
|
|
//printf("Found Match: %s\n", proj );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( match_it != projList.end() )
|
|
{
|
|
s = *match_it;
|
|
|
|
projList.erase(match_it);
|
|
|
|
projList.push_back(s);
|
|
}
|
|
else
|
|
{
|
|
s = new std::string();
|
|
|
|
s->assign( proj );
|
|
|
|
projList.push_back(s);
|
|
|
|
if ( projList.size() > 10 )
|
|
{
|
|
s = projList.front();
|
|
|
|
projList.pop_front();
|
|
|
|
delete s;
|
|
}
|
|
}
|
|
|
|
saveRecentProjectMenu();
|
|
|
|
recentProjectMenuReset = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::saveProjectCb(void)
|
|
{
|
|
saveProject();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::saveProjectAsCb(void)
|
|
{
|
|
saveProjectAs();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bool TasEditorWindow::saveCompactGetFilename( QString &outputFilePath )
|
|
{
|
|
std::string last;
|
|
int ret, useNativeFileDialogVal;
|
|
QString filename;
|
|
std::string lastPath;
|
|
//char dir[512];
|
|
const char *base, *rom;
|
|
QFileDialog dialog(this, tr("Save Compact TAS Editor Project As") );
|
|
QList<QUrl> urls;
|
|
QDir d;
|
|
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
|
|
dialog.setNameFilter(tr("TAS Project Files (*.fm3) ;; All files (*)"));
|
|
|
|
dialog.setViewMode(QFileDialog::List);
|
|
dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden );
|
|
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
|
|
|
|
base = FCEUI_GetBaseDirectory();
|
|
|
|
urls << QUrl::fromLocalFile( QDir::rootPath() );
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
|
|
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first());
|
|
|
|
if ( base )
|
|
{
|
|
urls << QUrl::fromLocalFile( QDir( base ).absolutePath() );
|
|
|
|
d.setPath( QString(base) + "/movies");
|
|
|
|
if ( d.exists() )
|
|
{
|
|
urls << QUrl::fromLocalFile( d.absolutePath() );
|
|
}
|
|
|
|
dialog.setDirectory( d.absolutePath() );
|
|
}
|
|
dialog.setDefaultSuffix( tr(".fm3") );
|
|
|
|
g_config->getOption ("SDL.TasProjectFilePath", &lastPath);
|
|
if ( lastPath.size() > 0 )
|
|
{
|
|
dialog.setDirectory( QString::fromStdString(lastPath) );
|
|
}
|
|
|
|
rom = getRomFile();
|
|
|
|
if (!project.getProjectName().empty())
|
|
{
|
|
char baseName[512];
|
|
|
|
strcpy(baseName, project.getProjectName().c_str());
|
|
|
|
if (strstr(baseName, "-compact") == NULL)
|
|
{
|
|
strcat(baseName, "-compact");
|
|
}
|
|
strcat( baseName, ".fm3");
|
|
|
|
dialog.selectFile(baseName);
|
|
}
|
|
else if ( rom )
|
|
{
|
|
char baseName[512];
|
|
getFileBaseName( rom, baseName );
|
|
|
|
if ( baseName[0] != 0 )
|
|
{
|
|
if (strstr(baseName, "-compact") == NULL)
|
|
{
|
|
strcat(baseName, "-compact");
|
|
}
|
|
strcat( baseName, ".fm3");
|
|
|
|
dialog.selectFile(baseName);
|
|
}
|
|
}
|
|
|
|
// Check config option to use native file dialog or not
|
|
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
|
|
|
|
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
|
|
dialog.setSidebarUrls(urls);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret )
|
|
{
|
|
QStringList fileList;
|
|
fileList = dialog.selectedFiles();
|
|
|
|
if ( fileList.size() > 0 )
|
|
{
|
|
filename = fileList[0];
|
|
}
|
|
}
|
|
|
|
if ( filename.isNull() )
|
|
{
|
|
return false;
|
|
}
|
|
QFileInfo fi( filename );
|
|
|
|
if ( fi.exists() )
|
|
{
|
|
int ret;
|
|
std::string msg;
|
|
|
|
msg = "Pre-existing TAS project file will be overwritten:\n\n" +
|
|
std::string(fi.fileName().toLocal8Bit()) + "\n\nReplace file?";
|
|
|
|
ret = QMessageBox::warning( this, QObject::tr("Overwrite Warning"),
|
|
QString::fromStdString(msg), QMessageBox::Yes | QMessageBox::No, QMessageBox::No );
|
|
|
|
if ( ret == QMessageBox::No )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
outputFilePath = filename;
|
|
|
|
//qDebug() << "selected file path : " << filename.toLocal8Bit();
|
|
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::saveProjectCompactCb(void)
|
|
{
|
|
int ret;
|
|
QDialog dialog(this);
|
|
FCEU_CRITICAL_SECTION(emuLock);
|
|
QGroupBox *fileContentsBox, *greenZoneSaveBox;
|
|
QVBoxLayout *mainLayout, *vbox1, *vbox;
|
|
QHBoxLayout *hbox;
|
|
QCheckBox *binaryInput, *saveMarkers, *saveBookmarks;
|
|
QCheckBox *saveHistory, *savePianoRoll, *saveSelection;
|
|
QRadioButton *allFrames, *every16thFrame, *markedFrames, *dontSave;
|
|
QPushButton *okButton, *cancelButton;
|
|
|
|
dialog.setWindowTitle( tr("Save Compact") );
|
|
|
|
mainLayout = new QVBoxLayout();
|
|
fileContentsBox = new QGroupBox( tr("File Contents") );
|
|
greenZoneSaveBox = new QGroupBox( tr("Greenzone Saving Options") );
|
|
|
|
binaryInput = new QCheckBox( tr("Binary Input") );
|
|
saveMarkers = new QCheckBox( tr("Markers") );
|
|
saveBookmarks = new QCheckBox( tr("Bookmarks") );
|
|
saveHistory = new QCheckBox( tr("History") );
|
|
savePianoRoll = new QCheckBox( tr("Piano Roll") );
|
|
saveSelection = new QCheckBox( tr("Selection") );
|
|
|
|
allFrames = new QRadioButton( tr("All Frames") );
|
|
every16thFrame = new QRadioButton( tr("Every 16th Frame") );
|
|
markedFrames = new QRadioButton( tr("Marked Frame") );
|
|
dontSave = new QRadioButton( tr("Don't Save") );
|
|
|
|
okButton = new QPushButton( tr("Ok") );
|
|
cancelButton = new QPushButton( tr("Cancel") );
|
|
|
|
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogApplyButton ) );
|
|
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
|
|
|
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
|
|
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
|
|
|
|
vbox1 = new QVBoxLayout();
|
|
|
|
dialog.setLayout( mainLayout );
|
|
mainLayout->addWidget( fileContentsBox );
|
|
|
|
fileContentsBox->setLayout( vbox1 );
|
|
|
|
vbox1->addWidget( binaryInput );
|
|
vbox1->addWidget( saveMarkers );
|
|
vbox1->addWidget( saveBookmarks );
|
|
vbox1->addWidget( saveHistory );
|
|
vbox1->addWidget( savePianoRoll );
|
|
vbox1->addWidget( saveSelection );
|
|
vbox1->addWidget( greenZoneSaveBox );
|
|
|
|
vbox = new QVBoxLayout();
|
|
greenZoneSaveBox->setLayout( vbox );
|
|
|
|
vbox->addWidget( allFrames );
|
|
vbox->addWidget( every16thFrame );
|
|
vbox->addWidget( markedFrames );
|
|
vbox->addWidget( dontSave );
|
|
|
|
hbox = new QHBoxLayout();
|
|
mainLayout->addLayout( hbox );
|
|
hbox->addStretch(5);
|
|
hbox->addWidget( okButton );
|
|
hbox->addWidget( cancelButton );
|
|
|
|
binaryInput->setChecked( taseditorConfig.saveCompact_SaveInBinary );
|
|
saveMarkers->setChecked( taseditorConfig.saveCompact_SaveMarkers );
|
|
saveBookmarks->setChecked( taseditorConfig.saveCompact_SaveBookmarks );
|
|
saveHistory->setChecked( taseditorConfig.saveCompact_SaveHistory );
|
|
savePianoRoll->setChecked( taseditorConfig.saveCompact_SavePianoRoll );
|
|
saveSelection->setChecked( taseditorConfig.saveCompact_SaveSelection );
|
|
|
|
allFrames->setChecked( taseditorConfig.saveCompact_GreenzoneSavingMode == GREENZONE_SAVING_MODE_ALL );
|
|
every16thFrame->setChecked( taseditorConfig.saveCompact_GreenzoneSavingMode == GREENZONE_SAVING_MODE_16TH );
|
|
markedFrames->setChecked( taseditorConfig.saveCompact_GreenzoneSavingMode == GREENZONE_SAVING_MODE_MARKED );
|
|
dontSave->setChecked( taseditorConfig.saveCompact_GreenzoneSavingMode == GREENZONE_SAVING_MODE_NO );
|
|
|
|
okButton->setDefault(true);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret == QDialog::Accepted )
|
|
{
|
|
QString filename;
|
|
|
|
taseditorConfig.saveCompact_SaveInBinary = binaryInput->isChecked();
|
|
taseditorConfig.saveCompact_SaveMarkers = saveMarkers->isChecked();
|
|
taseditorConfig.saveCompact_SaveBookmarks = saveBookmarks->isChecked();
|
|
taseditorConfig.saveCompact_SaveHistory = saveHistory->isChecked();
|
|
taseditorConfig.saveCompact_SavePianoRoll = savePianoRoll->isChecked();
|
|
taseditorConfig.saveCompact_SaveSelection = saveSelection->isChecked();
|
|
|
|
if ( allFrames->isChecked() )
|
|
{
|
|
taseditorConfig.saveCompact_GreenzoneSavingMode = GREENZONE_SAVING_MODE_ALL;
|
|
}
|
|
else if ( every16thFrame->isChecked() )
|
|
{
|
|
taseditorConfig.saveCompact_GreenzoneSavingMode = GREENZONE_SAVING_MODE_16TH;
|
|
}
|
|
else if ( markedFrames->isChecked() )
|
|
{
|
|
taseditorConfig.saveCompact_GreenzoneSavingMode = GREENZONE_SAVING_MODE_MARKED;
|
|
}
|
|
else
|
|
{
|
|
taseditorConfig.saveCompact_GreenzoneSavingMode = GREENZONE_SAVING_MODE_NO;
|
|
}
|
|
|
|
if ( saveCompactGetFilename( filename ) )
|
|
{
|
|
project.save(filename.toLocal8Bit().constData(), taseditorConfig.saveCompact_SaveInBinary, taseditorConfig.saveCompact_SaveMarkers, taseditorConfig.saveCompact_SaveBookmarks, taseditorConfig.saveCompact_GreenzoneSavingMode, taseditorConfig.saveCompact_SaveHistory, taseditorConfig.saveCompact_SavePianoRoll, taseditorConfig.saveCompact_SaveSelection);
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::openOnlineDocs(void)
|
|
{
|
|
if ( QDesktopServices::openUrl( QUrl("https://fceux.com/web/help/taseditor/Title.html") ) == false )
|
|
{
|
|
QMessageBox::critical( this, tr("Error"),
|
|
tr("Error: Failed to open link to: https://fceux.com/web/help/taseditor/Title.html") );
|
|
}
|
|
return;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::setCurrentPattern(int idx)
|
|
{
|
|
if ( idx < 0 )
|
|
{
|
|
return;
|
|
}
|
|
if ( (size_t)idx >= patternsNames.size() )
|
|
{
|
|
return;
|
|
}
|
|
//printf("Set Pattern: %i\n", idx);
|
|
taseditorConfig.currentPattern = idx;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::recordingChanged(int newState)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int oldState = !movie_readonly ? Qt::Checked : Qt::Unchecked;
|
|
|
|
if ( newState != oldState )
|
|
{
|
|
FCEUI_MovieToggleReadOnly();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editUndoCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
history.undo();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editRedoCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
history.redo();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editUndoSelCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.undo();
|
|
pianoRoll->followSelection();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editRedoSelCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.redo();
|
|
pianoRoll->followSelection();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editDeselectAll(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.clearAllRowsSelection();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editSelectAll(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.selectAllRows();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editSelBtwMkrs(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.selectAllRowsBetweenMarkers();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editReselectClipboard(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.reselectClipboard();
|
|
pianoRoll->followSelection();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editCutCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.cutSelectedInputToClipboard();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editCopyCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.copySelectedInputToClipboard();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editPasteCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.pasteInputFromClipboard();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editPasteInsertCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.pasteInsertInputFromClipboard();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editClearCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.clearSelectedFrames();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editDeleteCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.deleteSelectedFrames();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editCloneCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.cloneSelectedFrames();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editInsertCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.insertSelectedFrames();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editInsertNumFramesCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.insertNumberOfFrames();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::editTruncateMovieCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
splicer.truncateMovie();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::superImposedChanged(int state)
|
|
{
|
|
if ( state == Qt::Checked )
|
|
{
|
|
taseditorConfig.superimpose = SUPERIMPOSE_CHECKED;
|
|
}
|
|
else if ( state == Qt::PartiallyChecked )
|
|
{
|
|
taseditorConfig.superimpose = SUPERIMPOSE_INDETERMINATE;
|
|
}
|
|
else
|
|
{
|
|
taseditorConfig.superimpose = SUPERIMPOSE_UNCHECKED;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::usePatternChanged(int state)
|
|
{
|
|
taseditorConfig.recordingUsePattern ^= 1;
|
|
recorder.patternOffset = 0;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::recordInputChanged(int input)
|
|
{
|
|
//printf("Input Change: %i\n", input);
|
|
recorder.multitrackRecordingJoypadNumber = input;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::openFindNoteWindow(void)
|
|
{
|
|
if ( findWin )
|
|
{
|
|
findWin->activateWindow();
|
|
findWin->raise();
|
|
}
|
|
else
|
|
{
|
|
findWin = new TasFindNoteWindow(this);
|
|
findWin->show();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::dpyBrnchScrnChanged(bool val)
|
|
{
|
|
taseditorConfig.displayBranchScreenshots = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::dpyBrnchDescChanged(bool val)
|
|
{
|
|
taseditorConfig.displayBranchDescriptions = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::enaHotChgChanged(bool val)
|
|
{
|
|
taseditorConfig.enableHotChanges = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::followUndoActChanged(bool val)
|
|
{
|
|
taseditorConfig.followUndoContext = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::followMkrActChanged(bool val)
|
|
{
|
|
taseditorConfig.followMarkerNoteContext = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::enaGrnznActChanged(bool val)
|
|
{
|
|
taseditorConfig.enableGreenzoning = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::afPtrnSkipLagActChanged(bool val)
|
|
{
|
|
taseditorConfig.autofirePatternSkipsLag = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::adjInputLagActChanged(bool val)
|
|
{
|
|
taseditorConfig.autoAdjustInputAccordingToLag = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::drawInputDragActChanged(bool val)
|
|
{
|
|
taseditorConfig.drawInputByDragging = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::cmbRecDrawActChanged(bool val)
|
|
{
|
|
taseditorConfig.combineConsecutiveRecordingsAndDraws = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::use1PforRecActChanged(bool val)
|
|
{
|
|
taseditorConfig.use1PKeysForAllSingleRecordings = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::useInputColSetActChanged(bool val)
|
|
{
|
|
taseditorConfig.useInputKeysForColumnSet = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::bindMkrInputActChanged(bool val)
|
|
{
|
|
taseditorConfig.bindMarkersToInput = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::emptyNewMkrNotesActChanged(bool val)
|
|
{
|
|
taseditorConfig.emptyNewMarkerNotes = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::oldCtlBrnhSchemeActChanged(bool val)
|
|
{
|
|
taseditorConfig.oldControlSchemeForBranching = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::brnchRestoreMovieActChanged(bool val)
|
|
{
|
|
taseditorConfig.branchesRestoreEntireMovie = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::hudInScrnBranchActChanged(bool val)
|
|
{
|
|
taseditorConfig.HUDInBranchScreenshots = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::pauseAtEndActChanged(bool val)
|
|
{
|
|
taseditorConfig.autopauseAtTheEndOfMovie = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::manLuaRun(void)
|
|
{
|
|
mustCallManualLuaFunction = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::autoLuaRunChanged(bool val)
|
|
{
|
|
taseditorConfig.enableLuaAutoFunction = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::showToolTipsActChanged(bool val)
|
|
{
|
|
taseditorConfig.tooltipsEnabled = val;
|
|
|
|
updateToolTips();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::updateToolTips(void)
|
|
{
|
|
if ( taseditorConfig.tooltipsEnabled )
|
|
{
|
|
upperMarkerLabel->setToolTip( tr("Click here to scroll Piano Roll to Playback cursor") );
|
|
lowerMarkerLabel->setToolTip( tr("Click here to scroll Piano Roll to Selection") );
|
|
upperMarkerNote->setToolTip( tr("Click to edit text") );
|
|
lowerMarkerNote->setToolTip( tr("Click to edit text") );
|
|
|
|
recRecordingCbox->setToolTip( tr("Switch Input Recording on/off") );
|
|
recSuperImposeCbox->setToolTip( tr("Allows to superimpose old Input with new buttons, instead of overwriting") );
|
|
recUsePatternCbox->setToolTip( tr("Applies current Autofire Pattern to Input recording") );
|
|
recAllBtn->setToolTip( tr("Switch off Multitracking") );
|
|
rec1PBtn->setToolTip( tr("Select Joypad 1 as Current") );
|
|
rec2PBtn->setToolTip( tr("Select Joypad 2 as Current") );
|
|
rec3PBtn->setToolTip( tr("Select Joypad 3 as Current") );
|
|
rec4PBtn->setToolTip( tr("Select Joypad 4 as Current") );
|
|
|
|
rewindMkrBtn->setToolTip( tr("Send Playback to previous Marker (mouse: Shift+Wheel up) (hotkey: Shift+PageUp)") );
|
|
rewindFrmBtn->setToolTip( tr("Rewind 1 frame (mouse: Right button+Wheel up) (hotkey: Shift+Up)") );
|
|
playPauseBtn->setToolTip( tr("Pause/Unpause Emulation (mouse: Middle button)") );
|
|
advFrmBtn->setToolTip( tr("Advance 1 frame (mouse: Right button+Wheel down) (hotkey: Shift+Down)") );
|
|
advMkrBtn->setToolTip( tr("Send Playback to next Marker (mouse: Shift+Wheel down) (hotkey: Shift+PageDown)") );
|
|
|
|
followCursorCbox->setToolTip( tr("The Piano Roll will follow Playback cursor movements") );
|
|
turboSeekCbox->setToolTip( tr("Uncheck when you need to watch seeking in slow motion") );
|
|
autoRestoreCbox->setToolTip( tr("Whenever you change Input above Playback cursor, the cursor returns to where it was before the change") );
|
|
|
|
selectionLbl->setToolTip( tr("Current size of Selection") );
|
|
clipboardLbl->setToolTip( tr("Current size of Input in the Clipboard") );
|
|
|
|
prevMkrBtn->setToolTip( tr("Send Selection to previous Marker (mouse: Ctrl+Wheel up) (hotkey: Ctrl+PageUp)") );
|
|
nextMkrBtn->setToolTip( tr("Send Selection to next Marker (mouse: Ctrl+Wheel up) (hotkey: Ctrl+PageDown)") );
|
|
similarBtn->setToolTip( tr("Auto-search for Marker Note") );
|
|
moreBtn->setToolTip( tr("Continue Auto-search") );
|
|
}
|
|
else
|
|
{
|
|
upperMarkerLabel->setToolTip( tr("") );
|
|
lowerMarkerLabel->setToolTip( tr("") );
|
|
upperMarkerNote->setToolTip( tr("") );
|
|
lowerMarkerNote->setToolTip( tr("") );
|
|
|
|
recRecordingCbox->setToolTip( tr("") );
|
|
recSuperImposeCbox->setToolTip( tr("") );
|
|
recUsePatternCbox->setToolTip( tr("") );
|
|
recAllBtn->setToolTip( tr("") );
|
|
rec1PBtn->setToolTip( tr("") );
|
|
rec2PBtn->setToolTip( tr("") );
|
|
rec3PBtn->setToolTip( tr("") );
|
|
rec4PBtn->setToolTip( tr("") );
|
|
|
|
rewindMkrBtn->setToolTip( tr("") );
|
|
rewindFrmBtn->setToolTip( tr("") );
|
|
playPauseBtn->setToolTip( tr("") );
|
|
advFrmBtn->setToolTip( tr("") );
|
|
advMkrBtn->setToolTip( tr("") );
|
|
|
|
followCursorCbox->setToolTip( tr("") );
|
|
turboSeekCbox->setToolTip( tr("") );
|
|
autoRestoreCbox->setToolTip( tr("") );
|
|
|
|
selectionLbl->setToolTip( tr("") );
|
|
clipboardLbl->setToolTip( tr("") );
|
|
|
|
prevMkrBtn->setToolTip( tr("") );
|
|
nextMkrBtn->setToolTip( tr("") );
|
|
similarBtn->setToolTip( tr("") );
|
|
moreBtn->setToolTip( tr("") );
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::changePianoRollFontCB(void)
|
|
{
|
|
bool ok = false;
|
|
|
|
QFont selFont = QFontDialog::getFont( &ok, pianoRoll->QWidget::font(), this, tr("Select Font"), QFontDialog::MonospacedFonts );
|
|
|
|
if ( ok )
|
|
{
|
|
pianoRoll->setFont( selFont );
|
|
|
|
//printf("Font Changed to: '%s'\n", selFont.toString().toLocal8Bit().constData() );
|
|
|
|
g_config->setOption("SDL.TasPianoRollFont", selFont.toString().toLocal8Bit().constData() );
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::changeBookmarksFontCB(void)
|
|
{
|
|
bool ok = false;
|
|
|
|
QFont selFont = QFontDialog::getFont( &ok, bookmarks.QWidget::font(), this, tr("Select Font"), QFontDialog::MonospacedFonts );
|
|
|
|
if ( ok )
|
|
{
|
|
bookmarks.setFont( selFont );
|
|
|
|
//printf("Font Changed to: '%s'\n", selFont.toString().toLocal8Bit().constData() );
|
|
|
|
g_config->setOption("SDL.TasBookmarksFont", selFont.toString().toLocal8Bit().constData() );
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::changeBranchesFontCB(void)
|
|
{
|
|
bool ok = false;
|
|
|
|
QFont selFont = QFontDialog::getFont( &ok, branches.QWidget::font(), this, tr("Select Font"), QFontDialog::MonospacedFonts );
|
|
|
|
if ( ok )
|
|
{
|
|
branches.setFont( selFont );
|
|
|
|
//printf("Font Changed to: '%s'\n", selFont.toString().toLocal8Bit().constData() );
|
|
|
|
g_config->setOption("SDL.TasBranchesFont", selFont.toString().toLocal8Bit().constData() );
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackPauseCB(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
playback.toggleEmulationPause();
|
|
pianoRoll->update();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackFrameRewind(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
playback.handleRewindFrame();
|
|
pianoRoll->update();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackFrameForward(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
playback.handleForwardFrame();
|
|
pianoRoll->update();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackFrameRewindFull(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
playback.handleRewindFull();
|
|
pianoRoll->update();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackFrameForwardFull(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
playback.handleForwardFull();
|
|
pianoRoll->update();
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackFollowCursorCb(bool val)
|
|
{
|
|
taseditorConfig.followPlaybackCursor = val;
|
|
|
|
if ( val )
|
|
{
|
|
pianoRoll->ensureTheLineIsVisible( currFrameCounter );
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackTurboSeekCb(bool val)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
taseditorConfig.turboSeek = val;
|
|
|
|
// if currently seeking, apply this option immediately
|
|
if (playback.getPauseFrame() >= 0)
|
|
{
|
|
turbo = taseditorConfig.turboSeek;
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::playbackAutoRestoreCb(bool val)
|
|
{
|
|
taseditorConfig.autoRestoreLastPlaybackPosition = val;
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::scrollSelectionUpOne(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
//printf("DragMode: %i\n", dragMode);
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.transposeVertically(-1);
|
|
int selectionBeginning = selection.getCurrentRowsSelectionBeginning();
|
|
if (selectionBeginning >= 0)
|
|
{
|
|
pianoRoll->ensureTheLineIsVisible(selectionBeginning);
|
|
}
|
|
pianoRoll->update();
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::scrollSelectionDnOne(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
//printf("DragMode: %i\n", dragMode);
|
|
|
|
if ( (dragMode != DRAG_MODE_SELECTION) && (dragMode != DRAG_MODE_DESELECTION) )
|
|
{
|
|
selection.transposeVertically(1);
|
|
int selectionEnd = selection.getCurrentRowsSelectionEnd();
|
|
if (selectionEnd >= 0)
|
|
{
|
|
pianoRoll->ensureTheLineIsVisible(selectionEnd);
|
|
}
|
|
pianoRoll->update();
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::histTreeItemActivated(QTreeWidgetItem *item, int col)
|
|
{
|
|
int row = histTree->indexOfTopLevelItem(item);
|
|
|
|
if ( row < 0 )
|
|
{
|
|
return;
|
|
}
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
history.handleSingleClick(row);
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::tabViewChanged(int idx)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
taseditorConfig.displayBranchesTree = (idx == 1);
|
|
bookmarks.redrawBookmarksSectionCaption();
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::openProjectSaveOptions(void)
|
|
{
|
|
int ret;
|
|
QDialog dialog(this);
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
QGroupBox *settingsBox, *fileContentsBox, *greenZoneSaveBox;
|
|
QVBoxLayout *mainLayout, *vbox1, *vbox;
|
|
QHBoxLayout *hbox1, *hbox;
|
|
QCheckBox *autoSaveOpt, *saveSilentOpt;
|
|
QSpinBox *autoSavePeriod;
|
|
QCheckBox *binaryInput, *saveMarkers, *saveBookmarks;
|
|
QCheckBox *saveHistory, *savePianoRoll, *saveSelection;
|
|
QRadioButton *allFrames, *every16thFrame, *markedFrames, *dontSave;
|
|
QPushButton *okButton, *cancelButton;
|
|
|
|
dialog.setWindowTitle( tr("Project File Saving Options") );
|
|
|
|
mainLayout = new QVBoxLayout();
|
|
settingsBox = new QGroupBox( tr("Settings") );
|
|
fileContentsBox = new QGroupBox( tr("File Contents") );
|
|
greenZoneSaveBox = new QGroupBox( tr("Greenzone Saving Options") );
|
|
hbox1 = new QHBoxLayout();
|
|
|
|
autoSaveOpt = new QCheckBox( tr("Autosave project") );
|
|
saveSilentOpt = new QCheckBox( tr("silently") );
|
|
autoSavePeriod = new QSpinBox();
|
|
|
|
binaryInput = new QCheckBox( tr("Binary Input") );
|
|
saveMarkers = new QCheckBox( tr("Markers") );
|
|
saveBookmarks = new QCheckBox( tr("Bookmarks") );
|
|
saveHistory = new QCheckBox( tr("History") );
|
|
savePianoRoll = new QCheckBox( tr("Piano Roll") );
|
|
saveSelection = new QCheckBox( tr("Selection") );
|
|
|
|
allFrames = new QRadioButton( tr("All Frames") );
|
|
every16thFrame = new QRadioButton( tr("Every 16th Frame") );
|
|
markedFrames = new QRadioButton( tr("Marked Frame") );
|
|
dontSave = new QRadioButton( tr("Don't Save") );
|
|
|
|
okButton = new QPushButton( tr("Ok") );
|
|
cancelButton = new QPushButton( tr("Cancel") );
|
|
|
|
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogApplyButton ) );
|
|
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
|
|
|
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
|
|
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
|
|
|
|
hbox1->addWidget( settingsBox );
|
|
hbox1->addWidget( fileContentsBox );
|
|
|
|
dialog.setLayout( mainLayout );
|
|
mainLayout->addLayout( hbox1 );
|
|
|
|
vbox = new QVBoxLayout();
|
|
hbox = new QHBoxLayout();
|
|
settingsBox->setLayout( vbox );
|
|
|
|
hbox->addWidget( new QLabel( tr("every") ) );
|
|
hbox->addWidget( autoSavePeriod );
|
|
hbox->addWidget( new QLabel( tr("minutes") ) );
|
|
|
|
vbox->addWidget( autoSaveOpt );
|
|
vbox->addLayout( hbox );
|
|
vbox->addWidget( saveSilentOpt );
|
|
vbox->addStretch( 10 );
|
|
|
|
vbox1 = new QVBoxLayout();
|
|
fileContentsBox->setLayout( vbox1 );
|
|
|
|
vbox1->addWidget( binaryInput );
|
|
vbox1->addWidget( saveMarkers );
|
|
vbox1->addWidget( saveBookmarks );
|
|
vbox1->addWidget( saveHistory );
|
|
vbox1->addWidget( savePianoRoll );
|
|
vbox1->addWidget( saveSelection );
|
|
vbox1->addWidget( greenZoneSaveBox );
|
|
|
|
vbox = new QVBoxLayout();
|
|
greenZoneSaveBox->setLayout( vbox );
|
|
|
|
vbox->addWidget( allFrames );
|
|
vbox->addWidget( every16thFrame );
|
|
vbox->addWidget( markedFrames );
|
|
vbox->addWidget( dontSave );
|
|
|
|
hbox1 = new QHBoxLayout();
|
|
mainLayout->addLayout( hbox1 );
|
|
hbox1->addStretch(5);
|
|
hbox1->addWidget( okButton );
|
|
hbox1->addWidget( cancelButton );
|
|
|
|
autoSavePeriod->setRange( AUTOSAVE_PERIOD_MIN, AUTOSAVE_PERIOD_MAX );
|
|
|
|
autoSaveOpt->setChecked( taseditorConfig.autosaveEnabled );
|
|
autoSavePeriod->setValue( taseditorConfig.autosavePeriod );
|
|
saveSilentOpt->setChecked( taseditorConfig.autosaveSilent );
|
|
|
|
autoSavePeriod->setEnabled( taseditorConfig.autosaveEnabled );
|
|
saveSilentOpt->setEnabled( taseditorConfig.autosaveEnabled );
|
|
|
|
binaryInput->setChecked( taseditorConfig.projectSavingOptions_SaveInBinary );
|
|
saveMarkers->setChecked( taseditorConfig.projectSavingOptions_SaveMarkers );
|
|
saveBookmarks->setChecked( taseditorConfig.projectSavingOptions_SaveBookmarks );
|
|
saveHistory->setChecked( taseditorConfig.projectSavingOptions_SaveHistory );
|
|
savePianoRoll->setChecked( taseditorConfig.projectSavingOptions_SavePianoRoll );
|
|
saveSelection->setChecked( taseditorConfig.projectSavingOptions_SaveSelection );
|
|
|
|
allFrames->setChecked( taseditorConfig.projectSavingOptions_GreenzoneSavingMode == GREENZONE_SAVING_MODE_ALL );
|
|
every16thFrame->setChecked( taseditorConfig.projectSavingOptions_GreenzoneSavingMode == GREENZONE_SAVING_MODE_16TH );
|
|
markedFrames->setChecked( taseditorConfig.projectSavingOptions_GreenzoneSavingMode == GREENZONE_SAVING_MODE_MARKED );
|
|
dontSave->setChecked( taseditorConfig.projectSavingOptions_GreenzoneSavingMode == GREENZONE_SAVING_MODE_NO );
|
|
|
|
connect( autoSaveOpt, SIGNAL(clicked(bool)), autoSavePeriod, SLOT(setEnabled(bool)) );
|
|
connect( autoSaveOpt, SIGNAL(clicked(bool)), saveSilentOpt , SLOT(setEnabled(bool)) );
|
|
|
|
okButton->setDefault(true);
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret == QDialog::Accepted )
|
|
{
|
|
taseditorConfig.autosaveEnabled = autoSaveOpt->isChecked();
|
|
taseditorConfig.autosavePeriod = autoSavePeriod->value();
|
|
taseditorConfig.autosaveSilent = saveSilentOpt->isChecked();
|
|
|
|
taseditorConfig.projectSavingOptions_SaveInBinary = binaryInput->isChecked();
|
|
taseditorConfig.projectSavingOptions_SaveMarkers = saveMarkers->isChecked();
|
|
taseditorConfig.projectSavingOptions_SaveBookmarks = saveBookmarks->isChecked();
|
|
taseditorConfig.projectSavingOptions_SaveHistory = saveHistory->isChecked();
|
|
taseditorConfig.projectSavingOptions_SavePianoRoll = savePianoRoll->isChecked();
|
|
taseditorConfig.projectSavingOptions_SaveSelection = saveSelection->isChecked();
|
|
|
|
if ( allFrames->isChecked() )
|
|
{
|
|
taseditorConfig.projectSavingOptions_GreenzoneSavingMode = GREENZONE_SAVING_MODE_ALL;
|
|
}
|
|
else if ( every16thFrame->isChecked() )
|
|
{
|
|
taseditorConfig.projectSavingOptions_GreenzoneSavingMode = GREENZONE_SAVING_MODE_16TH;
|
|
}
|
|
else if ( markedFrames->isChecked() )
|
|
{
|
|
taseditorConfig.projectSavingOptions_GreenzoneSavingMode = GREENZONE_SAVING_MODE_MARKED;
|
|
}
|
|
else
|
|
{
|
|
taseditorConfig.projectSavingOptions_GreenzoneSavingMode = GREENZONE_SAVING_MODE_NO;
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::setGreenzoneCapacity(void)
|
|
{
|
|
int ret;
|
|
int newValue = taseditorConfig.greenzoneCapacity;
|
|
QInputDialog dialog(this);
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
dialog.setWindowTitle( tr("Greenzone Capacity") );
|
|
dialog.setInputMode( QInputDialog::IntInput );
|
|
dialog.setIntRange( GREENZONE_CAPACITY_MIN, GREENZONE_CAPACITY_MAX );
|
|
dialog.setLabelText( tr("Keep savestates for how many frames?\n(actual limit of savestates can be 5 times more than the number provided)") );
|
|
dialog.setIntValue( newValue );
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret == QDialog::Accepted )
|
|
{
|
|
newValue = dialog.intValue();
|
|
|
|
if (newValue < GREENZONE_CAPACITY_MIN)
|
|
{
|
|
newValue = GREENZONE_CAPACITY_MIN;
|
|
}
|
|
else if (newValue > GREENZONE_CAPACITY_MAX)
|
|
{
|
|
newValue = GREENZONE_CAPACITY_MAX;
|
|
}
|
|
if (newValue < taseditorConfig.greenzoneCapacity)
|
|
{
|
|
taseditorConfig.greenzoneCapacity = newValue;
|
|
greenzone.runGreenzoneCleaning();
|
|
}
|
|
else
|
|
{
|
|
taseditorConfig.greenzoneCapacity = newValue;
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::setMaxUndoCapacity(void)
|
|
{
|
|
int ret;
|
|
int newValue = taseditorConfig.maxUndoLevels;
|
|
QInputDialog dialog(this);
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
dialog.setWindowTitle( tr("Max undo levels") );
|
|
dialog.setInputMode( QInputDialog::IntInput );
|
|
dialog.setIntRange( UNDO_LEVELS_MIN, UNDO_LEVELS_MAX );
|
|
dialog.setLabelText( tr("Keep history of how many changes?") );
|
|
dialog.setIntValue( newValue );
|
|
|
|
ret = dialog.exec();
|
|
|
|
if ( ret == QDialog::Accepted )
|
|
{
|
|
newValue = dialog.intValue();
|
|
|
|
if (newValue < UNDO_LEVELS_MIN)
|
|
{
|
|
newValue = UNDO_LEVELS_MIN;
|
|
}
|
|
else if (newValue > UNDO_LEVELS_MAX)
|
|
{
|
|
newValue = UNDO_LEVELS_MAX;
|
|
}
|
|
if (newValue != taseditorConfig.maxUndoLevels)
|
|
{
|
|
taseditorConfig.maxUndoLevels = newValue;
|
|
history.updateHistoryLogSize();
|
|
selection.updateHistoryLogSize();
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
void TasEditorWindow::loadClipboard(const char *txt)
|
|
{
|
|
clipboard->setText( tr(txt), QClipboard::Clipboard );
|
|
|
|
if ( clipboard->supportsSelection() )
|
|
{
|
|
clipboard->setText( tr(txt), QClipboard::Selection );
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------
|
|
// following functions use function parameters to determine range of frames
|
|
void TasEditorWindow::toggleInput(int start, int end, int joy, int button, int consecutivenessTag)
|
|
{
|
|
if (joy < 0 || joy >= joysticksPerFrame[getInputType(currMovieData)]) return;
|
|
|
|
int check_frame = end;
|
|
if (start > end)
|
|
{
|
|
// swap
|
|
int temp_start = start;
|
|
start = end;
|
|
end = temp_start;
|
|
}
|
|
if (start < 0) start = end;
|
|
if (end >= currMovieData.getNumRecords())
|
|
return;
|
|
|
|
if (currMovieData.records[check_frame].checkBit(joy, button))
|
|
{
|
|
// clear range
|
|
for (int i = start; i <= end; ++i)
|
|
currMovieData.records[i].clearBit(joy, button);
|
|
greenzone.invalidateAndUpdatePlayback(history.registerChanges(MODTYPE_UNSET, start, end, 0, NULL, consecutivenessTag));
|
|
} else
|
|
{
|
|
// set range
|
|
for (int i = start; i <= end; ++i)
|
|
currMovieData.records[i].setBit(joy, button);
|
|
greenzone.invalidateAndUpdatePlayback(history.registerChanges(MODTYPE_SET, start, end, 0, NULL, consecutivenessTag));
|
|
}
|
|
}
|
|
void TasEditorWindow::setInputUsingPattern(int start, int end, int joy, int button, int consecutivenessTag)
|
|
{
|
|
if (joy < 0 || joy >= joysticksPerFrame[getInputType(currMovieData)]) return;
|
|
|
|
if (start > end)
|
|
{
|
|
// swap
|
|
int temp_start = start;
|
|
start = end;
|
|
end = temp_start;
|
|
}
|
|
if (start < 0) start = end;
|
|
if (end >= currMovieData.getNumRecords())
|
|
{
|
|
return;
|
|
}
|
|
|
|
int pattern_offset = 0, current_pattern = taseditorConfig.currentPattern;
|
|
bool changes_made = false;
|
|
bool value;
|
|
|
|
for (int i = start; i <= end; ++i)
|
|
{
|
|
// skip lag frames
|
|
if (taseditorConfig.autofirePatternSkipsLag && greenzone.lagLog.getLagInfoAtFrame(i) == LAGGED_YES)
|
|
{
|
|
continue;
|
|
}
|
|
value = (patterns[current_pattern][pattern_offset] != 0);
|
|
if (currMovieData.records[i].checkBit(joy, button) != value)
|
|
{
|
|
changes_made = true;
|
|
currMovieData.records[i].setBitValue(joy, button, value);
|
|
}
|
|
pattern_offset++;
|
|
if (pattern_offset >= (int)patterns[current_pattern].size())
|
|
{
|
|
pattern_offset -= patterns[current_pattern].size();
|
|
}
|
|
}
|
|
if (changes_made)
|
|
{
|
|
greenzone.invalidateAndUpdatePlayback(history.registerChanges(MODTYPE_PATTERN, start, end, 0, patternsNames[current_pattern].c_str(), consecutivenessTag));
|
|
}
|
|
}
|
|
|
|
// following functions use current Selection to determine range of frames
|
|
bool TasEditorWindow::handleColumnSet(void)
|
|
{
|
|
RowsSelection* current_selection = selection.getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size() == 0) return false;
|
|
RowsSelection::iterator current_selection_begin(current_selection->begin());
|
|
RowsSelection::iterator current_selection_end(current_selection->end());
|
|
|
|
// inspect the selected frames, if they are all set, then unset all, else set all
|
|
bool unset_found = false, changes_made = false;
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
if (!markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
unset_found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (unset_found)
|
|
{
|
|
// set all
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
if (!markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
if (markersManager.setMarkerAtFrame(*it))
|
|
{
|
|
changes_made = true;
|
|
//pianoRoll.redrawRow(*it);
|
|
//pianoRoll->update(); // Piano roll will update at next periodic cycle
|
|
lowerMarkerNote->setFocus();
|
|
}
|
|
}
|
|
}
|
|
if (changes_made)
|
|
{
|
|
history.registerMarkersChange(MODTYPE_MARKER_SET, *current_selection_begin, *current_selection->rbegin());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// unset all
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
if (markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
markersManager.removeMarkerFromFrame(*it);
|
|
changes_made = true;
|
|
//pianoRoll.redrawRow(*it);
|
|
//pianoRoll->update(); // Piano roll will update at next periodic cycle
|
|
}
|
|
}
|
|
if (changes_made)
|
|
{
|
|
history.registerMarkersChange(MODTYPE_MARKER_REMOVE, *current_selection_begin, *current_selection->rbegin());
|
|
}
|
|
}
|
|
if (changes_made)
|
|
{
|
|
selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true;
|
|
}
|
|
return changes_made;
|
|
}
|
|
|
|
bool TasEditorWindow::handleColumnSetUsingPattern(void)
|
|
{
|
|
RowsSelection* current_selection = selection.getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size() == 0) return false;
|
|
RowsSelection::iterator current_selection_begin(current_selection->begin());
|
|
RowsSelection::iterator current_selection_end(current_selection->end());
|
|
int pattern_offset = 0, current_pattern = taseditorConfig.currentPattern;
|
|
bool changes_made = false;
|
|
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
// skip lag frames
|
|
if (taseditorConfig.autofirePatternSkipsLag && greenzone.lagLog.getLagInfoAtFrame(*it) == LAGGED_YES)
|
|
continue;
|
|
if (patterns[current_pattern][pattern_offset])
|
|
{
|
|
if (!markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
if (markersManager.setMarkerAtFrame(*it))
|
|
{
|
|
changes_made = true;
|
|
pianoRoll->update();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
markersManager.removeMarkerFromFrame(*it);
|
|
changes_made = true;
|
|
pianoRoll->update();
|
|
}
|
|
}
|
|
pattern_offset++;
|
|
if (pattern_offset >= (int)patterns[current_pattern].size())
|
|
pattern_offset -= patterns[current_pattern].size();
|
|
}
|
|
if (changes_made)
|
|
{
|
|
history.registerMarkersChange(MODTYPE_MARKER_PATTERN, *current_selection_begin, *current_selection->rbegin(), patternsNames[current_pattern].c_str());
|
|
selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool TasEditorWindow::handleInputColumnSetUsingPattern(int joy, int button)
|
|
{
|
|
if (joy < 0 || joy >= joysticksPerFrame[getInputType(currMovieData)]) return false;
|
|
|
|
RowsSelection* current_selection = selection.getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size() == 0) return false;
|
|
RowsSelection::iterator current_selection_begin(current_selection->begin());
|
|
RowsSelection::iterator current_selection_end(current_selection->end());
|
|
int pattern_offset = 0, current_pattern = taseditorConfig.currentPattern;
|
|
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
// skip lag frames
|
|
if (taseditorConfig.autofirePatternSkipsLag && greenzone.lagLog.getLagInfoAtFrame(*it) == LAGGED_YES)
|
|
continue;
|
|
currMovieData.records[*it].setBitValue(joy, button, patterns[current_pattern][pattern_offset] != 0);
|
|
pattern_offset++;
|
|
if (pattern_offset >= (int)patterns[current_pattern].size())
|
|
pattern_offset -= patterns[current_pattern].size();
|
|
}
|
|
int first_changes = history.registerChanges(MODTYPE_PATTERN, *current_selection_begin, *current_selection->rbegin(), 0, patternsNames[current_pattern].c_str());
|
|
if (first_changes >= 0)
|
|
{
|
|
greenzone.invalidateAndUpdatePlayback(first_changes);
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
bool TasEditorWindow::handleInputColumnSet(int joy, int button)
|
|
{
|
|
if (joy < 0 || joy >= joysticksPerFrame[getInputType(currMovieData)]) return false;
|
|
|
|
RowsSelection* current_selection = selection.getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size() == 0) return false;
|
|
RowsSelection::iterator current_selection_begin(current_selection->begin());
|
|
RowsSelection::iterator current_selection_end(current_selection->end());
|
|
|
|
//inspect the selected frames, if they are all set, then unset all, else set all
|
|
bool newValue = false;
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
if (!(currMovieData.records[*it].checkBit(joy,button)))
|
|
{
|
|
newValue = true;
|
|
break;
|
|
}
|
|
}
|
|
// apply newValue
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
currMovieData.records[*it].setBitValue(joy,button,newValue);
|
|
|
|
int first_changes;
|
|
if (newValue)
|
|
{
|
|
first_changes = history.registerChanges(MODTYPE_SET, *current_selection_begin, *current_selection->rbegin());
|
|
} else
|
|
{
|
|
first_changes = history.registerChanges(MODTYPE_UNSET, *current_selection_begin, *current_selection->rbegin());
|
|
}
|
|
if (first_changes >= 0)
|
|
{
|
|
greenzone.invalidateAndUpdatePlayback(first_changes);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void TasEditorWindow::setMarkers(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
RowsSelection* current_selection = selection.getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size())
|
|
{
|
|
RowsSelection::iterator current_selection_begin(current_selection->begin());
|
|
RowsSelection::iterator current_selection_end(current_selection->end());
|
|
bool changes_made = false;
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
if (!markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
if (markersManager.setMarkerAtFrame(*it))
|
|
{
|
|
changes_made = true;
|
|
//pianoRoll->update();
|
|
}
|
|
}
|
|
}
|
|
if (changes_made)
|
|
{
|
|
selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true;
|
|
history.registerMarkersChange(MODTYPE_MARKER_SET, *current_selection_begin, *current_selection->rbegin());
|
|
}
|
|
}
|
|
}
|
|
void TasEditorWindow::removeMarkers(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
RowsSelection* current_selection = selection.getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size())
|
|
{
|
|
RowsSelection::iterator current_selection_begin(current_selection->begin());
|
|
RowsSelection::iterator current_selection_end(current_selection->end());
|
|
bool changes_made = false;
|
|
for(RowsSelection::iterator it(current_selection_begin); it != current_selection_end; it++)
|
|
{
|
|
if (markersManager.getMarkerAtFrame(*it))
|
|
{
|
|
markersManager.removeMarkerFromFrame(*it);
|
|
changes_made = true;
|
|
//pianoRoll->update();
|
|
}
|
|
}
|
|
if (changes_made)
|
|
{
|
|
selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true;
|
|
history.registerMarkersChange(MODTYPE_MARKER_REMOVE, *current_selection_begin, *current_selection->rbegin());
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::ungreenzoneSelectedFrames(void)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
greenzone.ungreenzoneSelectedFrames();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::upperMarkerLabelClicked(void)
|
|
{
|
|
pianoRoll->followPlaybackCursor();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::lowerMarkerLabelClicked(void)
|
|
{
|
|
int dragMode = pianoRoll->getDragMode();
|
|
|
|
if (dragMode != DRAG_MODE_SELECTION && dragMode != DRAG_MODE_DESELECTION)
|
|
{
|
|
pianoRoll->followSelection();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::jumpToPreviousMarker(void)
|
|
{
|
|
selection.jumpToPreviousMarker();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::jumpToNextMarker(void)
|
|
{
|
|
selection.jumpToNextMarker();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::findSimilarNote(void)
|
|
{
|
|
markersManager.findSimilarNote();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::findNextSimilarNote(void)
|
|
{
|
|
markersManager.findNextSimilarNote();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorWindow::openAboutWindow(void)
|
|
{
|
|
QDialog about(this);
|
|
QVBoxLayout *mainLayout, *vbox;
|
|
QHBoxLayout *hbox;
|
|
QPixmap pm(":icons/taseditor-icon32.png");
|
|
QPixmap pm2;
|
|
QLabel *imgLbl;
|
|
QTextEdit *txtEdit;
|
|
QPushButton *okButton;
|
|
const char *txt = "\
|
|
Created by AnS\n\n\
|
|
Originated from TASEdit\n\
|
|
made by zeromus & adelikat\n\n\
|
|
Ported to Qt by mjbudd77\n\
|
|
";
|
|
|
|
pm2 = pm.scaled( 64, 64 );
|
|
|
|
mainLayout = new QVBoxLayout();
|
|
vbox = new QVBoxLayout();
|
|
hbox = new QHBoxLayout();
|
|
txtEdit = new QTextEdit();
|
|
okButton = new QPushButton( tr("OK") );
|
|
|
|
about.setWindowTitle( tr("About") );
|
|
about.setLayout( mainLayout );
|
|
|
|
imgLbl = new QLabel();
|
|
imgLbl->setPixmap(pm2);
|
|
|
|
mainLayout->addLayout( hbox );
|
|
hbox->addWidget( imgLbl, 2, Qt::AlignCenter );
|
|
hbox->addLayout( vbox, 2 );
|
|
vbox->addWidget( new QLabel( tr("TAS Editor") ), 1, Qt::AlignCenter );
|
|
vbox->addWidget( new QLabel( tr("Version 1.01") ), 1, Qt::AlignCenter );
|
|
mainLayout->addWidget( txtEdit );
|
|
|
|
hbox = new QHBoxLayout();
|
|
hbox->addStretch(5);
|
|
hbox->addWidget( okButton, 1 );
|
|
mainLayout->addLayout( hbox );
|
|
|
|
txtEdit->setText( tr(txt) );
|
|
txtEdit->setReadOnly(true);
|
|
|
|
okButton->setDefault(true);
|
|
okButton->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
|
|
connect( okButton, SIGNAL(clicked(void)), &about, SLOT(accept(void)) );
|
|
|
|
about.exec();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//------ Custom Vertical Scroll For Piano Roll
|
|
//----------------------------------------------------------------------------
|
|
PianoRollScrollBar::PianoRollScrollBar( QWidget *parent )
|
|
: QScrollBar( Qt::Vertical, parent )
|
|
{
|
|
pxLineSpacing = 12;
|
|
wheelPixelCounter = 0;
|
|
wheelAngleCounter = 0;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
PianoRollScrollBar::~PianoRollScrollBar(void)
|
|
{
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void PianoRollScrollBar::wheelEvent(QWheelEvent *event)
|
|
{
|
|
int ofs, zDelta = 0;
|
|
|
|
//QScrollBar::wheelEvent(event);
|
|
QPoint numPixels = event->pixelDelta();
|
|
QPoint numDegrees = event->angleDelta();
|
|
|
|
ofs = value();
|
|
|
|
if (!numPixels.isNull())
|
|
{
|
|
wheelPixelCounter -= numPixels.y();
|
|
//printf("numPixels: (%i,%i) \n", numPixels.x(), numPixels.y() );
|
|
|
|
if ( wheelPixelCounter >= pxLineSpacing )
|
|
{
|
|
zDelta = wheelPixelCounter / pxLineSpacing;
|
|
|
|
wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
|
|
}
|
|
else if ( wheelPixelCounter <= -pxLineSpacing )
|
|
{
|
|
zDelta = wheelPixelCounter / pxLineSpacing;
|
|
|
|
wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
|
|
}
|
|
}
|
|
else if (!numDegrees.isNull())
|
|
{
|
|
int stepDeg = 120;
|
|
//QPoint numSteps = numDegrees / 15;
|
|
//printf("numSteps: (%i,%i) \n", numSteps.x(), numSteps.y() );
|
|
//printf("numDegrees: (%i,%i) %i\n", numDegrees.x(), numDegrees.y(), pxLineSpacing );
|
|
wheelAngleCounter -= numDegrees.y();
|
|
|
|
if ( wheelAngleCounter <= stepDeg )
|
|
{
|
|
zDelta = wheelAngleCounter / stepDeg;
|
|
|
|
wheelAngleCounter = wheelAngleCounter % stepDeg;
|
|
}
|
|
else if ( wheelAngleCounter >= stepDeg )
|
|
{
|
|
zDelta = wheelAngleCounter / stepDeg;
|
|
|
|
wheelAngleCounter = wheelAngleCounter % stepDeg;
|
|
}
|
|
}
|
|
|
|
if ( zDelta != 0 )
|
|
{
|
|
ofs = ofs + (6 * zDelta);
|
|
|
|
if ( ofs < 0 )
|
|
{
|
|
ofs = 0;
|
|
}
|
|
else if ( ofs > maximum() )
|
|
{
|
|
ofs = maximum();
|
|
}
|
|
setValue( ofs );
|
|
}
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//---- TAS Piano Roll Widget
|
|
//----------------------------------------------------------------------------
|
|
QPianoRoll::QPianoRoll(QWidget *parent)
|
|
: QWidget( parent )
|
|
{
|
|
QPalette pal;
|
|
std::string fontString;
|
|
QColor fg("black"), bg("white"), c;
|
|
|
|
useDarkTheme = false;
|
|
|
|
viewWidth = 256;
|
|
viewHeight = 512;
|
|
setMinimumWidth( viewWidth );
|
|
setMinimumHeight( viewHeight );
|
|
setAcceptDrops(true);
|
|
|
|
g_config->getOption("SDL.TasPianoRollFont", &fontString);
|
|
|
|
if ( fontString.size() > 0 )
|
|
{
|
|
//printf("Font String: '%s'\n", fontString.c_str() );
|
|
font.fromString( QString::fromStdString( fontString ) );
|
|
}
|
|
else
|
|
{
|
|
font.setFamily("Courier New");
|
|
font.setStyle( QFont::StyleNormal );
|
|
font.setStyleHint( QFont::Monospace );
|
|
}
|
|
font.setBold(true);
|
|
|
|
pal = this->palette();
|
|
|
|
windowColor = pal.color(QPalette::Window);
|
|
|
|
// Figure out if we are using a light or dark theme by checking the
|
|
// default window text grayscale color. If more white, then we will
|
|
// use white text on black background, else we do the opposite.
|
|
c = pal.color(QPalette::WindowText);
|
|
|
|
if ( qGray( c.red(), c.green(), c.blue() ) > 128 )
|
|
{
|
|
useDarkTheme = true;
|
|
}
|
|
//printf("WindowText: R:%i G:%i B:%i \n", c.red(), c.green(), c.blue() );
|
|
|
|
if ( useDarkTheme )
|
|
{
|
|
pal.setColor(QPalette::Base , fg );
|
|
pal.setColor(QPalette::Window , fg );
|
|
pal.setColor(QPalette::WindowText, bg );
|
|
}
|
|
else
|
|
{
|
|
pal.setColor(QPalette::Base , bg );
|
|
pal.setColor(QPalette::Window , bg );
|
|
pal.setColor(QPalette::WindowText, fg );
|
|
}
|
|
this->parent = qobject_cast <TasEditorWindow*>( parent );
|
|
this->setFocusPolicy(Qt::StrongFocus);
|
|
this->setMouseTracking(true);
|
|
this->setPalette(pal);
|
|
|
|
numCtlr = 2;
|
|
numColumns = 2 + (NUM_JOYPAD_BUTTONS * numCtlr);
|
|
|
|
vbar = NULL;
|
|
hbar = NULL;
|
|
|
|
mkrDrag = NULL;
|
|
lineOffset = 0;
|
|
maxLineOffset = 0;
|
|
playbackCursorPos = 0;
|
|
dragMode = DRAG_MODE_NONE;
|
|
dragSelectionStartingFrame = 0;
|
|
dragSelectionEndingFrame = 0;
|
|
realRowUnderMouse = -1;
|
|
rowUnderMouse = -1;
|
|
columnUnderMouse = 0;
|
|
rowUnderMouseAtPress = -1;
|
|
columnUnderMouseAtPress = 0;
|
|
markerDragFrameNumber = 0;
|
|
markerDragCountdown = 0;
|
|
drawingStartTimestamp = 0;
|
|
wheelPixelCounter = 0;
|
|
wheelAngleCounter = 0;
|
|
headerItemUnderMouse = 0;
|
|
nextHeaderUpdateTime = 0;
|
|
rightButtonDragMode = false;
|
|
mouse_x = mouse_y = -1;
|
|
scroll_x = scroll_y = 0;
|
|
memset( headerColors, 0, sizeof(headerColors) );
|
|
|
|
headerLightsColors[ 0] = QColor( 0x00, 0x00, 0x00 );
|
|
headerLightsColors[ 1] = QColor( 0x13, 0x73, 0x00 );
|
|
headerLightsColors[ 2] = QColor( 0x00, 0x91, 0x00 );
|
|
headerLightsColors[ 3] = QColor( 0x00, 0xAF, 0x1D );
|
|
headerLightsColors[ 4] = QColor( 0x00, 0xC7, 0x42 );
|
|
headerLightsColors[ 5] = QColor( 0x00, 0xD9, 0x65 );
|
|
headerLightsColors[ 6] = QColor( 0x00, 0xE5, 0x91 );
|
|
headerLightsColors[ 7] = QColor( 0x00, 0xF0, 0xB0 );
|
|
headerLightsColors[ 8] = QColor( 0x00, 0xF7, 0xDA );
|
|
headerLightsColors[ 9] = QColor( 0x7C, 0xFC, 0xF0 );
|
|
headerLightsColors[10] = QColor( 0xBA, 0xFF, 0xFC );
|
|
|
|
hotChangesColors[ 0] = QColor( 0x00, 0x00, 0x00 );
|
|
hotChangesColors[ 1] = QColor( 0x35, 0x40, 0x00 );
|
|
hotChangesColors[ 2] = QColor( 0x18, 0x52, 0x18 );
|
|
hotChangesColors[ 3] = QColor( 0x34, 0x5C, 0x5E );
|
|
hotChangesColors[ 4] = QColor( 0x00, 0x4C, 0x80 );
|
|
hotChangesColors[ 5] = QColor( 0x00, 0x03, 0xBA );
|
|
hotChangesColors[ 6] = QColor( 0x38, 0x00, 0xD1 );
|
|
hotChangesColors[ 7] = QColor( 0x72, 0x12, 0xB2 );
|
|
hotChangesColors[ 8] = QColor( 0xAB, 0x00, 0xBA );
|
|
hotChangesColors[ 9] = QColor( 0xB0, 0x00, 0x6F );
|
|
hotChangesColors[10] = QColor( 0xC2, 0x00, 0x37 );
|
|
hotChangesColors[11] = QColor( 0xBA, 0x0C, 0x00 );
|
|
hotChangesColors[12] = QColor( 0xC9, 0x2C, 0x00 );
|
|
hotChangesColors[13] = QColor( 0xBF, 0x53, 0x00 );
|
|
hotChangesColors[14] = QColor( 0xCF, 0x72, 0x00 );
|
|
hotChangesColors[15] = QColor( 0xC7, 0x8B, 0x3C );
|
|
|
|
gridPixelWidth = 1;
|
|
gridColor = QColor( 0x00, 0x00, 0x00 );
|
|
|
|
fceuLoadConfigColor("SDL.TasPianoRollGridColor" , &gridColor );
|
|
|
|
calcFontData();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
QPianoRoll::~QPianoRoll(void)
|
|
{
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::reset(void)
|
|
{
|
|
int num_joysticks = joysticksPerFrame[getInputType(currMovieData)];
|
|
|
|
numCtlr = num_joysticks;
|
|
|
|
numColumns = 2 + (NUM_JOYPAD_BUTTONS * num_joysticks);
|
|
|
|
calcFontData();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::save(EMUFILE *os, bool really_save)
|
|
{
|
|
if (really_save)
|
|
{
|
|
updateLinesCount();
|
|
// write "PIANO_ROLL" string
|
|
os->fwrite(pianoRollSaveID, PIANO_ROLL_ID_LEN);
|
|
// write current top item
|
|
int top_item = lineOffset;
|
|
write32le(top_item, os);
|
|
}
|
|
else
|
|
{
|
|
// write "PIANO_ROLX" string
|
|
os->fwrite(pianoRollSkipSaveID, PIANO_ROLL_ID_LEN);
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
// returns true if couldn't load
|
|
bool QPianoRoll::load(EMUFILE *is, unsigned int offset)
|
|
{
|
|
reset();
|
|
updateLinesCount();
|
|
if (offset)
|
|
{
|
|
if (is->fseek(offset, SEEK_SET)) goto error;
|
|
}
|
|
else
|
|
{
|
|
// scroll to the beginning
|
|
//ListView_EnsureVisible(hwndList, 0, FALSE);
|
|
lineOffset = 0;
|
|
return false;
|
|
}
|
|
// read "PIANO_ROLL" string
|
|
char save_id[PIANO_ROLL_ID_LEN];
|
|
if ((int)is->fread(save_id, PIANO_ROLL_ID_LEN) < PIANO_ROLL_ID_LEN) goto error;
|
|
if (!strcmp(pianoRollSkipSaveID, save_id))
|
|
{
|
|
// string says to skip loading Piano Roll
|
|
FCEU_printf("No Piano Roll data in the file\n");
|
|
// scroll to the beginning
|
|
//ListView_EnsureVisible(hwndList, 0, FALSE);
|
|
lineOffset = 0;
|
|
return false;
|
|
}
|
|
if (strcmp(pianoRollSaveID, save_id)) goto error; // string is not valid
|
|
// read current top item and scroll Piano Roll there
|
|
int top_item;
|
|
if (!read32le(&top_item, is)) goto error;
|
|
//ListView_EnsureVisible(hwndList, currMovieData.getNumRecords() - 1, FALSE);
|
|
//ListView_EnsureVisible(hwndList, top_item, FALSE);
|
|
ensureTheLineIsVisible( currMovieData.getNumRecords() - 1 );
|
|
ensureTheLineIsVisible( top_item );
|
|
return false;
|
|
error:
|
|
FCEU_printf("Error loading Piano Roll data\n");
|
|
// scroll to the beginning
|
|
//ListView_EnsureVisible(hwndList, 0, FALSE);
|
|
lineOffset = 0;
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::setScrollBars( QScrollBar *h, QScrollBar *v )
|
|
{
|
|
hbar = h; vbar = v;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::hbarChanged(int val)
|
|
{
|
|
if ( viewWidth >= pxLineWidth )
|
|
{
|
|
pxLineXScroll = 0;
|
|
}
|
|
else
|
|
{
|
|
pxLineXScroll = val;
|
|
}
|
|
update();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//void QPianoRoll::vbarActionTriggered(int act)
|
|
//{
|
|
// int val = vbar->value();
|
|
//
|
|
// if ( act == QAbstractSlider::SliderSingleStepAdd )
|
|
// {
|
|
// val = val - vbar->singleStep();
|
|
//
|
|
// if ( val < 0 )
|
|
// {
|
|
// val = 0;
|
|
// }
|
|
// vbar->setSliderPosition(val);
|
|
// }
|
|
// else if ( act == QAbstractSlider::SliderSingleStepSub )
|
|
// {
|
|
// val = val + vbar->singleStep();
|
|
//
|
|
// if ( val >= maxLineOffset )
|
|
// {
|
|
// val = maxLineOffset;
|
|
// }
|
|
// vbar->setSliderPosition(val);
|
|
// }
|
|
// else if ( act == QAbstractSlider::SliderPageStepAdd )
|
|
// {
|
|
// val = val - vbar->pageStep();
|
|
//
|
|
// if ( val < 0 )
|
|
// {
|
|
// val = 0;
|
|
// }
|
|
// vbar->setSliderPosition(val);
|
|
// }
|
|
// else if ( act == QAbstractSlider::SliderPageStepSub )
|
|
// {
|
|
// val = val + vbar->pageStep();
|
|
//
|
|
// if ( val >= maxLineOffset )
|
|
// {
|
|
// val = maxLineOffset;
|
|
// }
|
|
// vbar->setSliderPosition(val);
|
|
// }
|
|
// //printf("ACT:%i\n", act);
|
|
//}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::vbarChanged(int val)
|
|
{
|
|
lineOffset = val;
|
|
|
|
if ( lineOffset < 0 )
|
|
{
|
|
lineOffset = 0;
|
|
}
|
|
else if ( lineOffset > maxLineOffset )
|
|
{
|
|
lineOffset = maxLineOffset;
|
|
}
|
|
update();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::setFont( QFont &newFont )
|
|
{
|
|
font = newFont;
|
|
font.setBold(true);
|
|
QWidget::setFont( font );
|
|
calcFontData();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::calcFontData(void)
|
|
{
|
|
QRect rect;
|
|
QWidget::setFont(font);
|
|
QFontMetrics metrics(font);
|
|
#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0)
|
|
pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2'));
|
|
#else
|
|
pxCharWidth = metrics.width(QLatin1Char('2'));
|
|
#endif
|
|
pxCharHeight = metrics.capHeight();
|
|
pxLineSpacing = metrics.lineSpacing() * 1.25;
|
|
pxLineLead = pxLineSpacing - metrics.height();
|
|
pxCursorHeight = metrics.height();
|
|
pxLineTextOfs = pxLineSpacing - ((pxLineSpacing - pxCharHeight) / 2) + (pxLineSpacing - pxCharHeight + 1) % 2;
|
|
|
|
//printf("W:%i H:%i LS:%i \n", pxCharWidth, pxCharHeight, pxLineSpacing );
|
|
|
|
viewLines = (viewHeight / pxLineSpacing) + 1;
|
|
|
|
pxWidthCol1 = 3 * pxCharWidth;
|
|
pxWidthFrameCol = 9 * pxCharWidth;
|
|
pxWidthBtnCol = 3 * pxCharWidth;
|
|
pxWidthCtlCol = 8 * pxWidthBtnCol;
|
|
|
|
rect = metrics.boundingRect( tr("000000000") );
|
|
|
|
//printf("FrameWidth: %i %i\n", pxWidthFrameCol, rect.width() );
|
|
if ( pxWidthFrameCol < rect.width() )
|
|
{
|
|
pxWidthFrameCol = rect.width();
|
|
}
|
|
|
|
pxFrameColX = pxWidthCol1;
|
|
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
pxFrameCtlX[i] = pxFrameColX + pxWidthFrameCol + (i*pxWidthCtlCol);
|
|
}
|
|
pxLineWidth = pxFrameCtlX[ numCtlr-1 ] + pxWidthCtlCol;
|
|
|
|
if ( vbar )
|
|
{
|
|
if ( maxLineOffset < 0 )
|
|
{
|
|
vbar->hide();
|
|
maxLineOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
vbar->show();
|
|
}
|
|
vbar->setMinimum(0);
|
|
vbar->setMaximum(maxLineOffset);
|
|
vbar->setPageStep( (7*viewLines)/8 );
|
|
}
|
|
|
|
if ( hbar )
|
|
{
|
|
if ( viewWidth >= pxLineWidth )
|
|
{
|
|
pxLineXScroll = 0;
|
|
hbar->hide();
|
|
}
|
|
else
|
|
{
|
|
hbar->setPageStep( viewWidth );
|
|
hbar->setMaximum( pxLineWidth - viewWidth );
|
|
hbar->show();
|
|
pxLineXScroll = hbar->value();
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
QPoint QPianoRoll::convPixToCursor( QPoint p )
|
|
{
|
|
QPoint c(0,0);
|
|
|
|
if ( p.x() < 0 )
|
|
{
|
|
c.setX(0);
|
|
}
|
|
else
|
|
{
|
|
float x = (float)(p.x() + pxLineXScroll) / pxCharWidth;
|
|
|
|
c.setX( (int)x );
|
|
}
|
|
|
|
if ( p.y() < 0 )
|
|
{
|
|
c.setY( -1 );
|
|
}
|
|
else
|
|
{
|
|
float py = ( (float)p.y() ) / (float)pxLineSpacing;
|
|
|
|
c.setY( (int)py - 1 );
|
|
}
|
|
return c;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int QPianoRoll::calcColumn( int px )
|
|
{
|
|
int col = -1;
|
|
|
|
px = px + pxLineXScroll;
|
|
|
|
if ( px < pxFrameColX )
|
|
{
|
|
col = COLUMN_ICONS;
|
|
}
|
|
else if ( px < pxFrameCtlX[0] )
|
|
{
|
|
col = COLUMN_FRAMENUM;
|
|
}
|
|
else
|
|
{
|
|
int i=0;
|
|
|
|
while ( px < pxFrameCtlX[i] )
|
|
{
|
|
if ( i >= 3 )
|
|
{
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
col = COLUMN_JOYPAD1_A + (i*8) + ( (px - pxFrameCtlX[i]) / pxWidthBtnCol);
|
|
}
|
|
return col;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::drawArrow( QPainter *painter, int xl, int yl, int value )
|
|
{
|
|
int x, y, w, h;
|
|
QPoint p[3];
|
|
bool hasBookmark = false;
|
|
bool draw2ndArrow = false;
|
|
bool draw1stArrow = true;
|
|
QColor green( 0, 0xC0, 0x40 ), blue( 0x60, 0xC0, 0xC0 );
|
|
QColor arrowColor1 = green;
|
|
QColor arrowColor2 = blue;
|
|
|
|
x = xl+(pxCharWidth/3);
|
|
y = yl+1;
|
|
w = pxCharWidth;
|
|
h = pxLineSpacing-2;
|
|
|
|
if ( (value & BOOKMARKS_WITH_GREEN_ARROW) || (value & BOOKMARKS_WITH_BLUE_ARROW) || (value & BOOKMARKS_WITH_NO_ARROW) )
|
|
{
|
|
char txt[4];
|
|
int bookmarkNum;
|
|
|
|
bookmarkNum = (value & 0x0000FFFF);
|
|
|
|
txt[0] = (bookmarkNum % TOTAL_BOOKMARKS) + '0';
|
|
txt[1] = 0;
|
|
|
|
painter->drawText( x, y+pxLineTextOfs, tr(txt) );
|
|
|
|
hasBookmark = true;
|
|
draw1stArrow = false;
|
|
draw2ndArrow = (value & BOOKMARKS_WITH_NO_ARROW) ? false : true;
|
|
|
|
x += pxCharWidth;
|
|
|
|
}
|
|
|
|
p[0] = QPoint( x, y );
|
|
p[1] = QPoint( x, y+h );
|
|
p[2] = QPoint( x+w, y+(h/2) );
|
|
|
|
if ( hasBookmark )
|
|
{
|
|
if ( value & BOOKMARKS_WITH_GREEN_ARROW )
|
|
{
|
|
arrowColor1 = green;
|
|
}
|
|
else if ( value & BOOKMARKS_WITH_BLUE_ARROW )
|
|
{
|
|
arrowColor1 = blue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( value & GREEN_ARROW_IMAGE_ID )
|
|
{
|
|
arrowColor1 = green;
|
|
|
|
if ( value & BLUE_ARROW_IMAGE_ID )
|
|
{
|
|
draw2ndArrow = true;
|
|
arrowColor2 = blue;
|
|
}
|
|
}
|
|
else if ( value & BLUE_ARROW_IMAGE_ID )
|
|
{
|
|
arrowColor1 = blue;
|
|
}
|
|
}
|
|
if ( draw1stArrow )
|
|
{
|
|
painter->setBrush( arrowColor1 );
|
|
painter->drawPolygon( p, 3 );
|
|
x += pxCharWidth;
|
|
}
|
|
|
|
if ( draw2ndArrow )
|
|
{
|
|
x += (pxCharWidth / 4);
|
|
|
|
p[0] = QPoint( x, y+1 );
|
|
p[1] = QPoint( x, y+h-1 );
|
|
p[2] = QPoint( x+w-1, y+(h/2) );
|
|
|
|
painter->setBrush( arrowColor2 );
|
|
|
|
painter->drawPolygon( p, 3 );
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::updateLinesCount(void)
|
|
{
|
|
// update the number of items in the list
|
|
int movie_size = currMovieData.getNumRecords();
|
|
|
|
maxLineOffset = movie_size - viewLines + 2;
|
|
|
|
if ( maxLineOffset < 0 )
|
|
{
|
|
maxLineOffset = 0;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bool QPianoRoll::lineIsVisible( int lineNum )
|
|
{
|
|
int lineEnd = lineOffset + viewLines - 2;
|
|
|
|
return ( (lineNum >= lineOffset) && (lineNum < lineEnd) );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::ensureTheLineIsVisible( int lineNum )
|
|
{
|
|
if ( !lineIsVisible( lineNum ) )
|
|
{
|
|
//int lineEnd = lineOffset + viewLines - 2;
|
|
//printf("Seeking Frame %i\n", lineNum );
|
|
|
|
if ( lineNum < lineOffset )
|
|
{
|
|
lineOffset = lineNum;
|
|
}
|
|
else
|
|
{
|
|
//printf("Seeking View Frame %i\n", lineNum );
|
|
lineOffset = lineOffset - viewLines + 2;
|
|
}
|
|
|
|
if ( lineOffset < 0 )
|
|
{
|
|
lineOffset = 0;
|
|
}
|
|
else if ( lineOffset > maxLineOffset )
|
|
{
|
|
lineOffset = maxLineOffset;
|
|
}
|
|
vbar->setValue( lineOffset );
|
|
|
|
update();
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::resizeEvent(QResizeEvent *event)
|
|
{
|
|
viewWidth = event->size().width();
|
|
viewHeight = event->size().height();
|
|
|
|
//printf("QPianoRoll Resize: %ix%i $%04X\n", viewWidth, viewHeight );
|
|
|
|
viewLines = (viewHeight / pxLineSpacing) + 1;
|
|
|
|
maxLineOffset = currMovieData.records.size() - viewLines + 2;
|
|
|
|
if ( maxLineOffset < 0 )
|
|
{
|
|
vbar->hide();
|
|
maxLineOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
vbar->show();
|
|
}
|
|
vbar->setMinimum(0);
|
|
vbar->setMaximum(maxLineOffset);
|
|
vbar->setPageStep( (7*viewLines)/8 );
|
|
|
|
if ( viewWidth >= pxLineWidth )
|
|
{
|
|
pxLineXScroll = 0;
|
|
hbar->hide();
|
|
}
|
|
else
|
|
{
|
|
hbar->setPageStep( viewWidth );
|
|
hbar->setMaximum( pxLineWidth - viewWidth );
|
|
hbar->show();
|
|
pxLineXScroll = hbar->value();
|
|
}
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::mouseDoubleClickEvent(QMouseEvent * event)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int col, line, row_index, column_index, kbModifiers, alt_pressed;
|
|
bool headerClicked, row_valid;
|
|
QPoint c = convPixToCursor( event->pos() );
|
|
|
|
//printf("Mouse Double Click Pressed: 0x%x (%i,%i)\n", event->button(), c.x(), c.y() );
|
|
|
|
mouse_x = event->pos().x();
|
|
mouse_y = event->pos().y();
|
|
|
|
if ( c.y() >= 0 )
|
|
{
|
|
line = lineOffset + c.y();
|
|
headerClicked = false;
|
|
}
|
|
else
|
|
{
|
|
line = -1;
|
|
headerClicked = true;
|
|
}
|
|
col = calcColumn( event->pos().x() );
|
|
|
|
rowUnderMouseAtPress = rowUnderMouse = realRowUnderMouse = row_index = line;
|
|
columnUnderMouseAtPress = columnUnderMouse = column_index = col;
|
|
|
|
row_valid = (row_index >= 0) && ( (size_t)row_index < currMovieData.records.size() );
|
|
|
|
kbModifiers = QApplication::keyboardModifiers();
|
|
alt_pressed = (kbModifiers & Qt::AltModifier) ? 1 : 0;
|
|
|
|
if ( event->button() == Qt::LeftButton )
|
|
{
|
|
if (col == COLUMN_ICONS)
|
|
{
|
|
// clicked on the "icons" column
|
|
startDraggingPlaybackCursor();
|
|
}
|
|
else if ( (col == COLUMN_FRAMENUM) || (col == COLUMN_FRAMENUM2) )
|
|
{
|
|
//handleColumnSet( col, alt_pressed );
|
|
|
|
// doubleclick - set Marker and start dragging it
|
|
if (!markersManager->getMarkerAtFrame(row_index))
|
|
{
|
|
if (markersManager->setMarkerAtFrame(row_index))
|
|
{
|
|
selection->mustFindCurrentMarker = playback->mustFindCurrentMarker = true;
|
|
history->registerMarkersChange(MODTYPE_MARKER_SET, row_index);
|
|
update();
|
|
}
|
|
}
|
|
// Delay drag event by 100ms incase the button is quickly released
|
|
QTimer::singleShot( 100, this, SLOT(setupMarkerDrag(void)) );
|
|
|
|
//startDraggingMarker( mouse_x, mouse_y, row_index, column_index);
|
|
}
|
|
else if (column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
|
|
{
|
|
// clicked on Input
|
|
if (headerClicked)
|
|
{
|
|
drawingStartTimestamp = getTasEditorTime();
|
|
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
|
|
int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
int selection_end = selection->getCurrentRowsSelectionEnd();
|
|
|
|
if ( (selection_beginning >= 0) && (selection_end >= 0) )
|
|
{
|
|
tasWin->toggleInput(selection_beginning, selection_end, joy, button, drawingStartTimestamp);
|
|
}
|
|
}
|
|
else if (row_index >= 0)
|
|
{
|
|
if (!alt_pressed && !(kbModifiers & Qt::ShiftModifier))
|
|
{
|
|
// clicked without Shift/Alt - bring Selection cursor to this row
|
|
selection->clearAllRowsSelection();
|
|
selection->setRowSelection(row_index);
|
|
}
|
|
// toggle Input
|
|
drawingStartTimestamp = getTasEditorTime();
|
|
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
|
|
int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
if (alt_pressed && selection_beginning >= 0)
|
|
{
|
|
tasWin->setInputUsingPattern(selection_beginning, row_index, joy, button, drawingStartTimestamp);
|
|
}
|
|
else if ((kbModifiers & Qt::ShiftModifier) && selection_beginning >= 0)
|
|
{
|
|
tasWin->toggleInput(selection_beginning, row_index, joy, button, drawingStartTimestamp);
|
|
}
|
|
else
|
|
{
|
|
tasWin->toggleInput(row_index, row_index, joy, button, drawingStartTimestamp);
|
|
}
|
|
// and start dragging/drawing
|
|
if (dragMode == DRAG_MODE_NONE)
|
|
{
|
|
if (taseditorConfig->drawInputByDragging)
|
|
{
|
|
// if clicked this click created buttonpress, then start painting, else start erasing
|
|
if ( row_valid && currMovieData.records[row_index].checkBit(joy, button))
|
|
{
|
|
dragMode = DRAG_MODE_SET;
|
|
}
|
|
else
|
|
{
|
|
dragMode = DRAG_MODE_UNSET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dragMode = DRAG_MODE_OBSERVE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( event->button() == Qt::MiddleButton )
|
|
{
|
|
playback->handleMiddleButtonClick();
|
|
}
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::contextMenuEvent(QContextMenuEvent *event)
|
|
{
|
|
bool drawContext, rowIsSel;
|
|
|
|
rowIsSel = selection->isRowSelected( rowUnderMouse );
|
|
|
|
drawContext = rowIsSel &&
|
|
( (columnUnderMouse == COLUMN_ICONS) || (columnUnderMouse == COLUMN_FRAMENUM) || (columnUnderMouse == COLUMN_FRAMENUM2) );
|
|
|
|
if ( !drawContext )
|
|
{
|
|
return;
|
|
}
|
|
int mkr;
|
|
QAction *act;
|
|
QMenu menu(this);
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
|
|
mkr = markersManager->getMarkerAtFrame( rowUnderMouse );
|
|
|
|
act = new QAction(tr("Set Markers\tDbl-Clk"), &menu);
|
|
menu.addAction(act);
|
|
act->setEnabled( mkr == 0 );
|
|
//act->setShortcut(QKeySequence(tr("Double Click")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(setMarkers(void)));
|
|
|
|
act = new QAction(tr("Remove Markers"), &menu);
|
|
menu.addAction(act);
|
|
act->setEnabled( mkr > 0 );
|
|
//act->setShortcut(QKeySequence(tr("Dbl-clk")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(removeMarkers(void)));
|
|
|
|
menu.addSeparator();
|
|
|
|
act = new QAction(tr("Deselect"), &menu);
|
|
menu.addAction(act);
|
|
//act->setShortcut(QKeySequence(tr("D")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editDeselectAll(void)));
|
|
|
|
act = new QAction(tr("Select between markers"), &menu);
|
|
menu.addAction(act);
|
|
act->setShortcut(QKeySequence(tr("Ctrl-A")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editSelBtwMkrs(void)));
|
|
|
|
menu.addSeparator();
|
|
|
|
act = new QAction(tr("Ungreenzone"), &menu);
|
|
menu.addAction(act);
|
|
//act->setShortcut(QKeySequence(tr("Ctrl-A")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(ungreenzoneSelectedFrames(void)));
|
|
|
|
menu.addSeparator();
|
|
|
|
act = new QAction(tr("Clear"), &menu);
|
|
menu.addAction(act);
|
|
act->setShortcut(QKeySequence(tr("Del")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editClearCB(void)));
|
|
|
|
act = new QAction(tr("Delete"), &menu);
|
|
menu.addAction(act);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Del")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editDeleteCB(void)));
|
|
|
|
act = new QAction(tr("Clone"), &menu);
|
|
menu.addAction(act);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Ins")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editCloneCB(void)));
|
|
|
|
act = new QAction(tr("Insert"), &menu);
|
|
menu.addAction(act);
|
|
act->setShortcut(QKeySequence(tr("Ctrl+Shift+Ins")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editInsertCB(void)));
|
|
|
|
act = new QAction(tr("Insert # of Frames"), &menu);
|
|
menu.addAction(act);
|
|
act->setShortcut(QKeySequence(tr("Ins")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editInsertNumFramesCB(void)));
|
|
|
|
menu.addSeparator();
|
|
|
|
act = new QAction(tr("Truncate Movie"), &menu);
|
|
menu.addAction(act);
|
|
//act->setShortcut(QKeySequence(tr("Ins")));
|
|
connect(act, SIGNAL(triggered(void)), tasWin, SLOT(editTruncateMovieCB(void)));
|
|
|
|
menu.exec(event->globalPos());
|
|
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::mousePressEvent(QMouseEvent * event)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int col, line, row_index, column_index, kbModifiers, alt_pressed;
|
|
bool row_valid, headerClicked;
|
|
QPoint c = convPixToCursor( event->pos() );
|
|
|
|
mouse_x = event->pos().x();
|
|
mouse_y = event->pos().y();
|
|
|
|
if ( c.y() >= 0 )
|
|
{
|
|
line = lineOffset + c.y();
|
|
headerClicked = false;
|
|
}
|
|
else
|
|
{
|
|
line = -1;
|
|
headerClicked = true;
|
|
}
|
|
col = calcColumn( event->pos().x() );
|
|
|
|
row_index = line;
|
|
rowUnderMouseAtPress = rowUnderMouse = realRowUnderMouse = line;
|
|
columnUnderMouseAtPress = columnUnderMouse = column_index = col;
|
|
|
|
row_valid = (row_index >= 0) && ( (size_t)row_index < currMovieData.records.size() );
|
|
|
|
kbModifiers = QApplication::keyboardModifiers();
|
|
alt_pressed = (kbModifiers & Qt::AltModifier) ? 1 : 0;
|
|
|
|
//printf("Mouse Button Pressed: 0x%x (%i,%i)\n", event->button(), c.x(), c.y() );
|
|
|
|
if ( event->button() == Qt::LeftButton )
|
|
{
|
|
if (col == COLUMN_ICONS)
|
|
{
|
|
// clicked on the "icons" column
|
|
startDraggingPlaybackCursor();
|
|
}
|
|
else if ( (col == COLUMN_FRAMENUM) || (col == COLUMN_FRAMENUM2) )
|
|
{
|
|
// clicked on the "Frame#" column
|
|
if (row_index >= 0)
|
|
{
|
|
if (kbModifiers & Qt::ShiftModifier)
|
|
{
|
|
// select region from selection_beginning to row_index
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
if (selection_beginning >= 0)
|
|
{
|
|
if (selection_beginning < row_index)
|
|
{
|
|
selection->setRegionOfRowsSelection(selection_beginning, row_index + 1);
|
|
}
|
|
else
|
|
{
|
|
selection->setRegionOfRowsSelection(row_index, selection_beginning + 1);
|
|
}
|
|
}
|
|
startSelectingDrag(row_index);
|
|
}
|
|
else if (kbModifiers & Qt::AltModifier)
|
|
{
|
|
// make Selection by Pattern
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
if (selection_beginning >= 0)
|
|
{
|
|
selection->clearAllRowsSelection();
|
|
if (selection_beginning < row_index)
|
|
{
|
|
selection->setRegionOfRowsSelectionUsingPattern(selection_beginning, row_index);
|
|
}
|
|
else
|
|
{
|
|
selection->setRegionOfRowsSelectionUsingPattern(row_index, selection_beginning);
|
|
}
|
|
}
|
|
if (selection->isRowSelected(row_index))
|
|
{
|
|
startDeselectingDrag(row_index);
|
|
}
|
|
else
|
|
{
|
|
startSelectingDrag(row_index);
|
|
}
|
|
}
|
|
else if (kbModifiers & Qt::ControlModifier)
|
|
{
|
|
// clone current selection, so that user will be able to revert
|
|
if (selection->getCurrentRowsSelectionSize() > 0)
|
|
{
|
|
selection->addCurrentSelectionToHistory();
|
|
}
|
|
if (selection->isRowSelected(row_index))
|
|
{
|
|
selection->clearSingleRowSelection(row_index);
|
|
startDeselectingDrag(row_index);
|
|
}
|
|
else
|
|
{
|
|
selection->setRowSelection(row_index);
|
|
startSelectingDrag(row_index);
|
|
}
|
|
}
|
|
else // just click
|
|
{
|
|
selection->clearAllRowsSelection();
|
|
selection->setRowSelection(row_index);
|
|
startSelectingDrag(row_index);
|
|
}
|
|
}
|
|
}
|
|
else if (column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
|
|
{
|
|
// clicked on Input
|
|
if (headerClicked)
|
|
{
|
|
drawingStartTimestamp = getTasEditorTime();
|
|
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
|
|
int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
int selection_end = selection->getCurrentRowsSelectionEnd();
|
|
|
|
if ( (selection_beginning >= 0) && (selection_end >= 0) )
|
|
{
|
|
tasWin->toggleInput(selection_beginning, selection_end, joy, button, drawingStartTimestamp);
|
|
}
|
|
}
|
|
else if (row_index >= 0)
|
|
{
|
|
if (!alt_pressed && !(kbModifiers & Qt::ShiftModifier))
|
|
{
|
|
// clicked without Shift/Alt - bring Selection cursor to this row
|
|
selection->clearAllRowsSelection();
|
|
selection->setRowSelection(row_index);
|
|
}
|
|
// toggle Input
|
|
drawingStartTimestamp = getTasEditorTime();
|
|
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
|
|
int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
if (alt_pressed && selection_beginning >= 0)
|
|
{
|
|
tasWin->setInputUsingPattern(selection_beginning, row_index, joy, button, drawingStartTimestamp);
|
|
}
|
|
else if ((kbModifiers & Qt::ShiftModifier) && selection_beginning >= 0)
|
|
{
|
|
tasWin->toggleInput(selection_beginning, row_index, joy, button, drawingStartTimestamp);
|
|
}
|
|
else
|
|
{
|
|
tasWin->toggleInput(row_index, row_index, joy, button, drawingStartTimestamp);
|
|
}
|
|
// and start dragging/drawing
|
|
if (dragMode == DRAG_MODE_NONE)
|
|
{
|
|
if (taseditorConfig->drawInputByDragging)
|
|
{
|
|
// if clicked this click created buttonpress, then start painting, else start erasing
|
|
if ( row_valid && currMovieData.records[row_index].checkBit(joy, button))
|
|
{
|
|
dragMode = DRAG_MODE_SET;
|
|
}
|
|
else
|
|
{
|
|
dragMode = DRAG_MODE_UNSET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dragMode = DRAG_MODE_OBSERVE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( event->button() == Qt::MiddleButton )
|
|
{
|
|
playback->handleMiddleButtonClick();
|
|
}
|
|
else if ( event->button() == Qt::RightButton )
|
|
{
|
|
//rightButtonDragMode = true;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::mouseReleaseEvent(QMouseEvent * event)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int col, line;
|
|
QPoint c = convPixToCursor( event->pos() );
|
|
|
|
mouse_x = event->pos().x();
|
|
mouse_y = event->pos().y();
|
|
|
|
if ( c.y() >= 0 )
|
|
{
|
|
line = lineOffset + c.y();
|
|
}
|
|
else
|
|
{
|
|
line = lineOffset;
|
|
}
|
|
col = calcColumn( event->pos().x() );
|
|
|
|
rowUnderMouse = realRowUnderMouse = line;
|
|
columnUnderMouse = col;
|
|
|
|
//printf("Mouse Button Released: 0x%x (%i,%i)\n", event->button(), c.x(), c.y() );
|
|
|
|
if ( event->button() == Qt::LeftButton )
|
|
{
|
|
if (dragMode != DRAG_MODE_NONE)
|
|
{
|
|
// check if user released left button
|
|
finishDrag();
|
|
}
|
|
}
|
|
else if ( event->button() == Qt::RightButton )
|
|
{
|
|
//rightButtonDragMode = false;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::mouseMoveEvent(QMouseEvent * event)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int col, line;
|
|
QPoint c = convPixToCursor( event->pos() );
|
|
|
|
mouse_x = event->pos().x();
|
|
mouse_y = event->pos().y();
|
|
|
|
if ( c.y() >= 0 )
|
|
{
|
|
line = lineOffset + c.y();
|
|
}
|
|
else
|
|
{
|
|
line = lineOffset;
|
|
}
|
|
col = calcColumn( event->pos().x() );
|
|
|
|
rowUnderMouse = realRowUnderMouse = line;
|
|
columnUnderMouse = col;
|
|
|
|
//printf("Mouse Move Event: 0x%x (%i,%i) Col:%i\n", event->button(), c.x(), c.y(), col );
|
|
|
|
if ( event->button() == Qt::LeftButton )
|
|
{
|
|
|
|
}
|
|
updateDrag();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::wheelEvent(QWheelEvent *event)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int ofs, kbModifiers, msButtons, zDelta = 0;
|
|
|
|
QPoint numPixels = event->pixelDelta();
|
|
QPoint numDegrees = event->angleDelta();
|
|
|
|
msButtons = QApplication::mouseButtons();
|
|
kbModifiers = QApplication::keyboardModifiers();
|
|
|
|
ofs = vbar->value();
|
|
|
|
if (!numPixels.isNull())
|
|
{
|
|
wheelPixelCounter += numPixels.y();
|
|
//printf("numPixels: (%i,%i) \n", numPixels.x(), numPixels.y() );
|
|
|
|
if (wheelPixelCounter <= -pxLineSpacing)
|
|
{
|
|
zDelta = (wheelPixelCounter / pxLineSpacing);
|
|
|
|
wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
|
|
}
|
|
else if (wheelPixelCounter >= pxLineSpacing)
|
|
{
|
|
zDelta = (wheelPixelCounter / pxLineSpacing);
|
|
|
|
wheelPixelCounter = wheelPixelCounter % pxLineSpacing;
|
|
}
|
|
}
|
|
else if (!numDegrees.isNull())
|
|
{
|
|
int stepDeg = 120;
|
|
//QPoint numSteps = numDegrees / 15;
|
|
//printf("numSteps: (%i,%i) \n", numSteps.x(), numSteps.y() );
|
|
//printf("numDegrees: (%i,%i) %i\n", numDegrees.x(), numDegrees.y(), pxLineSpacing );
|
|
wheelAngleCounter += numDegrees.y();
|
|
|
|
if ( wheelAngleCounter <= stepDeg )
|
|
{
|
|
zDelta = wheelAngleCounter / stepDeg;
|
|
|
|
wheelAngleCounter = wheelAngleCounter % stepDeg;
|
|
}
|
|
else if ( wheelAngleCounter >= stepDeg )
|
|
{
|
|
zDelta = wheelAngleCounter / stepDeg;
|
|
|
|
wheelAngleCounter = wheelAngleCounter % stepDeg;
|
|
}
|
|
}
|
|
//printf("Wheel Event: %i\n", wheelPixelCounter);
|
|
|
|
if ( kbModifiers & Qt::ShiftModifier )
|
|
{
|
|
// Shift + wheel = Playback rewind full(speed)/forward full(speed)
|
|
if (zDelta < 0)
|
|
{
|
|
playback->handleForwardFull( -zDelta );
|
|
}
|
|
else if (zDelta > 0)
|
|
{
|
|
playback->handleRewindFull( zDelta );
|
|
}
|
|
}
|
|
else if ( kbModifiers & Qt::ControlModifier )
|
|
{
|
|
// Ctrl + wheel = Selection rewind full(speed)/forward full(speed)
|
|
if (zDelta < 0)
|
|
{
|
|
selection->jumpToNextMarker( -zDelta );
|
|
}
|
|
else if (zDelta > 0)
|
|
{
|
|
selection->jumpToPreviousMarker( zDelta );
|
|
}
|
|
}
|
|
else if ( msButtons & Qt::RightButton )
|
|
{
|
|
// Right button + wheel = rewind/forward Playback
|
|
int delta = zDelta;
|
|
if (delta < -1 || delta > 1)
|
|
{
|
|
delta *= PLAYBACK_WHEEL_BOOST;
|
|
}
|
|
int destination_frame;
|
|
if (FCEUI_EmulationPaused() || playback->getPauseFrame() < 0)
|
|
{
|
|
destination_frame = currFrameCounter - delta;
|
|
}
|
|
else
|
|
{
|
|
destination_frame = playback->getPauseFrame() - delta;
|
|
}
|
|
if (destination_frame < 0)
|
|
{
|
|
destination_frame = 0;
|
|
}
|
|
playback->jump(destination_frame);
|
|
}
|
|
else if (kbModifiers & Qt::AltModifier)
|
|
{
|
|
// cross gaps in Input/Markers
|
|
if ( zDelta != 0 )
|
|
{
|
|
crossGaps(zDelta);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (zDelta > 0)
|
|
{
|
|
ofs -= (zDelta*6);
|
|
|
|
if (ofs > maxLineOffset)
|
|
{
|
|
ofs = maxLineOffset;
|
|
}
|
|
vbar->setValue(ofs);
|
|
}
|
|
else if (zDelta < 0)
|
|
{
|
|
ofs -= (zDelta*6);
|
|
|
|
if (ofs < 0)
|
|
{
|
|
ofs = 0;
|
|
}
|
|
vbar->setValue(ofs);
|
|
}
|
|
}
|
|
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
//printf("Key Press: 0x%x \n", event->key() );
|
|
pushKeyEvent( event, 1 );
|
|
|
|
event->accept();
|
|
}
|
|
|
|
void QPianoRoll::keyReleaseEvent(QKeyEvent *event)
|
|
{
|
|
//printf("Key Release: 0x%x \n", event->key() );
|
|
pushKeyEvent( event, 0 );
|
|
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::focusInEvent(QFocusEvent *event)
|
|
{
|
|
QWidget::focusInEvent(event);
|
|
|
|
//printf("PianoRoll Focus In\n");
|
|
|
|
parent->pianoRollFrame->setStyleSheet("QFrame { border: 2px solid rgb(48,140,198); }");
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::focusOutEvent(QFocusEvent *event)
|
|
{
|
|
QWidget::focusOutEvent(event);
|
|
|
|
//printf("PianoRoll Focus Out\n");
|
|
|
|
parent->pianoRollFrame->setStyleSheet(NULL);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::dragEnterEvent(QDragEnterEvent *event)
|
|
{
|
|
if (event->mimeData()->hasUrls() )
|
|
{
|
|
QList<QUrl> urls = event->mimeData()->urls();
|
|
QFileInfo fi( urls[0].toString( QUrl::PreferLocalFile ) );
|
|
|
|
//printf("Suffix: '%s'\n", fi.suffix().toLocal8Bit().constData() );
|
|
|
|
if ( fi.suffix().compare("fm3") == 0)
|
|
{
|
|
event->acceptProposedAction();
|
|
}
|
|
else if ( fi.suffix().compare("fm2") == 0 )
|
|
{
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( event->source() == this )
|
|
{
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::dropEvent(QDropEvent *event)
|
|
{
|
|
if (event->mimeData()->hasUrls() )
|
|
{
|
|
QList<QUrl> urls = event->mimeData()->urls();
|
|
QFileInfo fi( urls[0].toString( QUrl::PreferLocalFile ) );
|
|
|
|
if ( fi.suffix().compare("fm3") == 0 )
|
|
{
|
|
FCEU_WRAPPER_LOCK();
|
|
tasWin->loadProject( fi.filePath().toLocal8Bit().constData() );
|
|
FCEU_WRAPPER_UNLOCK();
|
|
event->accept();
|
|
}
|
|
else if ( fi.suffix().compare("fm2") == 0 )
|
|
{
|
|
FCEU_WRAPPER_LOCK();
|
|
tasWin->importMovieFile( fi.filePath().toLocal8Bit().constData() );
|
|
FCEU_WRAPPER_UNLOCK();
|
|
event->accept();
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bool QPianoRoll::checkIfTheresAnIconAtFrame(int frame)
|
|
{
|
|
if (frame == currFrameCounter)
|
|
return true;
|
|
if (frame == playback->getLastPosition())
|
|
return true;
|
|
if (frame == playback->getPauseFrame())
|
|
return true;
|
|
if (bookmarks->findBookmarkAtFrame(frame) >= 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::crossGaps(int zDelta)
|
|
{
|
|
int row_index = rowUnderMouse;
|
|
int column_index = columnUnderMouse;
|
|
|
|
if (row_index >= 0 && column_index >= COLUMN_ICONS && column_index <= COLUMN_FRAMENUM2)
|
|
{
|
|
if (column_index == COLUMN_ICONS)
|
|
{
|
|
// cross gaps in Icons
|
|
if (zDelta < 0)
|
|
{
|
|
// search down
|
|
int last_frame = currMovieData.getNumRecords() - 1;
|
|
if (row_index < last_frame)
|
|
{
|
|
int frame = row_index + 1;
|
|
bool result_of_closest_frame = checkIfTheresAnIconAtFrame(frame);
|
|
while ((++frame) <= last_frame)
|
|
{
|
|
if (checkIfTheresAnIconAtFrame(frame) != result_of_closest_frame)
|
|
{
|
|
// found different result, so we crossed the gap
|
|
//ListView_Scroll(hwndList, 0, listRowHeight * (frame - row_index));
|
|
centerListAroundLine(frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// search up
|
|
int first_frame = 0;
|
|
if (row_index > first_frame)
|
|
{
|
|
int frame = row_index - 1;
|
|
bool result_of_closest_frame = checkIfTheresAnIconAtFrame(frame);
|
|
while ((--frame) >= first_frame)
|
|
{
|
|
if (checkIfTheresAnIconAtFrame(frame) != result_of_closest_frame)
|
|
{
|
|
// found different result, so we crossed the gap
|
|
//ListView_Scroll(hwndList, 0, listRowHeight * (frame - row_index));
|
|
centerListAroundLine(frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
|
|
{
|
|
// cross gaps in Markers
|
|
if (zDelta < 0)
|
|
{
|
|
// search down
|
|
int last_frame = currMovieData.getNumRecords() - 1;
|
|
if (row_index < last_frame)
|
|
{
|
|
int frame = row_index + 1;
|
|
bool result_of_closest_frame = (markersManager->getMarkerAtFrame(frame) != 0);
|
|
while ((++frame) <= last_frame)
|
|
{
|
|
if ((markersManager->getMarkerAtFrame(frame) != 0) != result_of_closest_frame)
|
|
{
|
|
// found different result, so we crossed the gap
|
|
//ListView_Scroll(hwndList, 0, listRowHeight * (frame - row_index));
|
|
centerListAroundLine(frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// search up
|
|
int first_frame = 0;
|
|
if (row_index > first_frame)
|
|
{
|
|
int frame = row_index - 1;
|
|
bool result_of_closest_frame = (markersManager->getMarkerAtFrame(frame) != 0);
|
|
while ((--frame) >= first_frame)
|
|
{
|
|
if ((markersManager->getMarkerAtFrame(frame) != 0) != result_of_closest_frame)
|
|
{
|
|
// found different result, so we crossed the gap
|
|
//ListView_Scroll(hwndList, 0, listRowHeight * (frame - row_index));
|
|
centerListAroundLine(frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// cross gaps in Input
|
|
int joy = (column_index - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
|
|
int button = (column_index - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
|
|
if (zDelta < 0)
|
|
{
|
|
// search down
|
|
int last_frame = currMovieData.getNumRecords() - 1;
|
|
if (row_index < last_frame)
|
|
{
|
|
int frame = row_index + 1;
|
|
bool result_of_closest_frame = currMovieData.records[frame].checkBit(joy, button);
|
|
while ((++frame) <= last_frame)
|
|
{
|
|
if (currMovieData.records[frame].checkBit(joy, button) != result_of_closest_frame)
|
|
{
|
|
// found different result, so we crossed the gap
|
|
//ListView_Scroll(hwndList, 0, listRowHeight * (frame - row_index));
|
|
centerListAroundLine(frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// search up
|
|
int first_frame = 0;
|
|
if (row_index > first_frame)
|
|
{
|
|
int frame = row_index - 1;
|
|
bool result_of_closest_frame = currMovieData.records[frame].checkBit(joy, button);
|
|
while ((--frame) >= first_frame)
|
|
{
|
|
if (currMovieData.records[frame].checkBit(joy, button) != result_of_closest_frame)
|
|
{
|
|
// found different result, so we crossed the gap
|
|
//ListView_Scroll(hwndList, 0, listRowHeight * (frame - row_index));
|
|
centerListAroundLine(frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::updateDrag(void)
|
|
{
|
|
int kbModifiers, altHeld;
|
|
|
|
if ( dragMode == DRAG_MODE_NONE )
|
|
{
|
|
return;
|
|
}
|
|
kbModifiers = QApplication::keyboardModifiers();
|
|
|
|
altHeld = (kbModifiers & Qt::AltModifier) ? 1 : 0;
|
|
|
|
// perform drag
|
|
switch (dragMode)
|
|
{
|
|
case DRAG_MODE_PLAYBACK:
|
|
{
|
|
handlePlaybackCursorDragging();
|
|
break;
|
|
}
|
|
case DRAG_MODE_MARKER:
|
|
{
|
|
// if suddenly source frame lost its Marker, abort drag
|
|
if (!markersManager->getMarkerAtFrame(markerDragFrameNumber))
|
|
{
|
|
//if (hwndMarkerDragBox)
|
|
//{
|
|
// DestroyWindow(hwndMarkerDragBox);
|
|
// hwndMarkerDragBox = 0;
|
|
//}
|
|
setCursor( Qt::ArrowCursor );
|
|
dragMode = DRAG_MODE_NONE;
|
|
break;
|
|
}
|
|
// when dragging, always show semi-transparent yellow rectangle under mouse
|
|
//POINT p = {0, 0};
|
|
//GetCursorPos(&p);
|
|
//markerDragBoxX = p.x - markerDragBoxDX;
|
|
//markerDragBoxY = p.y - markerDragBoxDY;
|
|
//if (!hwndMarkerDragBox)
|
|
//{
|
|
// hwndMarkerDragBox = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, markerDragBoxClassName, markerDragBoxClassName, WS_POPUP, markerDragBoxX, markerDragBoxY, COLUMN_FRAMENUM_WIDTH, listRowHeight, taseditorWindow.hwndTASEditor, NULL, fceu_hInstance, NULL);
|
|
// ShowWindow(hwndMarkerDragBox, SW_SHOWNA);
|
|
//} else
|
|
//{
|
|
// SetWindowPos(hwndMarkerDragBox, 0, markerDragBoxX, markerDragBoxY, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
|
//}
|
|
//SetLayeredWindowAttributes(hwndMarkerDragBox, 0, MARKER_DRAG_BOX_ALPHA, LWA_ALPHA);
|
|
//UpdateLayeredWindow(hwndMarkerDragBox, 0, 0, 0, 0, 0, 0, &blend, ULW_ALPHA);
|
|
break;
|
|
}
|
|
case DRAG_MODE_SET:
|
|
case DRAG_MODE_UNSET:
|
|
{
|
|
//ScreenToClient(hwndList, &p);
|
|
//int drawing_current_x = p.x + GetScrollPos(hwndList, SB_HORZ);
|
|
//int drawing_current_y = p.y + GetScrollPos(hwndList, SB_VERT) * listRowHeight;
|
|
//// draw (or erase) line from [drawing_current_x, drawing_current_y] to (drawing_last_x, drawing_last_y)
|
|
//int total_dx = drawingLastX - drawing_current_x, total_dy = drawingLastY - drawing_current_y;
|
|
//if (!shiftHeld)
|
|
//{
|
|
// // when user is not holding Shift, draw only vertical lines
|
|
// total_dx = 0;
|
|
// drawing_current_x = drawingLastX;
|
|
// p.x = drawing_current_x - GetScrollPos(hwndList, SB_HORZ);
|
|
//}
|
|
//LVHITTESTINFO info;
|
|
int row_index, column_index, joy, bit;
|
|
int min_row_index = currMovieData.getNumRecords(), max_row_index = -1;
|
|
bool changes_made = false;
|
|
if (altHeld)
|
|
{
|
|
// special mode: draw pattern
|
|
int selection_beginning = selection->getCurrentRowsSelectionBeginning();
|
|
if (selection_beginning >= 0)
|
|
{
|
|
// perform hit test
|
|
row_index = rowUnderMouse;
|
|
// pad movie size if user tries to draw pattern below Piano Roll limit
|
|
if (row_index >= currMovieData.getNumRecords())
|
|
{
|
|
currMovieData.insertEmpty(-1, row_index + 1 - currMovieData.getNumRecords());
|
|
}
|
|
column_index = columnUnderMouseAtPress;
|
|
|
|
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;
|
|
tasWin->setInputUsingPattern(selection_beginning, row_index, joy, bit, drawingStartTimestamp);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
row_index = rowUnderMouseAtPress;
|
|
|
|
while (row_index != rowUnderMouse)
|
|
{
|
|
// perform hit test
|
|
//row_index = rowUnderMouse;
|
|
if ( row_index < 0 )
|
|
{
|
|
break;
|
|
}
|
|
// pad movie size if user tries to draw below Piano Roll limit
|
|
if (row_index >= currMovieData.getNumRecords())
|
|
{
|
|
currMovieData.insertEmpty(-1, row_index + 1 - currMovieData.getNumRecords());
|
|
}
|
|
column_index = columnUnderMouseAtPress;
|
|
|
|
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 (dragMode == 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 (dragMode == 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 ( row_index < rowUnderMouse )
|
|
{
|
|
row_index++;
|
|
}
|
|
else if ( row_index > rowUnderMouse )
|
|
{
|
|
row_index--;
|
|
}
|
|
}
|
|
// pad movie size if user tries to draw below Piano Roll limit
|
|
if (row_index >= currMovieData.getNumRecords())
|
|
{
|
|
currMovieData.insertEmpty(-1, row_index + 1 - currMovieData.getNumRecords());
|
|
}
|
|
column_index = columnUnderMouseAtPress;
|
|
|
|
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 (dragMode == 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 (dragMode == 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 (dragMode == DRAG_MODE_SET)
|
|
{
|
|
greenzone->invalidateAndUpdatePlayback(history->registerChanges(MODTYPE_SET, min_row_index, max_row_index, 0, NULL, drawingStartTimestamp));
|
|
}
|
|
else
|
|
{
|
|
greenzone->invalidateAndUpdatePlayback(history->registerChanges(MODTYPE_UNSET, min_row_index, max_row_index, 0, NULL, drawingStartTimestamp));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case DRAG_MODE_SELECTION:
|
|
{
|
|
int new_drag_selection_ending_frame = realRowUnderMouse;
|
|
// if trying to select above Piano Roll, select from frame 0
|
|
if (new_drag_selection_ending_frame < 0)
|
|
new_drag_selection_ending_frame = 0;
|
|
else if (new_drag_selection_ending_frame >= currMovieData.getNumRecords())
|
|
new_drag_selection_ending_frame = currMovieData.getNumRecords() - 1;
|
|
if (new_drag_selection_ending_frame >= 0 && new_drag_selection_ending_frame != dragSelectionEndingFrame)
|
|
{
|
|
// change Selection shape
|
|
if (new_drag_selection_ending_frame >= dragSelectionStartingFrame)
|
|
{
|
|
// selecting from upper to lower
|
|
if (dragSelectionEndingFrame < dragSelectionStartingFrame)
|
|
{
|
|
selection->clearRegionOfRowsSelection(dragSelectionEndingFrame, dragSelectionStartingFrame);
|
|
selection->setRegionOfRowsSelection(dragSelectionStartingFrame, new_drag_selection_ending_frame + 1);
|
|
} else // both ending_frame and new_ending_frame are >= starting_frame
|
|
{
|
|
if (dragSelectionEndingFrame > new_drag_selection_ending_frame)
|
|
selection->clearRegionOfRowsSelection(new_drag_selection_ending_frame + 1, dragSelectionEndingFrame + 1);
|
|
else
|
|
selection->setRegionOfRowsSelection(dragSelectionEndingFrame + 1, new_drag_selection_ending_frame + 1);
|
|
}
|
|
} else
|
|
{
|
|
// selecting from lower to upper
|
|
if (dragSelectionEndingFrame > dragSelectionStartingFrame)
|
|
{
|
|
selection->clearRegionOfRowsSelection(dragSelectionStartingFrame + 1, dragSelectionEndingFrame + 1);
|
|
selection->setRegionOfRowsSelection(new_drag_selection_ending_frame, dragSelectionStartingFrame);
|
|
} else // both ending_frame and new_ending_frame are <= starting_frame
|
|
{
|
|
if (dragSelectionEndingFrame < new_drag_selection_ending_frame)
|
|
selection->clearRegionOfRowsSelection(dragSelectionEndingFrame, new_drag_selection_ending_frame);
|
|
else
|
|
selection->setRegionOfRowsSelection(new_drag_selection_ending_frame, dragSelectionEndingFrame);
|
|
}
|
|
}
|
|
dragSelectionEndingFrame = new_drag_selection_ending_frame;
|
|
}
|
|
break;
|
|
}
|
|
case DRAG_MODE_DESELECTION:
|
|
{
|
|
int new_drag_selection_ending_frame = realRowUnderMouse;
|
|
// if trying to deselect above Piano Roll, deselect from frame 0
|
|
if (new_drag_selection_ending_frame < 0)
|
|
new_drag_selection_ending_frame = 0;
|
|
else if (new_drag_selection_ending_frame >= currMovieData.getNumRecords())
|
|
new_drag_selection_ending_frame = currMovieData.getNumRecords() - 1;
|
|
if (new_drag_selection_ending_frame >= 0 && new_drag_selection_ending_frame != dragSelectionEndingFrame)
|
|
{
|
|
// change Deselection shape
|
|
if (new_drag_selection_ending_frame >= dragSelectionStartingFrame)
|
|
{
|
|
// deselecting from upper to lower
|
|
selection->clearRegionOfRowsSelection(dragSelectionStartingFrame, new_drag_selection_ending_frame + 1);
|
|
}
|
|
else
|
|
{
|
|
// deselecting from lower to upper
|
|
selection->clearRegionOfRowsSelection(new_drag_selection_ending_frame, dragSelectionStartingFrame + 1);
|
|
}
|
|
dragSelectionEndingFrame = new_drag_selection_ending_frame;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::handleColumnSet(int column, bool altPressed)
|
|
{
|
|
if (column == COLUMN_FRAMENUM || column == COLUMN_FRAMENUM2)
|
|
{
|
|
// user clicked on "Frame#" - apply ColumnSet to Markers
|
|
if (altPressed)
|
|
{
|
|
if (parent->handleColumnSetUsingPattern())
|
|
{
|
|
setLightInHeaderColumn(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (parent->handleColumnSet())
|
|
{
|
|
setLightInHeaderColumn(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// user clicked on Input column - apply ColumnSet to Input
|
|
int joy = (column - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS;
|
|
int button = (column - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS;
|
|
if (altPressed)
|
|
{
|
|
if (parent->handleInputColumnSetUsingPattern(joy, button))
|
|
{
|
|
setLightInHeaderColumn(column, HEADER_LIGHT_MAX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (parent->handleInputColumnSet(joy, button))
|
|
{
|
|
setLightInHeaderColumn(column, HEADER_LIGHT_MAX);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::periodicUpdate(void)
|
|
{
|
|
// scroll Piano Roll if user is dragging cursor outside
|
|
if ( (dragMode != DRAG_MODE_NONE) || rightButtonDragMode)
|
|
{
|
|
int x, y, line, col, scroll_up_threshold, scroll_down_threshold;
|
|
QPoint p, c;
|
|
|
|
x = mouse_x;
|
|
y = mouse_y;
|
|
|
|
p.setX(x);
|
|
p.setY(y);
|
|
|
|
c = convPixToCursor(p);
|
|
|
|
if ( c.y() >= 0 )
|
|
{
|
|
line = lineOffset + c.y();
|
|
}
|
|
else
|
|
{
|
|
line = lineOffset;
|
|
}
|
|
col = calcColumn( c.x() );
|
|
|
|
rowUnderMouse = realRowUnderMouse = line;
|
|
columnUnderMouse = col;
|
|
|
|
scroll_up_threshold = pxLineSpacing;
|
|
scroll_down_threshold = (viewHeight - pxLineSpacing/2);
|
|
|
|
//if (dragMode != DRAG_MODE_MARKER) // in DRAG_MODE_MARKER user can't scroll Piano Roll horizontally
|
|
//{
|
|
// if (p.x < DRAG_SCROLLING_BORDER_SIZE)
|
|
// scroll_dx = p.x - DRAG_SCROLLING_BORDER_SIZE;
|
|
// else if (p.x > (wrect.right - wrect.left - DRAG_SCROLLING_BORDER_SIZE))
|
|
// scroll_dx = p.x - (wrect.right - wrect.left - DRAG_SCROLLING_BORDER_SIZE);
|
|
//}
|
|
if (y < scroll_up_threshold )
|
|
{
|
|
scroll_y += (scroll_up_threshold - y);
|
|
|
|
if ( scroll_y > pxLineSpacing )
|
|
{
|
|
int d, v = vbar->value();
|
|
|
|
d = scroll_y / pxLineSpacing;
|
|
|
|
v -= d; scroll_y = 0;
|
|
|
|
if ( v < 0 )
|
|
{
|
|
v = 0;
|
|
}
|
|
else if ( v > maxLineOffset )
|
|
{
|
|
v = maxLineOffset;
|
|
}
|
|
vbar->setValue(v);
|
|
}
|
|
}
|
|
else if (y > scroll_down_threshold)
|
|
{
|
|
scroll_y += (scroll_down_threshold - y);
|
|
|
|
if ( scroll_y < -pxLineSpacing )
|
|
{
|
|
int d, v = vbar->value();
|
|
|
|
d = scroll_y / pxLineSpacing;
|
|
|
|
v -= d; scroll_y = 0;
|
|
|
|
if ( v < 0 )
|
|
{
|
|
v = 0;
|
|
}
|
|
else if ( v > maxLineOffset )
|
|
{
|
|
v = maxLineOffset;
|
|
}
|
|
vbar->setValue(v);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
scroll_x = scroll_y = 0;
|
|
}
|
|
|
|
updateDrag();
|
|
|
|
// once per 40 milliseconds update colors alpha in the Header
|
|
if (getTasEditorTime() > nextHeaderUpdateTime)
|
|
{
|
|
nextHeaderUpdateTime = getTasEditorTime() + HEADER_LIGHT_UPDATE_TICK;
|
|
bool changes_made = false;
|
|
int light_value = 0;
|
|
// 1 - update Frame# columns' heads
|
|
//if (GetAsyncKeyState(VK_MENU) & 0x8000) light_value = HEADER_LIGHT_HOLD; else
|
|
if (dragMode == DRAG_MODE_NONE && (headerItemUnderMouse == COLUMN_FRAMENUM || headerItemUnderMouse == COLUMN_FRAMENUM2))
|
|
{
|
|
light_value = (selection->getCurrentRowsSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER;
|
|
}
|
|
if (headerColors[COLUMN_FRAMENUM] < light_value)
|
|
{
|
|
headerColors[COLUMN_FRAMENUM]++;
|
|
changes_made = true;
|
|
}
|
|
else if (headerColors[COLUMN_FRAMENUM] > light_value)
|
|
{
|
|
headerColors[COLUMN_FRAMENUM]--;
|
|
changes_made = true;
|
|
}
|
|
headerColors[COLUMN_FRAMENUM2] = headerColors[COLUMN_FRAMENUM];
|
|
// 2 - update Input columns' heads
|
|
int i = numColumns-1;
|
|
if (i == COLUMN_FRAMENUM2) i--;
|
|
for (; i >= COLUMN_JOYPAD1_A; i--)
|
|
{
|
|
light_value = 0;
|
|
if (recorder->currentJoypadData[(i - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS] & (1 << ((i - COLUMN_JOYPAD1_A) % NUM_JOYPAD_BUTTONS)))
|
|
{
|
|
light_value = HEADER_LIGHT_HOLD;
|
|
}
|
|
else if (dragMode == DRAG_MODE_NONE && headerItemUnderMouse == i)
|
|
{
|
|
light_value = (selection->getCurrentRowsSelectionSize() > 0) ? HEADER_LIGHT_MOUSEOVER_SEL : HEADER_LIGHT_MOUSEOVER;
|
|
}
|
|
|
|
if (headerColors[i] < light_value)
|
|
{
|
|
headerColors[i]++;
|
|
changes_made = true;
|
|
}
|
|
else if (headerColors[i] > light_value)
|
|
{
|
|
headerColors[i]--;
|
|
changes_made = true;
|
|
}
|
|
}
|
|
// 3 - redraw
|
|
if (changes_made)
|
|
{
|
|
update();
|
|
}
|
|
}
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::setLightInHeaderColumn(int column, int level)
|
|
{
|
|
if (column < COLUMN_FRAMENUM || column >= numColumns || level < 0 || level > HEADER_LIGHT_MAX)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (headerColors[column] != level)
|
|
{
|
|
headerColors[column] = level;
|
|
//redrawHeader();
|
|
nextHeaderUpdateTime = getTasEditorTime() + HEADER_LIGHT_UPDATE_TICK;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::followSelection(void)
|
|
{
|
|
RowsSelection* current_selection = selection->getCopyOfCurrentRowsSelection();
|
|
if (current_selection->size() == 0) return;
|
|
|
|
int list_items = viewLines - 1;
|
|
int selection_start = *current_selection->begin();
|
|
int selection_end = *current_selection->rbegin();
|
|
int selection_items = 1 + selection_end - selection_start;
|
|
|
|
if (selection_items <= list_items)
|
|
{
|
|
// selected region can fit in screen
|
|
int lower_border = (list_items - selection_items) / 2;
|
|
int upper_border = (list_items - selection_items) - lower_border;
|
|
int index = selection_end + lower_border;
|
|
if (index >= currMovieData.getNumRecords())
|
|
{
|
|
index = currMovieData.getNumRecords()-1;
|
|
}
|
|
ensureTheLineIsVisible(index);
|
|
|
|
index = selection_start - upper_border;
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
ensureTheLineIsVisible(index);
|
|
}
|
|
else
|
|
{
|
|
// selected region is too big to fit in screen
|
|
// oh well, just center at selection_start
|
|
centerListAroundLine(selection_start);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::followMarker(int markerID)
|
|
{
|
|
if (markerID > 0)
|
|
{
|
|
int frame = markersManager->getMarkerFrameNumber(markerID);
|
|
if (frame >= 0)
|
|
{
|
|
centerListAroundLine(frame);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ensureTheLineIsVisible(0);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::followPlaybackCursor(void)
|
|
{
|
|
centerListAroundLine(currFrameCounter);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::followPlaybackCursorIfNeeded(bool followPauseframe)
|
|
{
|
|
if (taseditorConfig->followPlaybackCursor)
|
|
{
|
|
if (playback->getPauseFrame() < 0)
|
|
{
|
|
ensureTheLineIsVisible( currFrameCounter );
|
|
}
|
|
else if (followPauseframe)
|
|
{
|
|
ensureTheLineIsVisible( playback->getPauseFrame() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::followPauseframe(void)
|
|
{
|
|
if (playback->getPauseFrame() >= 0)
|
|
{
|
|
centerListAroundLine(playback->getPauseFrame());
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::followUndoHint(void)
|
|
{
|
|
int keyframe = history->getUndoHint();
|
|
if (taseditorConfig->followUndoContext && keyframe >= 0)
|
|
{
|
|
if (!lineIsVisible(keyframe))
|
|
{
|
|
centerListAroundLine(keyframe);
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::centerListAroundLine(int rowIndex)
|
|
{
|
|
int numItemsPerPage = viewLines - 1;
|
|
int lowerBorder = (numItemsPerPage - 1) / 2;
|
|
int upperBorder = (numItemsPerPage - 1) - lowerBorder;
|
|
int index = rowIndex + lowerBorder;
|
|
if (index >= currMovieData.getNumRecords())
|
|
{
|
|
index = currMovieData.getNumRecords()-1;
|
|
}
|
|
ensureTheLineIsVisible(index);
|
|
|
|
index = rowIndex - upperBorder;
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
ensureTheLineIsVisible(index);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
|
|
void QPianoRoll::startDraggingPlaybackCursor(void)
|
|
{
|
|
if (dragMode == DRAG_MODE_NONE)
|
|
{
|
|
dragMode = DRAG_MODE_PLAYBACK;
|
|
// call it once
|
|
handlePlaybackCursorDragging();
|
|
}
|
|
}
|
|
void QPianoRoll::setupMarkerDrag(void)
|
|
{
|
|
if ( QApplication::mouseButtons() & Qt::LeftButton )
|
|
{
|
|
startDraggingMarker( mouse_x, mouse_y, rowUnderMouseAtPress, columnUnderMouseAtPress);
|
|
}
|
|
else
|
|
{
|
|
tasWin->lowerMarkerNote->setFocus();
|
|
}
|
|
}
|
|
|
|
void QPianoRoll::startDraggingMarker(int mouseX, int mouseY, int rowIndex, int columnIndex)
|
|
{
|
|
if (dragMode == DRAG_MODE_NONE)
|
|
{
|
|
QColor bgColor = (taseditorConfig->bindMarkersToInput) ? QColor( BINDMARKED_FRAMENUM_COLOR ) : QColor( MARKED_FRAMENUM_COLOR );
|
|
|
|
QSize iconSize(pxWidthFrameCol, pxLineSpacing);
|
|
|
|
mkrDrag = new markerDragPopup(this);
|
|
mkrDrag->resize( iconSize );
|
|
mkrDrag->setInitialPosition( QCursor::pos() );
|
|
|
|
mkrDrag->setBgColor( bgColor );
|
|
mkrDrag->setRowIndex( rowIndex );
|
|
|
|
font.setItalic(true);
|
|
font.setBold(false);
|
|
mkrDrag->setFont(font);
|
|
font.setItalic(false);
|
|
font.setBold(true);
|
|
|
|
// start dragging the Marker
|
|
dragMode = DRAG_MODE_MARKER;
|
|
markerDragFrameNumber = rowIndex;
|
|
markerDragCountdown = MARKER_DRAG_COUNTDOWN_MAX;
|
|
setCursor( Qt::ClosedHandCursor );
|
|
|
|
connect(mkrDrag, &QDialog::destroyed, this,[=]
|
|
{
|
|
if ( mkrDrag == sender() )
|
|
{
|
|
//printf("Drag Destroyed\n");
|
|
mkrDrag = NULL;
|
|
}
|
|
});
|
|
|
|
mkrDrag->show();
|
|
|
|
update();
|
|
}
|
|
}
|
|
void QPianoRoll::startSelectingDrag(int start_frame)
|
|
{
|
|
if (dragMode == DRAG_MODE_NONE)
|
|
{
|
|
dragMode = DRAG_MODE_SELECTION;
|
|
dragSelectionStartingFrame = start_frame;
|
|
dragSelectionEndingFrame = dragSelectionStartingFrame; // assuming that start_frame is already selected
|
|
}
|
|
}
|
|
void QPianoRoll::startDeselectingDrag(int start_frame)
|
|
{
|
|
if (dragMode == DRAG_MODE_NONE)
|
|
{
|
|
dragMode = DRAG_MODE_DESELECTION;
|
|
dragSelectionStartingFrame = start_frame;
|
|
dragSelectionEndingFrame = dragSelectionStartingFrame; // assuming that start_frame is already deselected
|
|
}
|
|
}
|
|
|
|
void QPianoRoll::handlePlaybackCursorDragging(void)
|
|
{
|
|
int target_frame = realRowUnderMouse;
|
|
if (target_frame < 0)
|
|
{
|
|
target_frame = 0;
|
|
}
|
|
if (currFrameCounter != target_frame)
|
|
{
|
|
playback->jump(target_frame);
|
|
}
|
|
}
|
|
|
|
void QPianoRoll::finishDrag(void)
|
|
{
|
|
switch (dragMode)
|
|
{
|
|
case DRAG_MODE_MARKER:
|
|
{
|
|
// place Marker here
|
|
if (markersManager->getMarkerAtFrame(markerDragFrameNumber))
|
|
{
|
|
//POINT p = {0, 0};
|
|
//GetCursorPos(&p);
|
|
//int mouse_x = p.x, mouse_y = p.y;
|
|
//ScreenToClient(hwndList, &p);
|
|
//RECT wrect;
|
|
//GetClientRect(hwndList, &wrect);
|
|
if (mouse_x < 0 || mouse_x > viewWidth || mouse_y < 0 || mouse_y > viewHeight)
|
|
{
|
|
// user threw the Marker away
|
|
markersManager->removeMarkerFromFrame(markerDragFrameNumber);
|
|
//redrawRow(markerDragFrameNumber);
|
|
history->registerMarkersChange(MODTYPE_MARKER_REMOVE, markerDragFrameNumber);
|
|
selection->mustFindCurrentMarker = playback->mustFindCurrentMarker = true;
|
|
// calculate vector of movement
|
|
if ( mkrDrag )
|
|
{
|
|
mkrDrag->throwAway();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rowUnderMouse >= 0 && (columnUnderMouse <= COLUMN_FRAMENUM || columnUnderMouse >= COLUMN_FRAMENUM2))
|
|
{
|
|
if (rowUnderMouse == markerDragFrameNumber)
|
|
{
|
|
// it was just double-click and release
|
|
// if Selection points at dragged Marker, set focus to lower Note edit field
|
|
int dragged_marker_id = markersManager->getMarkerAtFrame(markerDragFrameNumber);
|
|
int selection_marker_id = markersManager->getMarkerAboveFrame(selection->getCurrentRowsSelectionBeginning());
|
|
if (dragged_marker_id == selection_marker_id)
|
|
{
|
|
//SetFocus(selection.hwndSelectionMarkerEditField);
|
|
// select all text in case user wants to overwrite it
|
|
//SendMessage(selection.hwndSelectionMarkerEditField, EM_SETSEL, 0, -1);
|
|
tasWin->lowerMarkerNote->setFocus();
|
|
}
|
|
}
|
|
else if (markersManager->getMarkerAtFrame(rowUnderMouse))
|
|
{
|
|
int dragged_marker_id = markersManager->getMarkerAtFrame(markerDragFrameNumber);
|
|
int destination_marker_id = markersManager->getMarkerAtFrame(rowUnderMouse);
|
|
// swap Notes of these Markers
|
|
char dragged_marker_note[MAX_NOTE_LEN];
|
|
strcpy(dragged_marker_note, markersManager->getNoteCopy(dragged_marker_id).c_str());
|
|
if (strcmp(markersManager->getNoteCopy(destination_marker_id).c_str(), dragged_marker_note))
|
|
{
|
|
// notes are different, swap them
|
|
markersManager->setNote(dragged_marker_id, markersManager->getNoteCopy(destination_marker_id).c_str());
|
|
markersManager->setNote(destination_marker_id, dragged_marker_note);
|
|
history->registerMarkersChange(MODTYPE_MARKER_SWAP, markerDragFrameNumber, rowUnderMouse);
|
|
selection->mustFindCurrentMarker = playback->mustFindCurrentMarker = true;
|
|
setLightInHeaderColumn(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// move Marker
|
|
int new_marker_id = markersManager->setMarkerAtFrame(rowUnderMouse);
|
|
if (new_marker_id)
|
|
{
|
|
markersManager->setNote(new_marker_id, markersManager->getNoteCopy(markersManager->getMarkerAtFrame(markerDragFrameNumber)).c_str());
|
|
// and delete it from old frame
|
|
markersManager->removeMarkerFromFrame(markerDragFrameNumber);
|
|
history->registerMarkersChange(MODTYPE_MARKER_DRAG, markerDragFrameNumber, rowUnderMouse, markersManager->getNoteCopy(markersManager->getMarkerAtFrame(rowUnderMouse)).c_str());
|
|
selection->mustFindCurrentMarker = playback->mustFindCurrentMarker = true;
|
|
setLightInHeaderColumn(COLUMN_FRAMENUM, HEADER_LIGHT_MAX);
|
|
//redrawRow(rowUnderMouse);
|
|
}
|
|
}
|
|
if ( mkrDrag )
|
|
{
|
|
mkrDrag->dropAccept();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( mkrDrag )
|
|
{
|
|
mkrDrag->dropAbort();
|
|
}
|
|
}
|
|
|
|
//redrawRow(markerDragFrameNumber);
|
|
//if (hwndMarkerDragBox)
|
|
//{
|
|
// DestroyWindow(hwndMarkerDragBox);
|
|
// hwndMarkerDragBox = 0;
|
|
//}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// abort drag
|
|
if ( mkrDrag )
|
|
{
|
|
mkrDrag->dropAbort();
|
|
}
|
|
//if (hwndMarkerDragBox)
|
|
//{
|
|
// DestroyWindow(hwndMarkerDragBox);
|
|
// hwndMarkerDragBox = 0;
|
|
//}
|
|
}
|
|
//if ( mkrDrag )
|
|
//{
|
|
// mkrDrag->done(0);
|
|
// mkrDrag->deleteLater();
|
|
//}
|
|
setCursor( Qt::ArrowCursor );
|
|
}
|
|
break;
|
|
}
|
|
dragMode = DRAG_MODE_NONE;
|
|
//mustCheckItemUnderMouse = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void QPianoRoll::paintEvent(QPaintEvent *event)
|
|
{
|
|
FCEU_CRITICAL_SECTION( emuLock );
|
|
int x, y, row, nrow, lineNum;
|
|
QPainter painter(this);
|
|
QColor /*white(255,255,255),*/ black(0,0,0), blkColor, rowTextColor, hdrGridColor;
|
|
static const char *buttonNames[] = { "A", "B", "S", "T", "U", "D", "L", "R", NULL };
|
|
char stmp[32];
|
|
char rowIsSel=0;
|
|
char rowSelArray[256];
|
|
int numSelRows=0;
|
|
QRect rect;
|
|
|
|
font.setBold(true);
|
|
painter.setFont(font);
|
|
viewWidth = event->rect().width();
|
|
viewHeight = event->rect().height();
|
|
|
|
nrow = (viewHeight / pxLineSpacing) + 1;
|
|
|
|
if ( nrow < 1 ) nrow = 1;
|
|
|
|
memset( rowSelArray, 0, nrow+1 );
|
|
|
|
viewLines = nrow;
|
|
|
|
maxLineOffset = currMovieData.records.size() - nrow + 2;
|
|
|
|
vbar->setMinimum(0);
|
|
vbar->setMaximum(maxLineOffset);
|
|
|
|
if ( maxLineOffset < 0 )
|
|
{
|
|
vbar->hide();
|
|
maxLineOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
vbar->show();
|
|
}
|
|
|
|
if ( taseditorConfig->followPlaybackCursor )
|
|
{
|
|
lineOffset = vbar->value();
|
|
|
|
if ( playbackCursorPos != currFrameCounter )
|
|
{
|
|
int lineOffsetLowerLim, lineOffsetUpperLim;
|
|
|
|
playbackCursorPos = currFrameCounter;
|
|
|
|
lineOffsetLowerLim = lineOffset;
|
|
lineOffsetUpperLim = lineOffset + nrow - 2;
|
|
|
|
if ( playbackCursorPos < lineOffsetLowerLim )
|
|
{
|
|
lineOffset = playbackCursorPos;
|
|
vbar->setValue( lineOffset );
|
|
}
|
|
else if ( playbackCursorPos >= lineOffsetUpperLim )
|
|
{
|
|
lineOffset = playbackCursorPos - nrow + 3;
|
|
if ( lineOffset < 0 )
|
|
{
|
|
lineOffset = 0;
|
|
}
|
|
vbar->setValue( lineOffset );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vbar->setValue( lineOffset );
|
|
}
|
|
|
|
if ( lineOffset < 0 )
|
|
{
|
|
lineOffset = 0;
|
|
}
|
|
if ( lineOffset > maxLineOffset )
|
|
{
|
|
lineOffset = maxLineOffset;
|
|
}
|
|
|
|
painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Window) );
|
|
|
|
// Draw Title Bar
|
|
x = -pxLineXScroll; y = 0;
|
|
painter.fillRect( 0, 0, viewWidth, pxLineSpacing, windowColor );
|
|
painter.setPen( black );
|
|
|
|
//font.setBold(true);
|
|
//painter.setFont(font);
|
|
|
|
rect = painter.fontMetrics().boundingRect( tr("Frame#") );
|
|
|
|
//x = -pxLineXScroll + pxFrameColX + (pxWidthFrameCol - 6*pxCharWidth) / 2;
|
|
x = -pxLineXScroll + pxFrameColX + (pxWidthFrameCol - rect.width()) / 2;
|
|
|
|
painter.drawText( x, pxLineTextOfs, tr("Frame#") );
|
|
|
|
//rect = QRect( -pxLineXScroll + pxFrameColX, 0, pxWidthFrameCol, pxLineSpacing );
|
|
//painter.drawText( rect, Qt::AlignCenter, tr("Frame#") );
|
|
//painter.drawText( rect, Qt::AlignHCenter | Qt::AlignBottom, tr("Frame#") );
|
|
|
|
//font.setBold(false);
|
|
//painter.setFont(font);
|
|
|
|
// Draw Grid
|
|
painter.drawLine( -pxLineXScroll, 0, -pxLineXScroll, viewHeight );
|
|
|
|
//x = pxFrameColX - pxLineXScroll;
|
|
//painter.drawLine( x, 0, x, viewHeight );
|
|
|
|
for (int i=0; i<numCtlr; i++)
|
|
{
|
|
x = pxFrameCtlX[i] - pxLineXScroll;
|
|
|
|
if ( i % 2 )
|
|
{
|
|
painter.fillRect( x, pxLineSpacing, pxWidthCtlCol, viewHeight, this->palette().color(QPalette::AlternateBase) );
|
|
}
|
|
}
|
|
|
|
y = pxLineSpacing;
|
|
|
|
for (row=0; row<nrow; row++)
|
|
{
|
|
uint8_t data;
|
|
|
|
lineNum = lineOffset + row;
|
|
|
|
if ( static_cast<size_t>(lineNum) >= currMovieData.records.size() )
|
|
{
|
|
break;
|
|
}
|
|
int frame_lag = greenzone->lagLog.getLagInfoAtFrame(lineNum);
|
|
|
|
rowSelArray[row] = rowIsSel = selection->isRowSelected( lineNum );
|
|
|
|
for (int i=0; i<numCtlr; i++)
|
|
{
|
|
x = pxFrameCtlX[i] - pxLineXScroll;
|
|
|
|
if ( lineNum == history->getUndoHint())
|
|
{
|
|
// undo hint here
|
|
blkColor = (i%2) ? QColor(UNDOHINT_INPUT_COLOR2) : QColor(UNDOHINT_INPUT_COLOR1);
|
|
}
|
|
else if ( lineNum == currFrameCounter || lineNum == (playback->getFlashingPauseFrame() - 1))
|
|
{
|
|
// this is current frame
|
|
blkColor = (i%2) ? QColor(CUR_INPUT_COLOR2) : QColor(CUR_INPUT_COLOR1);
|
|
}
|
|
else if ( lineNum < greenzone->getSize() )
|
|
{
|
|
if (!greenzone->isSavestateEmpty(lineNum))
|
|
{
|
|
// the frame is normal Greenzone frame
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = (i%2) ? QColor(LAG_INPUT_COLOR2) : QColor(LAG_INPUT_COLOR1);
|
|
}
|
|
else
|
|
{
|
|
blkColor = (i%2) ? QColor(GREENZONE_INPUT_COLOR2) : QColor(GREENZONE_INPUT_COLOR1);
|
|
}
|
|
}
|
|
else if ( !greenzone->isSavestateEmpty(lineNum & EVERY16TH)
|
|
|| !greenzone->isSavestateEmpty(lineNum & EVERY8TH)
|
|
|| !greenzone->isSavestateEmpty(lineNum & EVERY4TH)
|
|
|| !greenzone->isSavestateEmpty(lineNum & EVERY2ND))
|
|
{
|
|
// the frame is in a gap (in Greenzone tail)
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = (i%2) ? QColor(PALE_LAG_INPUT_COLOR2) : QColor(PALE_LAG_INPUT_COLOR1);
|
|
}
|
|
else
|
|
{
|
|
blkColor = (i%2) ? QColor(PALE_GREENZONE_INPUT_COLOR2) : QColor(PALE_GREENZONE_INPUT_COLOR1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the frame is above Greenzone tail
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = (i%2) ? QColor(VERY_PALE_LAG_INPUT_COLOR2) : QColor(VERY_PALE_LAG_INPUT_COLOR1);
|
|
}
|
|
else if (frame_lag == LAGGED_NO)
|
|
{
|
|
blkColor = (i%2) ? QColor(VERY_PALE_GREENZONE_INPUT_COLOR2) : QColor(VERY_PALE_GREENZONE_INPUT_COLOR1);
|
|
}
|
|
else
|
|
{
|
|
blkColor = (i%2) ? QColor(NORMAL_INPUT_COLOR2) : QColor(NORMAL_INPUT_COLOR1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the frame is below Greenzone head
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = (i%2) ? QColor(VERY_PALE_LAG_INPUT_COLOR2) : QColor(VERY_PALE_LAG_INPUT_COLOR1);
|
|
}
|
|
else if (frame_lag == LAGGED_NO)
|
|
{
|
|
blkColor = (i%2) ? QColor(VERY_PALE_GREENZONE_INPUT_COLOR2) : QColor(VERY_PALE_GREENZONE_INPUT_COLOR1);
|
|
}
|
|
else
|
|
{
|
|
blkColor = (i%2) ? QColor(NORMAL_INPUT_COLOR2) : QColor(NORMAL_INPUT_COLOR1);
|
|
}
|
|
}
|
|
painter.fillRect( x, y, pxWidthCtlCol, pxLineSpacing, blkColor );
|
|
}
|
|
|
|
// Frame number column
|
|
// font
|
|
//if (markersManager.getMarkerAtFrame(lineNum))
|
|
// SelectObject(msg->nmcd.hdc, hMainListSelectFont);
|
|
//else
|
|
// SelectObject(msg->nmcd.hdc, hMainListFont);
|
|
// bg
|
|
// frame number
|
|
if (lineNum == history->getUndoHint())
|
|
{
|
|
// undo hint here
|
|
if (markersManager->getMarkerAtFrame(lineNum) && (dragMode != DRAG_MODE_MARKER || markerDragFrameNumber != lineNum))
|
|
{
|
|
blkColor = (taseditorConfig->bindMarkersToInput) ? QColor( BINDMARKED_UNDOHINT_FRAMENUM_COLOR ) : QColor( MARKED_UNDOHINT_FRAMENUM_COLOR );
|
|
}
|
|
else
|
|
{
|
|
blkColor = QColor( UNDOHINT_FRAMENUM_COLOR );
|
|
}
|
|
}
|
|
else if (lineNum == currFrameCounter || lineNum == (playback->getFlashingPauseFrame() - 1))
|
|
{
|
|
// this is current frame
|
|
if (markersManager->getMarkerAtFrame(lineNum) && (dragMode != DRAG_MODE_MARKER || markerDragFrameNumber != lineNum))
|
|
{
|
|
blkColor = (taseditorConfig->bindMarkersToInput) ? QColor( CUR_BINDMARKED_FRAMENUM_COLOR ) : QColor( CUR_MARKED_FRAMENUM_COLOR );
|
|
}
|
|
else
|
|
{
|
|
blkColor = QColor( CUR_FRAMENUM_COLOR );
|
|
}
|
|
}
|
|
else if (markersManager->getMarkerAtFrame(lineNum) && (dragMode != DRAG_MODE_MARKER || markerDragFrameNumber != lineNum))
|
|
{
|
|
// this is marked frame
|
|
blkColor = (taseditorConfig->bindMarkersToInput) ? QColor( BINDMARKED_FRAMENUM_COLOR ) : QColor( MARKED_FRAMENUM_COLOR );
|
|
}
|
|
else if (lineNum < greenzone->getSize())
|
|
{
|
|
if (!greenzone->isSavestateEmpty(lineNum))
|
|
{
|
|
// the frame is normal Greenzone frame
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = QColor( LAG_FRAMENUM_COLOR );
|
|
}
|
|
else
|
|
{
|
|
blkColor = QColor( GREENZONE_FRAMENUM_COLOR );
|
|
}
|
|
}
|
|
else if (!greenzone->isSavestateEmpty(lineNum & EVERY16TH)
|
|
|| !greenzone->isSavestateEmpty(lineNum & EVERY8TH)
|
|
|| !greenzone->isSavestateEmpty(lineNum & EVERY4TH)
|
|
|| !greenzone->isSavestateEmpty(lineNum & EVERY2ND))
|
|
{
|
|
// the frame is in a gap (in Greenzone tail)
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = QColor( PALE_LAG_FRAMENUM_COLOR );
|
|
}
|
|
else
|
|
{
|
|
blkColor = QColor( PALE_GREENZONE_FRAMENUM_COLOR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the frame is above Greenzone tail
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = QColor( VERY_PALE_LAG_FRAMENUM_COLOR );
|
|
}
|
|
else if (frame_lag == LAGGED_NO)
|
|
{
|
|
blkColor = QColor( VERY_PALE_GREENZONE_FRAMENUM_COLOR );
|
|
}
|
|
else
|
|
{
|
|
blkColor = QColor( NORMAL_FRAMENUM_COLOR );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the frame is below Greenzone head
|
|
if (frame_lag == LAGGED_YES)
|
|
{
|
|
blkColor = QColor( VERY_PALE_LAG_FRAMENUM_COLOR );
|
|
}
|
|
else if (frame_lag == LAGGED_NO)
|
|
{
|
|
blkColor = QColor( VERY_PALE_GREENZONE_FRAMENUM_COLOR );
|
|
}
|
|
else
|
|
{
|
|
blkColor = QColor( NORMAL_FRAMENUM_COLOR );
|
|
}
|
|
}
|
|
x = -pxLineXScroll + pxFrameColX;
|
|
|
|
painter.fillRect( x, y, pxWidthFrameCol, pxLineSpacing, blkColor );
|
|
|
|
// Selected Line
|
|
if ( rowIsSel )
|
|
{
|
|
painter.fillRect( 0, y, viewWidth, pxLineSpacing, QColor( 10, 36, 106 ) );
|
|
|
|
rowTextColor = QColor( 255, 255, 255 );
|
|
|
|
numSelRows++;
|
|
}
|
|
else
|
|
{
|
|
rowTextColor = QColor( 0, 0, 0 );
|
|
}
|
|
painter.setPen( rowTextColor );
|
|
|
|
for (int i=0; i<numCtlr; i++)
|
|
{
|
|
int ctlrOfs, btnOfs, hotChangeVal;
|
|
data = currMovieData.records[ lineNum ].joysticks[i];
|
|
|
|
x = pxFrameCtlX[i] - pxLineXScroll;
|
|
|
|
ctlrOfs = i*8;
|
|
|
|
for (int j=0; j<8; j++)
|
|
{
|
|
btnOfs = ctlrOfs+j;
|
|
|
|
if (taseditorConfig->enableHotChanges)
|
|
{
|
|
hotChangeVal = history->getCurrentSnapshot().inputlog.getHotChangesInfo( lineNum, btnOfs );
|
|
|
|
if ( !rowIsSel && (hotChangeVal >= 0) && (hotChangeVal < 16) )
|
|
{
|
|
painter.setPen( hotChangesColors[hotChangeVal] );
|
|
}
|
|
else
|
|
{
|
|
painter.setPen( rowTextColor );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hotChangeVal = -1;
|
|
}
|
|
rect = QRect( x, y, pxWidthBtnCol, pxLineSpacing );
|
|
|
|
if ( data & (0x01 << j) )
|
|
{
|
|
painter.drawText( x + pxCharWidth, y+pxLineTextOfs, tr(buttonNames[j]) );
|
|
//painter.drawText( rect, Qt::AlignCenter, tr(buttonNames[j]) );
|
|
//painter.drawText( rect, Qt::AlignHCenter | Qt::AlignBottom, tr(buttonNames[j]) );
|
|
}
|
|
else if ( hotChangeVal > 0 )
|
|
{
|
|
painter.drawText( x + pxCharWidth, y+pxLineTextOfs, tr("-") );
|
|
//painter.drawText( rect, Qt::AlignCenter, tr("-") );
|
|
//painter.drawText( rect, Qt::AlignHCenter | Qt::AlignBottom, tr("-") );
|
|
}
|
|
x += pxWidthBtnCol;
|
|
}
|
|
//painter.drawLine( x, y, x, pxLineSpacing );
|
|
}
|
|
|
|
// Frame number column
|
|
// font
|
|
//if (markersManager.getMarkerAtFrame(lineNum))
|
|
// SelectObject(msg->nmcd.hdc, hMainListSelectFont);
|
|
//else
|
|
// SelectObject(msg->nmcd.hdc, hMainListFont);
|
|
// bg
|
|
painter.setPen( rowTextColor );
|
|
|
|
//rect = QRect( -pxLineXScroll + pxFrameColX, y, pxWidthFrameCol, pxLineSpacing );
|
|
|
|
snprintf( stmp, sizeof(stmp), "%07i", lineNum );
|
|
|
|
rect = painter.fontMetrics().boundingRect( tr(stmp) );
|
|
|
|
x = -pxLineXScroll + pxFrameColX + (pxWidthFrameCol - rect.width()) / 2;
|
|
|
|
if (markersManager->getMarkerAtFrame(lineNum))
|
|
{
|
|
font.setItalic(true);
|
|
font.setBold(false);
|
|
}
|
|
else
|
|
{
|
|
font.setBold(true);
|
|
font.setItalic(false);
|
|
}
|
|
painter.setFont(font);
|
|
painter.drawText( x, y+pxLineTextOfs, tr(stmp) );
|
|
//painter.drawText( rect, Qt::AlignCenter, tr(stmp) );
|
|
//painter.drawText( rect, Qt::AlignHCenter | Qt::AlignBottom, tr(stmp) );
|
|
|
|
if ( font.italic() )
|
|
{
|
|
font.setBold(true);
|
|
font.setItalic(false);
|
|
painter.setFont(font);
|
|
}
|
|
|
|
x = -pxLineXScroll;
|
|
|
|
int iImage = bookmarks->findBookmarkAtFrame(lineNum);
|
|
if (iImage < 0)
|
|
{
|
|
// no bookmark at this frame
|
|
if (lineNum == playback->getLastPosition())
|
|
{
|
|
if (lineNum == currFrameCounter)
|
|
{
|
|
iImage = GREEN_BLUE_ARROW_IMAGE_ID;
|
|
}
|
|
else
|
|
{
|
|
iImage = GREEN_ARROW_IMAGE_ID;
|
|
}
|
|
}
|
|
else if (lineNum == currFrameCounter)
|
|
{
|
|
iImage = BLUE_ARROW_IMAGE_ID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bookmark at this frame
|
|
if (lineNum == playback->getLastPosition())
|
|
{
|
|
iImage |= BOOKMARKS_WITH_GREEN_ARROW;
|
|
}
|
|
else if (lineNum == currFrameCounter)
|
|
{
|
|
iImage |= BOOKMARKS_WITH_BLUE_ARROW;
|
|
}
|
|
else
|
|
{
|
|
iImage |= BOOKMARKS_WITH_NO_ARROW;
|
|
}
|
|
}
|
|
|
|
if ( iImage >= 0 )
|
|
{
|
|
drawArrow( &painter, x, y, iImage );
|
|
}
|
|
|
|
y += pxLineSpacing;
|
|
}
|
|
|
|
int gridBlack = gridColor.black();
|
|
hdrGridColor = gridColor;
|
|
|
|
if ( gridBlack < 128 )
|
|
{
|
|
hdrGridColor = QColor(128,128,128);
|
|
}
|
|
|
|
// Draw Grid lines
|
|
painter.setPen( QPen(gridColor,gridPixelWidth) );
|
|
x = pxFrameColX - pxLineXScroll;
|
|
painter.drawLine( x, 0, x, viewHeight );
|
|
|
|
painter.setPen( QPen(hdrGridColor,gridPixelWidth) );
|
|
painter.drawLine( x, 0, x, pxLineSpacing );
|
|
|
|
font.setBold(true);
|
|
font.setItalic(false);
|
|
painter.setFont(font);
|
|
|
|
|
|
for (int i=0; i<numCtlr; i++)
|
|
{
|
|
x = pxFrameCtlX[i] - pxLineXScroll;
|
|
|
|
for (int j=0; j<8; j++)
|
|
{
|
|
//painter.setPen( QColor( 128, 128, 128 ) );
|
|
//painter.drawLine( x, 0, x, viewHeight ); x++;
|
|
painter.setPen( QPen(gridColor,gridPixelWidth) );
|
|
painter.drawLine( x, 0, x, viewHeight ); //x--;
|
|
|
|
painter.setPen( QPen(hdrGridColor,gridPixelWidth) );
|
|
painter.drawLine( x, 0, x, pxLineSpacing );
|
|
|
|
rect = QRect( x, 0, pxWidthBtnCol, pxLineSpacing );
|
|
painter.setPen( QPen(headerLightsColors[ headerColors[COLUMN_JOYPAD1_A + (i*8) + j] ],1) );
|
|
painter.drawText( x + pxCharWidth, pxLineTextOfs, tr(buttonNames[j]) );
|
|
//painter.drawText( rect, Qt::AlignCenter, tr(buttonNames[j]) );
|
|
//painter.drawText( rect, Qt::AlignHCenter | Qt::AlignBottom, tr(buttonNames[j]) );
|
|
|
|
x += pxWidthBtnCol;
|
|
}
|
|
//painter.setPen( QColor( 128, 128, 128 ) );
|
|
//painter.drawLine( x, 0, x, viewHeight ); x++;
|
|
painter.setPen( QPen(gridColor,gridPixelWidth) );
|
|
painter.drawLine( x, 0, x, viewHeight );
|
|
|
|
painter.setPen( QPen(hdrGridColor,gridPixelWidth) );
|
|
painter.drawLine( x, 0, x, pxLineSpacing );
|
|
|
|
}
|
|
painter.setPen( QPen(gridColor,gridPixelWidth) );
|
|
|
|
y = 0;
|
|
for (int i=0; i<nrow; i++)
|
|
{
|
|
painter.drawLine( 0, y, viewWidth, y );
|
|
|
|
y += pxLineSpacing;
|
|
}
|
|
|
|
painter.setPen( QPen(hdrGridColor,gridPixelWidth) );
|
|
painter.drawLine( 0, 0, viewWidth, 0 );
|
|
painter.drawLine( 0, pxLineSpacing, viewWidth, pxLineSpacing );
|
|
|
|
// Draw grid lines for selections
|
|
if ( numSelRows > 0 )
|
|
{
|
|
int inv;
|
|
QColor invGrid;
|
|
|
|
inv = gridColor.black();
|
|
|
|
if ( inv < 128 )
|
|
{
|
|
inv = 255 - inv;
|
|
}
|
|
|
|
invGrid.setRed( inv );
|
|
invGrid.setGreen( inv );
|
|
invGrid.setBlue( inv );
|
|
|
|
painter.setPen( QPen(invGrid,gridPixelWidth) );
|
|
|
|
y = pxLineSpacing;
|
|
|
|
for (row=0; row<nrow; row++)
|
|
{
|
|
if ( rowSelArray[row] )
|
|
{
|
|
int yl = y + pxLineSpacing;
|
|
|
|
x = pxFrameColX - pxLineXScroll;
|
|
painter.drawLine( x, y, x, yl );
|
|
|
|
for (int i=0; i<numCtlr; i++)
|
|
{
|
|
x = pxFrameCtlX[i] - pxLineXScroll;
|
|
|
|
for (int j=0; j<8; j++)
|
|
{
|
|
painter.drawLine( x, y, x, yl );
|
|
|
|
x += pxWidthBtnCol;
|
|
}
|
|
}
|
|
painter.drawLine( x, y, x, yl );
|
|
painter.drawLine( 0, y , viewWidth, y );
|
|
painter.drawLine( 0, yl, viewWidth, yl );
|
|
}
|
|
y += pxLineSpacing;
|
|
}
|
|
painter.setPen( QPen(gridColor,gridPixelWidth) );
|
|
}
|
|
|
|
font.setBold(false);
|
|
painter.setFont(font);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
//---- Bookmark Preview Popup
|
|
//----------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
bookmarkPreviewPopup *bookmarkPreviewPopup::instance = 0;
|
|
//----------------------------------------------------------------------------
|
|
bookmarkPreviewPopup::bookmarkPreviewPopup( int index, QWidget *parent )
|
|
: QDialog( parent, Qt::ToolTip )
|
|
{
|
|
int p;
|
|
QPoint pos;
|
|
QVBoxLayout *vbox;
|
|
uint32_t *pixBuf;
|
|
uint32_t pixel;
|
|
QPixmap pixmap;
|
|
|
|
if ( instance )
|
|
{
|
|
//instance->done(0);
|
|
//instance->deleteLater();
|
|
instance->actv = false;
|
|
instance = 0;
|
|
}
|
|
instance = this;
|
|
|
|
imageIndex = index;
|
|
|
|
//qApp->installEventFilter(this);
|
|
|
|
//FCEU_WRAPPER_LOCK();
|
|
|
|
// retrieve info from the pointed bookmark's Markers
|
|
int frame = bookmarks->bookmarksArray[index].snapshot.keyFrame;
|
|
int markerID = markersManager->getMarkerAboveFrame(bookmarks->bookmarksArray[index].snapshot.markers, frame);
|
|
|
|
screenShotRaster = (unsigned char *)malloc( SCREENSHOT_SIZE );
|
|
|
|
if ( screenShotRaster == NULL )
|
|
{
|
|
printf("Error: Failed to allocate screenshot image memory\n");
|
|
}
|
|
// bookmarks.itemUnderMouse
|
|
|
|
pixBuf = (uint32_t *)malloc( SCREENSHOT_SIZE * sizeof(uint32_t) );
|
|
|
|
loadImage(index);
|
|
|
|
p=0;
|
|
for (int h=0; h<SCREENSHOT_HEIGHT; h++)
|
|
{
|
|
for (int w=0; w<SCREENSHOT_WIDTH; w++)
|
|
{
|
|
pixel = ModernDeemphColorMap( &screenShotRaster[p], screenShotRaster, 1 );
|
|
pixBuf[p] = 0xFF000000;
|
|
pixBuf[p] |= (pixel & 0x000000FF) << 16;
|
|
pixBuf[p] |= (pixel & 0x00FF0000) >> 16;
|
|
pixBuf[p] |= (pixel & 0x0000FF00);
|
|
p++;
|
|
}
|
|
}
|
|
QImage img( (unsigned char*)pixBuf, SCREENSHOT_WIDTH, SCREENSHOT_HEIGHT, SCREENSHOT_WIDTH*4, QImage::Format_RGBA8888 );
|
|
pixmap.convertFromImage( img );
|
|
|
|
vbox = new QVBoxLayout();
|
|
|
|
setLayout( vbox );
|
|
|
|
imgLbl = new QLabel();
|
|
descLbl = new QLabel();
|
|
|
|
imgLbl->setPixmap( pixmap );
|
|
|
|
vbox->addWidget( imgLbl , 100 );
|
|
vbox->addWidget( descLbl, 1 );
|
|
|
|
descLbl->setText( tr(markersManager->getNoteCopy(bookmarks->bookmarksArray[index].snapshot.markers, markerID).c_str()) );
|
|
|
|
resize( 256, 256 );
|
|
|
|
if ( pixBuf )
|
|
{
|
|
free( pixBuf ); pixBuf = NULL;
|
|
}
|
|
|
|
pos = tasWin->getPreviewPopupCoordinates();
|
|
|
|
pos.setX( pos.x() - 300 );
|
|
|
|
move(pos);
|
|
|
|
//FCEU_WRAPPER_UNLOCK();
|
|
|
|
alpha = 0;
|
|
actv = true;
|
|
|
|
setWindowOpacity(0.0f);
|
|
|
|
timer = new QTimer(this);
|
|
|
|
connect( timer, &QTimer::timeout, this, &bookmarkPreviewPopup::periodicUpdate );
|
|
|
|
timer->start(33);
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bookmarkPreviewPopup::~bookmarkPreviewPopup( void )
|
|
{
|
|
timer->stop();
|
|
|
|
if ( screenShotRaster != NULL )
|
|
{
|
|
free( screenShotRaster ); screenShotRaster = NULL;
|
|
}
|
|
//printf("Popup Deleted\n");
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void bookmarkPreviewPopup::periodicUpdate(void)
|
|
{
|
|
if ( actv )
|
|
{
|
|
if ( alpha < 255 )
|
|
{
|
|
alpha += 25;
|
|
|
|
if ( alpha > 255 )
|
|
{
|
|
alpha = 255;
|
|
}
|
|
setWindowOpacity( alpha / 255.0f );
|
|
|
|
update();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( alpha > 0 )
|
|
{
|
|
alpha -= 25;
|
|
|
|
if ( alpha < 0 )
|
|
{
|
|
alpha = 0;
|
|
}
|
|
setWindowOpacity( alpha / 255.0f );
|
|
|
|
update();
|
|
}
|
|
else
|
|
{
|
|
if ( instance == this )
|
|
{
|
|
instance = NULL;
|
|
}
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bookmarkPreviewPopup *bookmarkPreviewPopup::currentInstance(void)
|
|
{
|
|
return instance;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int bookmarkPreviewPopup::currentIndex(void)
|
|
{
|
|
if ( instance )
|
|
{
|
|
return instance->imageIndex;
|
|
}
|
|
return -1;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void bookmarkPreviewPopup::imageIndexChanged(int newIndex)
|
|
{
|
|
FCEU_CRITICAL_SECTION(emuLock);
|
|
//printf("newIndex:%i\n", newIndex );
|
|
|
|
if ( newIndex >= 0 )
|
|
{
|
|
reloadImage(newIndex);
|
|
actv = true;
|
|
}
|
|
else
|
|
{
|
|
actv = false;
|
|
}
|
|
|
|
//if ( instance == this )
|
|
//{
|
|
// instance = NULL;
|
|
//}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int bookmarkPreviewPopup::loadImage(int index)
|
|
{
|
|
// uncompress
|
|
int ret = 0;
|
|
uLongf destlen = SCREENSHOT_SIZE;
|
|
int e = uncompress(screenShotRaster, &destlen, &bookmarks->bookmarksArray[index].savedScreenshot[0], bookmarks->bookmarksArray[index].savedScreenshot.size());
|
|
if (e != Z_OK && e != Z_BUF_ERROR)
|
|
{
|
|
// error decompressing
|
|
FCEU_printf("Error decompressing screenshot %d\n", index);
|
|
// at least fill bitmap with zeros
|
|
memset(screenShotRaster, 0, SCREENSHOT_SIZE);
|
|
ret = -1;
|
|
}
|
|
return ret;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int bookmarkPreviewPopup::reloadImage(int index)
|
|
{
|
|
int p, ret = 0;
|
|
uint32_t *pixBuf;
|
|
uint32_t pixel;
|
|
QPixmap pixmap;
|
|
|
|
if ( index == imageIndex )
|
|
{ // no change
|
|
return 0;
|
|
}
|
|
actv = true;
|
|
imageIndex = index;
|
|
|
|
// retrieve info from the pointed bookmark's Markers
|
|
int frame = bookmarks->bookmarksArray[index].snapshot.keyFrame;
|
|
int markerID = markersManager->getMarkerAboveFrame(bookmarks->bookmarksArray[index].snapshot.markers, frame);
|
|
|
|
pixBuf = (uint32_t *)malloc( SCREENSHOT_SIZE * sizeof(uint32_t) );
|
|
|
|
loadImage(index);
|
|
|
|
p=0;
|
|
for (int h=0; h<SCREENSHOT_HEIGHT; h++)
|
|
{
|
|
for (int w=0; w<SCREENSHOT_WIDTH; w++)
|
|
{
|
|
pixel = ModernDeemphColorMap( &screenShotRaster[p], screenShotRaster, 1 );
|
|
pixBuf[p] = 0xFF000000;
|
|
pixBuf[p] |= (pixel & 0x000000FF) << 16;
|
|
pixBuf[p] |= (pixel & 0x00FF0000) >> 16;
|
|
pixBuf[p] |= (pixel & 0x0000FF00);
|
|
p++;
|
|
}
|
|
}
|
|
QImage img( (unsigned char*)pixBuf, SCREENSHOT_WIDTH, SCREENSHOT_HEIGHT, SCREENSHOT_WIDTH*4, QImage::Format_RGBA8888 );
|
|
pixmap.convertFromImage( img );
|
|
|
|
if ( pixBuf )
|
|
{
|
|
free( pixBuf ); pixBuf = NULL;
|
|
}
|
|
|
|
imgLbl->setPixmap( pixmap );
|
|
|
|
descLbl->setText( tr(markersManager->getNoteCopy(bookmarks->bookmarksArray[index].snapshot.markers, markerID).c_str()) );
|
|
|
|
update();
|
|
|
|
return ret;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//---- TAS Find Note Window
|
|
//----------------------------------------------------------------------------
|
|
TasFindNoteWindow::TasFindNoteWindow( QWidget *parent )
|
|
: QDialog( parent, Qt::Window )
|
|
{
|
|
QSettings settings;
|
|
QVBoxLayout *mainLayout, *vbox;
|
|
QHBoxLayout *hbox, *hbox1;
|
|
QGroupBox *gbox;
|
|
|
|
setWindowTitle( tr("Find Note") );
|
|
|
|
mainLayout = new QVBoxLayout();
|
|
hbox1 = new QHBoxLayout();
|
|
hbox = new QHBoxLayout();
|
|
vbox = new QVBoxLayout();
|
|
|
|
setLayout( mainLayout );
|
|
|
|
searchPattern = new QLineEdit();
|
|
matchCase = new QCheckBox( tr("Match Case") );
|
|
up = new QRadioButton( tr("Up") );
|
|
down = new QRadioButton( tr("Down") );
|
|
nextBtn = new QPushButton( tr("Next") );
|
|
closeBtn = new QPushButton( tr("Close") );
|
|
gbox = new QGroupBox( tr("Direction") );
|
|
|
|
mainLayout->addWidget( searchPattern );
|
|
mainLayout->addLayout( hbox1 );
|
|
|
|
hbox1->addWidget( matchCase );
|
|
hbox1->addWidget( gbox );
|
|
hbox1->addLayout( vbox );
|
|
|
|
gbox->setLayout( hbox );
|
|
|
|
hbox->addWidget( up );
|
|
hbox->addWidget( down );
|
|
|
|
vbox->addWidget( nextBtn );
|
|
vbox->addWidget( closeBtn );
|
|
|
|
findWin = this;
|
|
|
|
nextBtn->setDefault(true);
|
|
|
|
matchCase->setChecked( taseditorConfig->findnoteMatchCase );
|
|
up->setChecked( taseditorConfig->findnoteSearchUp );
|
|
down->setChecked( !taseditorConfig->findnoteSearchUp );
|
|
|
|
searchPattern->setText( QString(markersManager->findNoteString) );
|
|
|
|
nextBtn->setEnabled( searchPattern->text().size() > 0 );
|
|
|
|
connect( matchCase, SIGNAL(clicked(bool)), this, SLOT(matchCaseChanged(bool)) );
|
|
connect( up , SIGNAL(clicked(void)), this, SLOT(upDirectionSelected(void)) );
|
|
connect( down , SIGNAL(clicked(void)), this, SLOT(downDirectionSelected(void)) );
|
|
connect( closeBtn , SIGNAL(clicked(void)), this, SLOT(closeWindow(void)) );
|
|
connect( nextBtn , SIGNAL(clicked(void)), this, SLOT(findNextClicked(void)) );
|
|
|
|
connect( searchPattern, SIGNAL(textChanged(const QString &)), this, SLOT(searchPatternChanged(const QString &)) );
|
|
|
|
// Restore Window Geometry
|
|
restoreGeometry(settings.value("tasEditorFindDialog/geometry").toByteArray());
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
TasFindNoteWindow::~TasFindNoteWindow(void)
|
|
{
|
|
QSettings settings;
|
|
|
|
if ( findWin == this )
|
|
{
|
|
findWin = NULL;
|
|
}
|
|
|
|
// Save Window Geometry
|
|
settings.setValue("tasEditorFindDialog/geometry", saveGeometry());
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
done(0);
|
|
deleteLater();
|
|
event->accept();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::closeWindow(void)
|
|
{
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::matchCaseChanged(bool val)
|
|
{
|
|
taseditorConfig->findnoteMatchCase = val;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::upDirectionSelected(void)
|
|
{
|
|
taseditorConfig->findnoteSearchUp = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::downDirectionSelected(void)
|
|
{
|
|
taseditorConfig->findnoteSearchUp = false;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::searchPatternChanged(const QString &s)
|
|
{
|
|
nextBtn->setEnabled( s.size() > 0 );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasFindNoteWindow::findNextClicked(void)
|
|
{
|
|
|
|
if ( searchPattern->text().size() == 0 )
|
|
{
|
|
return;
|
|
}
|
|
strncpy( markersManager->findNoteString, searchPattern->text().toLocal8Bit().constData(), MAX_NOTE_LEN-1 );
|
|
markersManager->findNoteString[MAX_NOTE_LEN-1] = 0;
|
|
|
|
// scan frames from current Selection to the border
|
|
int cur_marker = 0;
|
|
bool result;
|
|
int movie_size = currMovieData.getNumRecords();
|
|
int current_frame = selection->getCurrentRowsSelectionBeginning();
|
|
if ( (current_frame < 0) && taseditorConfig->findnoteSearchUp)
|
|
{
|
|
current_frame = movie_size;
|
|
}
|
|
while (true)
|
|
{
|
|
// move forward
|
|
if (taseditorConfig->findnoteSearchUp)
|
|
{
|
|
current_frame--;
|
|
if (current_frame < 0)
|
|
{
|
|
QMessageBox::information( this, tr("Find Note"), tr("Nothing was found!") );
|
|
printf("Nothing was found\n");
|
|
//MessageBox(taseditorWindow.hwndFindNote, "Nothing was found.", "Find Note", MB_OK);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
current_frame++;
|
|
if (current_frame >= movie_size)
|
|
{
|
|
QMessageBox::information( this, tr("Find Note"), tr("Nothing was found!") );
|
|
printf("Nothing was found\n");
|
|
//MessageBox(taseditorWindow.hwndFindNote, "Nothing was found!", "Find Note", MB_OK);
|
|
break;
|
|
}
|
|
}
|
|
// scan marked frames
|
|
cur_marker = markersManager->getMarkerAtFrame(current_frame);
|
|
if (cur_marker)
|
|
{
|
|
QString haystack, needle;
|
|
|
|
needle = QString(markersManager->findNoteString);
|
|
haystack = QString::fromStdString(markersManager->getNoteCopy(cur_marker));
|
|
|
|
if (taseditorConfig->findnoteMatchCase)
|
|
{
|
|
result = haystack.indexOf( needle, 0, Qt::CaseSensitive ) >= 0;
|
|
//result = (strstr(markersManager->getNoteCopy(cur_marker).c_str(), markersManager->findNoteString) != 0);
|
|
}
|
|
else
|
|
{
|
|
result = haystack.indexOf( needle, 0, Qt::CaseInsensitive ) >= 0;
|
|
//#ifdef WIN32
|
|
// result = (StrStrI(markersManager->getNoteCopy(cur_marker).c_str(), markersManager->findNoteString) != 0);
|
|
//#else
|
|
// result = (strcasestr(markersManager->getNoteCopy(cur_marker).c_str(), markersManager->findNoteString) != 0);
|
|
//#endif
|
|
}
|
|
if (result)
|
|
{
|
|
// found note containing searched string - jump there
|
|
selection->jumpToFrame(current_frame);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//---- TAS Recent Project Menu Action
|
|
//----------------------------------------------------------------------------
|
|
TasRecentProjectAction::TasRecentProjectAction(QString desc, QWidget *parent)
|
|
: QAction( desc, parent )
|
|
{
|
|
QString txt;
|
|
QFileInfo fi(desc);
|
|
|
|
path = desc.toLocal8Bit().constData();
|
|
|
|
txt = fi.fileName();
|
|
txt += QString("\t");
|
|
txt += desc;
|
|
|
|
setText( txt );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
TasRecentProjectAction::~TasRecentProjectAction(void)
|
|
{
|
|
//printf("Recent TAS Project Menu Action Deleted\n");
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasRecentProjectAction::activateCB(void)
|
|
{
|
|
//printf("Activate Recent TAS Project: %s \n", path.c_str() );
|
|
|
|
if ( tasWin )
|
|
{
|
|
tasWin->loadProject( path.c_str() );
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//---- Marker Drag
|
|
//----------------------------------------------------------------------------
|
|
markerDragPopup::markerDragPopup(QWidget *parent)
|
|
: QDialog( parent, Qt::ToolTip )
|
|
{
|
|
rowIndex = 0;
|
|
alpha = 255;
|
|
bgColor = QColor( 255,255,255 );
|
|
liveCount = 30;
|
|
|
|
qApp->installEventFilter(this);
|
|
|
|
timer = new QTimer(this);
|
|
|
|
connect( timer, &QTimer::timeout, this, &markerDragPopup::fadeAway );
|
|
|
|
timer->start(33);
|
|
|
|
released = false;
|
|
thrownAway = false;
|
|
dropAborted = false;
|
|
dropAccepted = false;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
markerDragPopup::~markerDragPopup(void)
|
|
{
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::setRowIndex( int row )
|
|
{
|
|
rowIndex = row;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::setBgColor( QColor c )
|
|
{
|
|
bgColor = c;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::setInitialPosition( QPoint p )
|
|
{
|
|
initialPos = p;
|
|
|
|
move( initialPos );
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::throwAway(void)
|
|
{
|
|
thrownAway = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::dropAccept(void)
|
|
{
|
|
dropAccepted = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::dropAbort(void)
|
|
{
|
|
dropAborted = true;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::fadeAway(void)
|
|
{
|
|
|
|
if ( released )
|
|
{
|
|
if ( thrownAway )
|
|
{
|
|
QPoint p = pos();
|
|
//printf("Fade:%i\n", alpha);
|
|
|
|
p.setY( p.y() + 2 );
|
|
|
|
move(p);
|
|
|
|
if ( alpha > 0 )
|
|
{
|
|
alpha -= 10;
|
|
|
|
if ( alpha < 0 )
|
|
{
|
|
alpha = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
setWindowOpacity( alpha / 255.0f );
|
|
|
|
update();
|
|
}
|
|
else if ( dropAborted )
|
|
{
|
|
QPoint p = pos();
|
|
int vx, vy, vm = 10;
|
|
|
|
vx = initialPos.x() - p.x();
|
|
|
|
if ( vx < -vm )
|
|
{
|
|
vx = -vm;
|
|
}
|
|
else if ( vx > vm )
|
|
{
|
|
vx = vm;
|
|
}
|
|
|
|
vy = initialPos.y() - p.y();
|
|
|
|
if ( vy < -vm )
|
|
{
|
|
vy = -vm;
|
|
}
|
|
else if ( vy > vm )
|
|
{
|
|
vy = vm;
|
|
}
|
|
|
|
p.setX( p.x() + vx );
|
|
p.setY( p.y() + vy );
|
|
|
|
if ( (vx == 0) && (vy == 0) )
|
|
{
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
else
|
|
{
|
|
move(p);
|
|
}
|
|
}
|
|
else if ( dropAccepted )
|
|
{
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
else
|
|
{
|
|
if ( liveCount > 0 )
|
|
{
|
|
liveCount--;
|
|
}
|
|
if ( liveCount == 0 )
|
|
{
|
|
done(0);
|
|
deleteLater();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void markerDragPopup::paintEvent(QPaintEvent *event)
|
|
{
|
|
int w,h;
|
|
QPainter painter(this);
|
|
char txt[32];
|
|
|
|
w = event->rect().width();
|
|
h = event->rect().height();
|
|
|
|
snprintf( txt, sizeof(txt), "%07i", rowIndex );
|
|
|
|
//painter.setFont(font);
|
|
//I want to make the title bar pasted on the content
|
|
//But you can't get the image of the default title bar, just draw a rectangular box
|
|
//If the external theme color is set, you need to change it
|
|
QRect title_rect{0,0,w,h};
|
|
painter.fillRect(title_rect,bgColor);
|
|
painter.drawText(title_rect,Qt::AlignCenter, txt);
|
|
//painter.drawText(title_rect,Qt::AlignHCenter | Qt::AlignBottom, txt);
|
|
//painter.drawRect(pixmap.rect().adjusted(0,0,-1,-1));
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
bool markerDragPopup::eventFilter( QObject *obj, QEvent *event)
|
|
{
|
|
//printf("Event:%i %p\n", event->type(), obj);
|
|
switch (event->type() )
|
|
{
|
|
case QEvent::MouseMove:
|
|
{
|
|
if ( !released )
|
|
{
|
|
move( QCursor::pos() );
|
|
}
|
|
break;
|
|
}
|
|
case QEvent::MouseButtonRelease:
|
|
{
|
|
released = true;
|
|
break;
|
|
}
|
|
default:
|
|
// Ignore
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
//---- TAS Window Main Horizontal Splitter
|
|
//----------------------------------------------------------------------------
|
|
TasEditorSplitter::TasEditorSplitter( QWidget *parent )
|
|
: QSplitter( Qt::Horizontal, parent )
|
|
{
|
|
panelInitDone = false;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
TasEditorSplitter::~TasEditorSplitter(void)
|
|
{
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void TasEditorSplitter::resizeEvent(QResizeEvent *event)
|
|
{
|
|
int minWidth;
|
|
//int widthDelta;
|
|
QList<int> panelWidth;
|
|
|
|
//printf("Panel Resize\n");
|
|
if ( !panelInitDone )
|
|
{
|
|
QSplitter::resizeEvent(event);
|
|
panelInitDone = true;
|
|
return;
|
|
}
|
|
//widthDelta = event->size().width() - event->oldSize().width();
|
|
|
|
panelWidth = sizes();
|
|
|
|
|
|
//for (int i=0; i<panelWidth.count(); i++)
|
|
//{
|
|
// printf("Panel %i: %i\n", i, panelWidth[i] );
|
|
//}
|
|
panelWidth[0] = event->size().width() - panelWidth[1] - handleWidth();
|
|
//panelWidth[0] += widthDelta;
|
|
|
|
minWidth = widget(0)->minimumWidth();
|
|
|
|
if ( panelWidth[0] < minWidth )
|
|
{
|
|
panelWidth[0] = minWidth;
|
|
}
|
|
setSizes( panelWidth );
|
|
}
|
|
//----------------------------------------------------------------------------
|