2 // mainwin.cpp - Qt-based GUI for Virtual Jaguar: Main Application Window
4 // (C) 2009 Underground Software
6 // JLH = James L. Hammons <jlhamm@acm.org>
9 // --- ---------- -------------------------------------------------------------
10 // JLH 12/23/2009 Created this file
11 // JLH 12/20/2010 Added settings, menus & toolbars
21 // Uncomment this for debugging...
23 //#define DEBUGFOO // Various tool debugging...
24 //#define DEBUGTP // Toolpalette debugging...
33 #include "filepicker.h"
35 // The way BSNES controls things is by setting a timer with a zero
36 // timeout, sleeping if not emulating anything. Seems there has to be a
39 // It has a novel approach to plugging-in/using different video/audio/input
40 // methods, can we do something similar or should we just use the built-in
43 // We're going to try to use the built-in OpenGL support and see how it goes.
44 // We'll make the VJ core modular so that it doesn't matter what GUI is in
45 // use, we can drop it in anywhere and use it as-is.
49 videoWidget = new GLWidget(this);
50 setCentralWidget(videoWidget);
51 setWindowIcon(QIcon(":/res/vj.xpm"));
52 setWindowTitle("Virtual Jaguar v2.0.0");
55 setUnifiedTitleAndToolBarOnMac(true);
57 aboutWin = new AboutWindow(this);
58 filePickWin = new FilePickerWindow(this);
60 videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
61 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
65 quitAppAct = new QAction(tr("E&xit"), this);
66 quitAppAct->setShortcuts(QKeySequence::Quit);
67 quitAppAct->setStatusTip(tr("Quit Virtual Jaguar"));
68 connect(quitAppAct, SIGNAL(triggered()), this, SLOT(close()));
70 powerAct = new QAction(QIcon(":/res/power.png"), tr("&Power"), this);
71 powerAct->setStatusTip(tr("Toggle running state"));
72 powerAct->setCheckable(true);
73 connect(powerAct, SIGNAL(triggered()), this, SLOT(ToggleRunState()));
75 zoomActs = new QActionGroup(this);
77 x1Act = new QAction(QIcon(":/res/zoom100.png"), tr("Zoom 100%"), zoomActs);
78 x1Act->setStatusTip(tr("Set window zoom to 100%"));
79 x1Act->setCheckable(true);
80 connect(x1Act, SIGNAL(triggered()), this, SLOT(SetZoom100()));
82 x2Act = new QAction(QIcon(":/res/zoom200.png"), tr("Zoom 200%"), zoomActs);
83 x2Act->setStatusTip(tr("Set window zoom to 200%"));
84 x2Act->setCheckable(true);
85 connect(x2Act, SIGNAL(triggered()), this, SLOT(SetZoom200()));
87 x3Act = new QAction(QIcon(":/res/zoom300.png"), tr("Zoom 300%"), zoomActs);
88 x3Act->setStatusTip(tr("Set window zoom to 300%"));
89 x3Act->setCheckable(true);
90 connect(x3Act, SIGNAL(triggered()), this, SLOT(SetZoom300()));
92 tvTypeActs = new QActionGroup(this);
94 ntscAct = new QAction(QIcon(":/res/generic.png"), tr("NTSC"), tvTypeActs);
95 ntscAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
96 ntscAct->setCheckable(true);
97 connect(ntscAct, SIGNAL(triggered()), this, SLOT(SetNTSC()));
99 palAct = new QAction(QIcon(":/res/generic.png"), tr("PAL"), tvTypeActs);
100 palAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
101 palAct->setCheckable(true);
102 connect(palAct, SIGNAL(triggered()), this, SLOT(SetPAL()));
104 blurAct = new QAction(QIcon(":/res/generic.png"), tr("Blur"), this);
105 blurAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
106 blurAct->setCheckable(true);
107 connect(blurAct, SIGNAL(triggered()), this, SLOT(ToggleBlur()));
109 aboutAct = new QAction(QIcon(":/res/generic.png"), tr("&About..."), this);
110 aboutAct->setStatusTip(tr("Blatant self-promotion"));
111 connect(aboutAct, SIGNAL(triggered()), this, SLOT(ShowAboutWin()));
113 filePickAct = new QAction(QIcon(":/res/generic.png"), tr("Insert Cartridge..."), this);
114 filePickAct->setStatusTip(tr("Insert a cartridge into Virtual Jaguar"));
115 connect(filePickAct, SIGNAL(triggered()), this, SLOT(InsertCart()));
117 // Create menus & toolbars
119 fileMenu = menuBar()->addMenu(tr("&File"));
120 fileMenu->addAction(filePickAct);
121 fileMenu->addAction(powerAct);
122 fileMenu->addAction(quitAppAct);
124 fileMenu = menuBar()->addMenu(tr("&Help"));
125 fileMenu->addAction(aboutAct);
127 QToolBar * toolbar = addToolBar(tr("Stuff"));
128 toolbar->addAction(powerAct);
129 toolbar->addAction(x1Act);
130 toolbar->addAction(x2Act);
131 toolbar->addAction(x3Act);
132 toolbar->addAction(ntscAct);
133 toolbar->addAction(palAct);
134 toolbar->addAction(blurAct);
137 statusBar()->showMessage(tr("Ready"));
139 // Set toolbar button based on setting read in (sync the UI)...
140 blurAct->setChecked(vjs.glFilter);
141 x1Act->setChecked(zoomLevel == 1);
142 x2Act->setChecked(zoomLevel == 2);
143 x3Act->setChecked(zoomLevel == 3);
144 running = powerAct->isChecked();
145 ntscAct->setChecked(vjs.hardwareTypeNTSC);
146 palAct->setChecked(!vjs.hardwareTypeNTSC);
148 // Do this in case original size isn't correct (mostly for the first-run case)
151 // Set up timer based loop for animation...
152 timer = new QTimer(this);
153 connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
157 void MainWin::closeEvent(QCloseEvent * event)
160 event->accept(); // ignore() if can't close for some reason
163 void MainWin::Open(void)
167 void MainWin::Timer(void)
172 // Random hash & trash
173 // We try to simulate an untuned tank circuit here... :-)
174 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
176 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
178 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF;
179 // buffer[(y * textureWidth) + x] = x*y;
183 videoWidget->updateGL();
186 void MainWin::ToggleRunState(void)
192 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
193 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
194 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = 0x00000000;
196 videoWidget->updateGL();
200 void MainWin::SetZoom100(void)
206 void MainWin::SetZoom200(void)
212 void MainWin::SetZoom300(void)
218 void MainWin::SetNTSC(void)
220 vjs.hardwareTypeNTSC = true;
224 void MainWin::SetPAL(void)
226 vjs.hardwareTypeNTSC = false;
230 void MainWin::ToggleBlur(void)
232 vjs.glFilter = !vjs.glFilter;
235 void MainWin::ShowAboutWin(void)
240 void MainWin::InsertCart(void)
245 void MainWin::ResizeMainWindow(void)
247 videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
250 for(int i=0; i<2; i++)
254 QApplication::processEvents();
258 void MainWin::ReadSettings(void)
260 QSettings settings("Underground Software", "Virtual Jaguar");
261 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
262 QSize size = settings.value("size", QSize(400, 400)).toSize();
266 zoomLevel = settings.value("zoom", 1).toInt();
268 vjs.useJoystick = settings.value("useJoystick", false).toBool();
269 vjs.joyport = settings.value("joyport", 0).toInt();
270 vjs.hardwareTypeNTSC = settings.value("hardwareTypeNTSC", true).toBool();
271 vjs.frameSkip = settings.value("frameSkip", 0).toInt();
272 vjs.useJaguarBIOS = settings.value("useJaguarBIOS", false).toBool();
273 vjs.DSPEnabled = settings.value("DSPEnabled", false).toBool();
274 vjs.usePipelinedDSP = settings.value("usePipelinedDSP", false).toBool();
275 vjs.fullscreen = settings.value("fullscreen", false).toBool();
276 vjs.useOpenGL = settings.value("useOpenGL", true).toBool();
277 vjs.glFilter = settings.value("glFilterType", 0).toInt();
278 vjs.renderType = settings.value("renderType", 0).toInt();
280 // Hardcoded, !!! FIX !!!
281 strcpy(vjs.ROMPath, "./roms");
284 void MainWin::WriteSettings(void)
286 QSettings settings("Underground Software", "Virtual Jaguar");
287 settings.setValue("pos", pos());
288 settings.setValue("size", size());
290 settings.setValue("zoom", zoomLevel);
292 settings.setValue("useJoystick", vjs.useJoystick);
293 settings.setValue("joyport", vjs.joyport);
294 settings.setValue("hardwareTypeNTSC", vjs.hardwareTypeNTSC);
295 settings.setValue("frameSkip", vjs.frameSkip);
296 settings.setValue("useJaguarBIOS", vjs.useJaguarBIOS);
297 settings.setValue("DSPEnabled", vjs.DSPEnabled);
298 settings.setValue("usePipelinedDSP", vjs.usePipelinedDSP);
299 settings.setValue("fullscreen", vjs.fullscreen);
300 settings.setValue("useOpenGL", vjs.useOpenGL);
301 settings.setValue("glFilterType", vjs.glFilter);
302 settings.setValue("renderType", vjs.renderType);
305 // Here's how Byuu does it...
306 // I think I have it working now... :-)
308 void Utility::resizeMainWindow()
310 unsigned region = config().video.context->region;
311 unsigned multiplier = config().video.context->multiplier;
312 unsigned width = 256 * multiplier;
313 unsigned height = (region == 0 ? 224 : 239) * multiplier;
315 if(config().video.context->correctAspectRatio)
319 width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust
323 width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust
327 if(config().video.isFullscreen == false)
329 //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
330 QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
332 //ensure window size will not be larger than viewable desktop area
333 constrainSize(height, width, deskRect.height()); //- frameHeight);
334 constrainSize(width, height, deskRect.width()); //- frameWidth );
336 mainWindow->canvas->setFixedSize(width, height);
341 for(unsigned i = 0; i < 2; i++)
343 unsigned iWidth = width, iHeight = height;
345 constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
346 constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
348 //center canvas onscreen; ensure it is not larger than viewable area
349 mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
350 mainWindow->canvas->setFixedSize(iWidth, iHeight);
351 mainWindow->canvas->setMinimumSize(0, 0);
354 QApplication::processEvents();
358 //workaround for Qt/Xlib bug:
359 //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor;
360 //so force it to show Qt::ArrowCursor, as expected
361 mainWindow->setCursor(Qt::ArrowCursor);
362 mainWindow->canvasContainer->setCursor(Qt::ArrowCursor);
363 mainWindow->canvas->setCursor(Qt::ArrowCursor);
365 //workaround for DirectSound(?) bug:
366 //window resizing sometimes breaks audio sync, this call re-initializes it
370 void Utility::setScale(unsigned scale)
372 config().video.context->multiplier = scale;
374 mainWindow->shrink();
375 mainWindow->syncUi();
378 void QbWindow::shrink()
380 if(config().video.isFullscreen == false)
382 for(unsigned i = 0; i < 2; i++)
386 QApplication::processEvents();