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 Jaguar to NTSC mode"));
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 Jaguar to PAL mode"));
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 helpMenu = menuBar()->addMenu(tr("&Help"));
125 helpMenu->addAction(aboutAct);
127 toolbar = addToolBar(tr("Stuff"));
128 toolbar->addAction(powerAct);
129 toolbar->addSeparator();
130 toolbar->addAction(x1Act);
131 toolbar->addAction(x2Act);
132 toolbar->addAction(x3Act);
133 toolbar->addSeparator();
134 toolbar->addAction(ntscAct);
135 toolbar->addAction(palAct);
136 toolbar->addSeparator();
137 toolbar->addAction(blurAct);
140 statusBar()->showMessage(tr("Ready"));
142 // Set toolbar buttons/menus based on settings read in (sync the UI)...
143 blurAct->setChecked(vjs.glFilter);
144 x1Act->setChecked(zoomLevel == 1);
145 x2Act->setChecked(zoomLevel == 2);
146 x3Act->setChecked(zoomLevel == 3);
147 running = powerAct->isChecked();
148 ntscAct->setChecked(vjs.hardwareTypeNTSC);
149 palAct->setChecked(!vjs.hardwareTypeNTSC);
151 // Do this in case original size isn't correct (mostly for the first-run case)
154 // Set up timer based loop for animation...
155 timer = new QTimer(this);
156 connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
160 void MainWin::closeEvent(QCloseEvent * event)
163 event->accept(); // ignore() if can't close for some reason
166 void MainWin::Open(void)
170 void MainWin::Timer(void)
175 // Random hash & trash
176 // We try to simulate an untuned tank circuit here... :-)
177 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
179 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
181 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF;
182 // buffer[(y * textureWidth) + x] = x*y;
186 videoWidget->updateGL();
189 void MainWin::ToggleRunState(void)
195 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
196 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
197 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = 0x00000000;
199 videoWidget->updateGL();
203 void MainWin::SetZoom100(void)
209 void MainWin::SetZoom200(void)
215 void MainWin::SetZoom300(void)
221 void MainWin::SetNTSC(void)
223 vjs.hardwareTypeNTSC = true;
227 void MainWin::SetPAL(void)
229 vjs.hardwareTypeNTSC = false;
233 void MainWin::ToggleBlur(void)
235 vjs.glFilter = !vjs.glFilter;
238 void MainWin::ShowAboutWin(void)
243 void MainWin::InsertCart(void)
248 void MainWin::ResizeMainWindow(void)
250 videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
253 for(int i=0; i<2; i++)
257 QApplication::processEvents();
261 void MainWin::ReadSettings(void)
263 QSettings settings("Underground Software", "Virtual Jaguar");
264 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
265 QSize size = settings.value("size", QSize(400, 400)).toSize();
269 zoomLevel = settings.value("zoom", 1).toInt();
271 vjs.useJoystick = settings.value("useJoystick", false).toBool();
272 vjs.joyport = settings.value("joyport", 0).toInt();
273 vjs.hardwareTypeNTSC = settings.value("hardwareTypeNTSC", true).toBool();
274 vjs.frameSkip = settings.value("frameSkip", 0).toInt();
275 vjs.useJaguarBIOS = settings.value("useJaguarBIOS", false).toBool();
276 vjs.DSPEnabled = settings.value("DSPEnabled", false).toBool();
277 vjs.usePipelinedDSP = settings.value("usePipelinedDSP", false).toBool();
278 vjs.fullscreen = settings.value("fullscreen", false).toBool();
279 vjs.useOpenGL = settings.value("useOpenGL", true).toBool();
280 vjs.glFilter = settings.value("glFilterType", 0).toInt();
281 vjs.renderType = settings.value("renderType", 0).toInt();
283 // Hardcoded, !!! FIX !!!
284 strcpy(vjs.ROMPath, "./roms");
287 void MainWin::WriteSettings(void)
289 QSettings settings("Underground Software", "Virtual Jaguar");
290 settings.setValue("pos", pos());
291 settings.setValue("size", size());
293 settings.setValue("zoom", zoomLevel);
295 settings.setValue("useJoystick", vjs.useJoystick);
296 settings.setValue("joyport", vjs.joyport);
297 settings.setValue("hardwareTypeNTSC", vjs.hardwareTypeNTSC);
298 settings.setValue("frameSkip", vjs.frameSkip);
299 settings.setValue("useJaguarBIOS", vjs.useJaguarBIOS);
300 settings.setValue("DSPEnabled", vjs.DSPEnabled);
301 settings.setValue("usePipelinedDSP", vjs.usePipelinedDSP);
302 settings.setValue("fullscreen", vjs.fullscreen);
303 settings.setValue("useOpenGL", vjs.useOpenGL);
304 settings.setValue("glFilterType", vjs.glFilter);
305 settings.setValue("renderType", vjs.renderType);
308 // Here's how Byuu does it...
309 // I think I have it working now... :-)
311 void Utility::resizeMainWindow()
313 unsigned region = config().video.context->region;
314 unsigned multiplier = config().video.context->multiplier;
315 unsigned width = 256 * multiplier;
316 unsigned height = (region == 0 ? 224 : 239) * multiplier;
318 if(config().video.context->correctAspectRatio)
322 width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust
326 width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust
330 if(config().video.isFullscreen == false)
332 //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
333 QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
335 //ensure window size will not be larger than viewable desktop area
336 constrainSize(height, width, deskRect.height()); //- frameHeight);
337 constrainSize(width, height, deskRect.width()); //- frameWidth );
339 mainWindow->canvas->setFixedSize(width, height);
344 for(unsigned i = 0; i < 2; i++)
346 unsigned iWidth = width, iHeight = height;
348 constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
349 constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
351 //center canvas onscreen; ensure it is not larger than viewable area
352 mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
353 mainWindow->canvas->setFixedSize(iWidth, iHeight);
354 mainWindow->canvas->setMinimumSize(0, 0);
357 QApplication::processEvents();
361 //workaround for Qt/Xlib bug:
362 //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor;
363 //so force it to show Qt::ArrowCursor, as expected
364 mainWindow->setCursor(Qt::ArrowCursor);
365 mainWindow->canvasContainer->setCursor(Qt::ArrowCursor);
366 mainWindow->canvas->setCursor(Qt::ArrowCursor);
368 //workaround for DirectSound(?) bug:
369 //window resizing sometimes breaks audio sync, this call re-initializes it
373 void Utility::setScale(unsigned scale)
375 config().video.context->multiplier = scale;
377 mainWindow->shrink();
378 mainWindow->syncUi();
381 void QbWindow::shrink()
383 if(config().video.isFullscreen == false)
385 for(unsigned i = 0; i < 2; i++)
389 QApplication::processEvents();