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...
34 // The way BSNES controls things is by setting a timer with a zero
35 // timeout, sleeping if not emulating anything. Seems there has to be a
38 // It has a novel approach to plugging-in/using different video/audio/input
39 // methods, can we do something similar or should we just use the built-in
42 // We're going to try to use the built-in OpenGL support and see how it goes.
43 // We'll make the VJ core modular so that it doesn't matter what GUI is in
44 // use, we can drop it in anywhere and use it as-is.
48 videoWidget = new GLWidget(this);
49 setCentralWidget(videoWidget);
50 setWindowIcon(QIcon(":/res/vj.xpm"));
51 setWindowTitle("Virtual Jaguar v2.0.0");
53 aboutWin = new AboutWindow(this);
55 videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
56 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
60 quitAppAct = new QAction(tr("E&xit"), this);
61 quitAppAct->setShortcuts(QKeySequence::Quit);
62 quitAppAct->setStatusTip(tr("Quit Virtual Jaguar"));
63 connect(quitAppAct, SIGNAL(triggered()), this, SLOT(close()));
65 powerAct = new QAction(QIcon(":/res/power.png"), tr("&Power"), this);
66 powerAct->setStatusTip(tr("Toggle running state"));
67 powerAct->setCheckable(true);
68 connect(powerAct, SIGNAL(triggered()), this, SLOT(ToggleRunState()));
70 zoomActs = new QActionGroup(this);
72 x1Act = new QAction(QIcon(":/res/zoom100.png"), tr("Zoom 100%"), zoomActs);
73 x1Act->setStatusTip(tr("Set window zoom to 100%"));
74 x1Act->setCheckable(true);
75 connect(x1Act, SIGNAL(triggered()), this, SLOT(SetZoom100()));
77 x2Act = new QAction(QIcon(":/res/zoom200.png"), tr("Zoom 200%"), zoomActs);
78 x2Act->setStatusTip(tr("Set window zoom to 200%"));
79 x2Act->setCheckable(true);
80 connect(x2Act, SIGNAL(triggered()), this, SLOT(SetZoom200()));
82 x3Act = new QAction(QIcon(":/res/zoom300.png"), tr("Zoom 300%"), zoomActs);
83 x3Act->setStatusTip(tr("Set window zoom to 300%"));
84 x3Act->setCheckable(true);
85 connect(x3Act, SIGNAL(triggered()), this, SLOT(SetZoom300()));
87 tvTypeActs = new QActionGroup(this);
89 ntscAct = new QAction(QIcon(":/res/generic.png"), tr("NTSC"), tvTypeActs);
90 ntscAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
91 ntscAct->setCheckable(true);
92 connect(ntscAct, SIGNAL(triggered()), this, SLOT(SetNTSC()));
94 palAct = new QAction(QIcon(":/res/generic.png"), tr("PAL"), tvTypeActs);
95 palAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
96 palAct->setCheckable(true);
97 connect(palAct, SIGNAL(triggered()), this, SLOT(SetPAL()));
99 blurAct = new QAction(QIcon(":/res/generic.png"), tr("Blur"), this);
100 blurAct->setStatusTip(tr("Sets OpenGL rendering to GL_NEAREST"));
101 blurAct->setCheckable(true);
102 connect(blurAct, SIGNAL(triggered()), this, SLOT(ToggleBlur()));
104 aboutAct = new QAction(QIcon(":/res/generic.png"), tr("&About..."), this);
105 aboutAct->setStatusTip(tr("Shows self-serving credits"));
106 // aboutAct->setCheckable(true);
107 connect(aboutAct, SIGNAL(triggered()), this, SLOT(ShowAboutWin()));
109 // Create menus & toolbars
111 fileMenu = menuBar()->addMenu(tr("&File"));
112 fileMenu->addAction(powerAct);
113 fileMenu->addAction(quitAppAct);
115 fileMenu = menuBar()->addMenu(tr("&Help"));
116 fileMenu->addAction(aboutAct);
118 QToolBar * toolbar = addToolBar(tr("Stuff"));
119 toolbar->addAction(powerAct);
120 toolbar->addAction(x1Act);
121 toolbar->addAction(x2Act);
122 toolbar->addAction(x3Act);
123 toolbar->addAction(ntscAct);
124 toolbar->addAction(palAct);
125 toolbar->addAction(blurAct);
128 statusBar()->showMessage(tr("Ready"));
131 setUnifiedTitleAndToolBarOnMac(true);
133 // Set toolbar button based on setting read in (sync the UI)...
134 blurAct->setChecked(vjs.glFilter);
135 x1Act->setChecked(zoomLevel == 1);
136 x2Act->setChecked(zoomLevel == 2);
137 x3Act->setChecked(zoomLevel == 3);
138 running = powerAct->isChecked();
139 ntscAct->setChecked(vjs.hardwareTypeNTSC);
140 palAct->setChecked(!vjs.hardwareTypeNTSC);
142 // Do this in case original size isn't correct
145 // Set up timer based loop for animation...
146 timer = new QTimer(this);
147 connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
151 void MainWin::closeEvent(QCloseEvent * event)
154 event->accept(); // ignore() if can't close for some reason
157 void MainWin::Open(void)
161 void MainWin::Timer(void)
166 // Random hash & trash
167 // We try to simulate an untuned tank circuit here... :-)
168 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
170 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
172 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF;
173 // buffer[(y * textureWidth) + x] = x*y;
177 videoWidget->updateGL();
180 void MainWin::ToggleRunState(void)
186 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
187 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
188 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = 0x00000000;
190 videoWidget->updateGL();
194 void MainWin::SetZoom100(void)
200 void MainWin::SetZoom200(void)
206 void MainWin::SetZoom300(void)
212 void MainWin::SetNTSC(void)
214 vjs.hardwareTypeNTSC = true;
218 void MainWin::SetPAL(void)
220 vjs.hardwareTypeNTSC = false;
224 void MainWin::ToggleBlur(void)
226 vjs.glFilter = !vjs.glFilter;
229 void MainWin::ShowAboutWin(void)
232 // QMessageBox::about(this, tr("About Application"),
233 // tr("The <b>Application</b> example demonstrates how to "
234 // "write modern GUI applications using Qt, with a menu bar, "
235 // "toolbars, and a status bar."));
238 void MainWin::ResizeMainWindow(void)
240 videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
243 for(int i=0; i<2; i++)
247 QApplication::processEvents();
251 void MainWin::ReadSettings(void)
253 QSettings settings("Underground Software", "Virtual Jaguar");
254 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
255 QSize size = settings.value("size", QSize(400, 400)).toSize();
259 zoomLevel = settings.value("zoom", 1).toInt();
261 vjs.useJoystick = settings.value("useJoystick", false).toBool();
262 vjs.joyport = settings.value("joyport", 0).toInt();
263 vjs.hardwareTypeNTSC = settings.value("hardwareTypeNTSC", true).toBool();
264 vjs.frameSkip = settings.value("frameSkip", 0).toInt();
265 vjs.useJaguarBIOS = settings.value("useJaguarBIOS", false).toBool();
266 vjs.DSPEnabled = settings.value("DSPEnabled", false).toBool();
267 vjs.usePipelinedDSP = settings.value("usePipelinedDSP", false).toBool();
268 vjs.fullscreen = settings.value("fullscreen", false).toBool();
269 vjs.useOpenGL = settings.value("useOpenGL", true).toBool();
270 vjs.glFilter = settings.value("glFilterType", 0).toInt();
271 vjs.renderType = settings.value("renderType", 0).toInt();
274 void MainWin::WriteSettings(void)
276 QSettings settings("Underground Software", "Virtual Jaguar");
277 settings.setValue("pos", pos());
278 settings.setValue("size", size());
280 settings.setValue("zoom", zoomLevel);
282 settings.setValue("useJoystick", vjs.useJoystick);
283 settings.setValue("joyport", vjs.joyport);
284 settings.setValue("hardwareTypeNTSC", vjs.hardwareTypeNTSC);
285 settings.setValue("frameSkip", vjs.frameSkip);
286 settings.setValue("useJaguarBIOS", vjs.useJaguarBIOS);
287 settings.setValue("DSPEnabled", vjs.DSPEnabled);
288 settings.setValue("usePipelinedDSP", vjs.usePipelinedDSP);
289 settings.setValue("fullscreen", vjs.fullscreen);
290 settings.setValue("useOpenGL", vjs.useOpenGL);
291 settings.setValue("glFilterType", vjs.glFilter);
292 settings.setValue("renderType", vjs.renderType);
295 // Here's how Byuu does it...
296 // I think I have it working now... :-)
298 void Utility::resizeMainWindow()
300 unsigned region = config().video.context->region;
301 unsigned multiplier = config().video.context->multiplier;
302 unsigned width = 256 * multiplier;
303 unsigned height = (region == 0 ? 224 : 239) * multiplier;
305 if(config().video.context->correctAspectRatio)
309 width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust
313 width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust
317 if(config().video.isFullscreen == false)
319 //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
320 QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
322 //ensure window size will not be larger than viewable desktop area
323 constrainSize(height, width, deskRect.height()); //- frameHeight);
324 constrainSize(width, height, deskRect.width()); //- frameWidth );
326 mainWindow->canvas->setFixedSize(width, height);
331 for(unsigned i = 0; i < 2; i++)
333 unsigned iWidth = width, iHeight = height;
335 constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
336 constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
338 //center canvas onscreen; ensure it is not larger than viewable area
339 mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
340 mainWindow->canvas->setFixedSize(iWidth, iHeight);
341 mainWindow->canvas->setMinimumSize(0, 0);
344 QApplication::processEvents();
348 //workaround for Qt/Xlib bug:
349 //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor;
350 //so force it to show Qt::ArrowCursor, as expected
351 mainWindow->setCursor(Qt::ArrowCursor);
352 mainWindow->canvasContainer->setCursor(Qt::ArrowCursor);
353 mainWindow->canvas->setCursor(Qt::ArrowCursor);
355 //workaround for DirectSound(?) bug:
356 //window resizing sometimes breaks audio sync, this call re-initializes it
360 void Utility::setScale(unsigned scale)
362 config().video.context->multiplier = scale;
364 mainWindow->shrink();
365 mainWindow->syncUi();
368 void QbWindow::shrink()
370 if(config().video.isFullscreen == false)
372 for(unsigned i = 0; i < 2; i++)
376 QApplication::processEvents();