]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/mainwin.cpp
3d9276f3d77d309a28cacc285acb271b1a635bec
[virtualjaguar] / src / gui / mainwin.cpp
1 //
2 // mainwin.cpp - Qt-based GUI for Virtual Jaguar: Main Application Window
3 // by James L. Hammons
4 // (C) 2009 Underground Software
5 //
6 // JLH = James L. Hammons <jlhamm@acm.org>
7 //
8 // Who  When        What
9 // ---  ----------  -------------------------------------------------------------
10 // JLH  12/23/2009  Created this file
11 // JLH  12/20/2010  Added settings, menus & toolbars
12 //
13
14 // FIXED:
15 //
16 //
17 // STILL TO BE DONE:
18 //
19 //
20
21 // Uncomment this for debugging...
22 //#define DEBUG
23 //#define DEBUGFOO                      // Various tool debugging...
24 //#define DEBUGTP                               // Toolpalette debugging...
25
26 #include "mainwin.h"
27
28 //#include <QtGui>
29 //#include <QtOpenGL>
30 #include "glwidget.h"
31 #include "about.h"
32 #include "settings.h"
33 #include "filepicker.h"
34
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
37 // better way.
38
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
41 // QOpenGL?
42
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.
46
47 MainWin::MainWin()
48 {
49         videoWidget = new GLWidget(this);
50         setCentralWidget(videoWidget);
51         setWindowIcon(QIcon(":/res/vj.xpm"));
52         setWindowTitle("Virtual Jaguar v2.0.0");
53
54         ReadSettings();
55         setUnifiedTitleAndToolBarOnMac(true);
56
57         aboutWin = new AboutWindow(this);
58         filePickWin = new FilePickerWindow(this);
59
60     videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
61     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
62
63         // Create actions
64
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()));
69
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()));
74
75         zoomActs = new QActionGroup(this);
76
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()));
81
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()));
86
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()));
91
92         tvTypeActs = new QActionGroup(this);
93
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()));
98
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()));
103
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()));
108
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()));
112
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()));
116
117         // Create menus & toolbars
118
119         fileMenu = menuBar()->addMenu(tr("&File"));
120         fileMenu->addAction(filePickAct);
121         fileMenu->addAction(powerAct);
122         fileMenu->addAction(quitAppAct);
123
124         helpMenu = menuBar()->addMenu(tr("&Help"));
125         helpMenu->addAction(aboutAct);
126
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);
138
139         //      Create status bar
140         statusBar()->showMessage(tr("Ready"));
141
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);
150
151         // Do this in case original size isn't correct (mostly for the first-run case)
152         ResizeMainWindow();
153
154         // Set up timer based loop for animation...
155         timer = new QTimer(this);
156         connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
157         timer->start(20);
158 }
159
160 void MainWin::closeEvent(QCloseEvent * event)
161 {
162         WriteSettings();
163         event->accept(); // ignore() if can't close for some reason
164 }
165
166 void MainWin::Open(void)
167 {
168 }
169
170 void MainWin::Timer(void)
171 {
172         if (!running)
173                 return;
174
175         // Random hash & trash
176         // We try to simulate an untuned tank circuit here... :-)
177         for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
178         {
179                 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
180                 {
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;
183                 }
184         }
185
186         videoWidget->updateGL();
187 }
188
189 void MainWin::ToggleRunState(void)
190 {
191         running = !running;
192
193         if (!running)
194         {
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;
198
199                 videoWidget->updateGL();
200         }
201 }
202
203 void MainWin::SetZoom100(void)
204 {
205         zoomLevel = 1;
206         ResizeMainWindow();
207 }
208
209 void MainWin::SetZoom200(void)
210 {
211         zoomLevel = 2;
212         ResizeMainWindow();
213 }
214
215 void MainWin::SetZoom300(void)
216 {
217         zoomLevel = 3;
218         ResizeMainWindow();
219 }
220
221 void MainWin::SetNTSC(void)
222 {
223         vjs.hardwareTypeNTSC = true;
224         ResizeMainWindow();
225 }
226
227 void MainWin::SetPAL(void)
228 {
229         vjs.hardwareTypeNTSC = false;
230         ResizeMainWindow();
231 }
232
233 void MainWin::ToggleBlur(void)
234 {
235         vjs.glFilter = !vjs.glFilter;
236 }
237
238 void MainWin::ShowAboutWin(void)
239 {
240         aboutWin->show();
241 }
242
243 void MainWin::InsertCart(void)
244 {
245         filePickWin->show();
246 }
247
248 void MainWin::ResizeMainWindow(void)
249 {
250         videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
251         show();
252
253         for(int i=0; i<2; i++)
254         {
255                 resize(0, 0);
256                 usleep(2000);
257                 QApplication::processEvents();
258         }
259 }
260
261 void MainWin::ReadSettings(void)
262 {
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();
266         resize(size);
267         move(pos);
268
269         zoomLevel = settings.value("zoom", 1).toInt();
270
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();
282
283         // Hardcoded, !!! FIX !!!
284         strcpy(vjs.ROMPath, "./roms");
285 }
286
287 void MainWin::WriteSettings(void)
288 {
289         QSettings settings("Underground Software", "Virtual Jaguar");
290         settings.setValue("pos", pos());
291         settings.setValue("size", size());
292
293         settings.setValue("zoom", zoomLevel);
294
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);
306 }
307
308 // Here's how Byuu does it...
309 // I think I have it working now... :-)
310 #if 0
311 void Utility::resizeMainWindow()
312 {
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;
317
318   if(config().video.context->correctAspectRatio)
319   {
320     if(region == 0)
321         {
322       width = (double)width * config().video.ntscAspectRatio + 0.5;  //NTSC adjust
323     }
324         else
325         {
326       width = (double)width * config().video.palAspectRatio  + 0.5;  //PAL adjust
327     }
328   }
329
330   if(config().video.isFullscreen == false)
331   {
332     //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
333     QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
334
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 );
338
339     mainWindow->canvas->setFixedSize(width, height);
340     mainWindow->show();
341   }
342   else
343   {
344     for(unsigned i = 0; i < 2; i++)
345         {
346       unsigned iWidth = width, iHeight = height;
347
348       constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
349       constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
350
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);
355
356       usleep(2000);
357       QApplication::processEvents();
358     }
359   }
360
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);
367
368   //workaround for DirectSound(?) bug:
369   //window resizing sometimes breaks audio sync, this call re-initializes it
370   updateAvSync();
371 }
372
373 void Utility::setScale(unsigned scale)
374 {
375   config().video.context->multiplier = scale;
376   resizeMainWindow();
377   mainWindow->shrink();
378   mainWindow->syncUi();
379 }
380
381 void QbWindow::shrink()
382 {
383   if(config().video.isFullscreen == false)
384   {
385     for(unsigned i = 0; i < 2; i++)
386         {
387       resize(0, 0);
388       usleep(2000);
389       QApplication::processEvents();
390     }
391   }
392 }
393 #endif