]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/mainwin.cpp
More GUI fill in, new About box
[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
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
36 // better way.
37
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
40 // QOpenGL?
41
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.
45
46 MainWin::MainWin()
47 {
48         videoWidget = new GLWidget(this);
49         setCentralWidget(videoWidget);
50         setWindowIcon(QIcon(":/res/vj.xpm"));
51         setWindowTitle("Virtual Jaguar v2.0.0");
52
53         aboutWin = new AboutWindow(this);
54
55     videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
56     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
57
58         // Create actions
59
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()));
64
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()));
69
70         zoomActs = new QActionGroup(this);
71
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()));
76
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()));
81
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()));
86
87         tvTypeActs = new QActionGroup(this);
88
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()));
93
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()));
98
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()));
103
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()));
108
109         // Create menus & toolbars
110
111         fileMenu = menuBar()->addMenu(tr("&File"));
112         fileMenu->addAction(powerAct);
113         fileMenu->addAction(quitAppAct);
114
115         fileMenu = menuBar()->addMenu(tr("&Help"));
116         fileMenu->addAction(aboutAct);
117
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);
126
127         //      Create status bar
128         statusBar()->showMessage(tr("Ready"));
129
130         ReadSettings();
131         setUnifiedTitleAndToolBarOnMac(true);
132
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);
141
142         // Do this in case original size isn't correct
143         ResizeMainWindow();
144
145         // Set up timer based loop for animation...
146         timer = new QTimer(this);
147         connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
148         timer->start(20);
149 }
150
151 void MainWin::closeEvent(QCloseEvent * event)
152 {
153         WriteSettings();
154         event->accept(); // ignore() if can't close for some reason
155 }
156
157 void MainWin::Open(void)
158 {
159 }
160
161 void MainWin::Timer(void)
162 {
163         if (!running)
164                 return;
165
166         // Random hash & trash
167         // We try to simulate an untuned tank circuit here... :-)
168         for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
169         {
170                 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
171                 {
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;
174                 }
175         }
176
177         videoWidget->updateGL();
178 }
179
180 void MainWin::ToggleRunState(void)
181 {
182         running = !running;
183
184         if (!running)
185         {
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;
189
190                 videoWidget->updateGL();
191         }
192 }
193
194 void MainWin::SetZoom100(void)
195 {
196         zoomLevel = 1;
197         ResizeMainWindow();
198 }
199
200 void MainWin::SetZoom200(void)
201 {
202         zoomLevel = 2;
203         ResizeMainWindow();
204 }
205
206 void MainWin::SetZoom300(void)
207 {
208         zoomLevel = 3;
209         ResizeMainWindow();
210 }
211
212 void MainWin::SetNTSC(void)
213 {
214         vjs.hardwareTypeNTSC = true;
215         ResizeMainWindow();
216 }
217
218 void MainWin::SetPAL(void)
219 {
220         vjs.hardwareTypeNTSC = false;
221         ResizeMainWindow();
222 }
223
224 void MainWin::ToggleBlur(void)
225 {
226         vjs.glFilter = !vjs.glFilter;
227 }
228
229 void MainWin::ShowAboutWin(void)
230 {
231         aboutWin->show();
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."));
236 }
237
238 void MainWin::ResizeMainWindow(void)
239 {
240         videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
241         show();
242
243         for(int i=0; i<2; i++)
244         {
245                 resize(0, 0);
246                 usleep(2000);
247                 QApplication::processEvents();
248         }
249 }
250
251 void MainWin::ReadSettings(void)
252 {
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();
256         resize(size);
257         move(pos);
258
259         zoomLevel = settings.value("zoom", 1).toInt();
260
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();
272 }
273
274 void MainWin::WriteSettings(void)
275 {
276         QSettings settings("Underground Software", "Virtual Jaguar");
277         settings.setValue("pos", pos());
278         settings.setValue("size", size());
279
280         settings.setValue("zoom", zoomLevel);
281
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);
293 }
294
295 // Here's how Byuu does it...
296 // I think I have it working now... :-)
297 #if 0
298 void Utility::resizeMainWindow()
299 {
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;
304
305   if(config().video.context->correctAspectRatio)
306   {
307     if(region == 0)
308         {
309       width = (double)width * config().video.ntscAspectRatio + 0.5;  //NTSC adjust
310     }
311         else
312         {
313       width = (double)width * config().video.palAspectRatio  + 0.5;  //PAL adjust
314     }
315   }
316
317   if(config().video.isFullscreen == false)
318   {
319     //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
320     QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
321
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 );
325
326     mainWindow->canvas->setFixedSize(width, height);
327     mainWindow->show();
328   }
329   else
330   {
331     for(unsigned i = 0; i < 2; i++)
332         {
333       unsigned iWidth = width, iHeight = height;
334
335       constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
336       constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
337
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);
342
343       usleep(2000);
344       QApplication::processEvents();
345     }
346   }
347
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);
354
355   //workaround for DirectSound(?) bug:
356   //window resizing sometimes breaks audio sync, this call re-initializes it
357   updateAvSync();
358 }
359
360 void Utility::setScale(unsigned scale)
361 {
362   config().video.context->multiplier = scale;
363   resizeMainWindow();
364   mainWindow->shrink();
365   mainWindow->syncUi();
366 }
367
368 void QbWindow::shrink()
369 {
370   if(config().video.isFullscreen == false)
371   {
372     for(unsigned i = 0; i < 2; i++)
373         {
374       resize(0, 0);
375       usleep(2000);
376       QApplication::processEvents();
377     }
378   }
379 }
380 #endif