]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/mainwin.cpp
Added beginnings of graphical file chooser
[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("Blatant self-promotion"));
106         connect(aboutAct, SIGNAL(triggered()), this, SLOT(ShowAboutWin()));
107
108         // Create menus & toolbars
109
110         fileMenu = menuBar()->addMenu(tr("&File"));
111         fileMenu->addAction(powerAct);
112         fileMenu->addAction(quitAppAct);
113
114         fileMenu = menuBar()->addMenu(tr("&Help"));
115         fileMenu->addAction(aboutAct);
116
117         QToolBar * toolbar = addToolBar(tr("Stuff"));
118         toolbar->addAction(powerAct);
119         toolbar->addAction(x1Act);
120         toolbar->addAction(x2Act);
121         toolbar->addAction(x3Act);
122         toolbar->addAction(ntscAct);
123         toolbar->addAction(palAct);
124         toolbar->addAction(blurAct);
125
126         //      Create status bar
127         statusBar()->showMessage(tr("Ready"));
128
129         ReadSettings();
130         setUnifiedTitleAndToolBarOnMac(true);
131
132         // Set toolbar button based on setting read in (sync the UI)...
133         blurAct->setChecked(vjs.glFilter);
134         x1Act->setChecked(zoomLevel == 1);
135         x2Act->setChecked(zoomLevel == 2);
136         x3Act->setChecked(zoomLevel == 3);
137         running = powerAct->isChecked();
138         ntscAct->setChecked(vjs.hardwareTypeNTSC);
139         palAct->setChecked(!vjs.hardwareTypeNTSC);
140
141         // Do this in case original size isn't correct (mostly for the first-run case)
142         ResizeMainWindow();
143
144         // Set up timer based loop for animation...
145         timer = new QTimer(this);
146         connect(timer, SIGNAL(timeout()), this, SLOT(Timer()));
147         timer->start(20);
148 }
149
150 void MainWin::closeEvent(QCloseEvent * event)
151 {
152         WriteSettings();
153         event->accept(); // ignore() if can't close for some reason
154 }
155
156 void MainWin::Open(void)
157 {
158 }
159
160 void MainWin::Timer(void)
161 {
162         if (!running)
163                 return;
164
165         // Random hash & trash
166         // We try to simulate an untuned tank circuit here... :-)
167         for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
168         {
169                 for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
170                 {
171                         videoWidget->buffer[(y * videoWidget->textureWidth) + x] = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;// | (rand() & 0xFF);//0x000000FF;
172 //                      buffer[(y * textureWidth) + x] = x*y;
173                 }
174         }
175
176         videoWidget->updateGL();
177 }
178
179 void MainWin::ToggleRunState(void)
180 {
181         running = !running;
182
183         if (!running)
184         {
185                 for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
186                         for(uint32_t y=0; y<videoWidget->rasterHeight; y++)
187                                 videoWidget->buffer[(y * videoWidget->textureWidth) + x] = 0x00000000;
188
189                 videoWidget->updateGL();
190         }
191 }
192
193 void MainWin::SetZoom100(void)
194 {
195         zoomLevel = 1;
196         ResizeMainWindow();
197 }
198
199 void MainWin::SetZoom200(void)
200 {
201         zoomLevel = 2;
202         ResizeMainWindow();
203 }
204
205 void MainWin::SetZoom300(void)
206 {
207         zoomLevel = 3;
208         ResizeMainWindow();
209 }
210
211 void MainWin::SetNTSC(void)
212 {
213         vjs.hardwareTypeNTSC = true;
214         ResizeMainWindow();
215 }
216
217 void MainWin::SetPAL(void)
218 {
219         vjs.hardwareTypeNTSC = false;
220         ResizeMainWindow();
221 }
222
223 void MainWin::ToggleBlur(void)
224 {
225         vjs.glFilter = !vjs.glFilter;
226 }
227
228 void MainWin::ShowAboutWin(void)
229 {
230         aboutWin->show();
231 }
232
233 void MainWin::ResizeMainWindow(void)
234 {
235         videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
236         show();
237
238         for(int i=0; i<2; i++)
239         {
240                 resize(0, 0);
241                 usleep(2000);
242                 QApplication::processEvents();
243         }
244 }
245
246 void MainWin::ReadSettings(void)
247 {
248         QSettings settings("Underground Software", "Virtual Jaguar");
249         QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
250         QSize size = settings.value("size", QSize(400, 400)).toSize();
251         resize(size);
252         move(pos);
253
254         zoomLevel = settings.value("zoom", 1).toInt();
255
256         vjs.useJoystick      = settings.value("useJoystick", false).toBool();
257         vjs.joyport          = settings.value("joyport", 0).toInt();
258         vjs.hardwareTypeNTSC = settings.value("hardwareTypeNTSC", true).toBool();
259         vjs.frameSkip        = settings.value("frameSkip", 0).toInt();
260         vjs.useJaguarBIOS    = settings.value("useJaguarBIOS", false).toBool();
261         vjs.DSPEnabled       = settings.value("DSPEnabled", false).toBool();
262         vjs.usePipelinedDSP  = settings.value("usePipelinedDSP", false).toBool();
263         vjs.fullscreen       = settings.value("fullscreen", false).toBool();
264         vjs.useOpenGL        = settings.value("useOpenGL", true).toBool();
265         vjs.glFilter         = settings.value("glFilterType", 0).toInt();
266         vjs.renderType       = settings.value("renderType", 0).toInt();
267 }
268
269 void MainWin::WriteSettings(void)
270 {
271         QSettings settings("Underground Software", "Virtual Jaguar");
272         settings.setValue("pos", pos());
273         settings.setValue("size", size());
274
275         settings.setValue("zoom", zoomLevel);
276
277         settings.setValue("useJoystick", vjs.useJoystick);
278         settings.setValue("joyport", vjs.joyport);
279         settings.setValue("hardwareTypeNTSC", vjs.hardwareTypeNTSC);
280         settings.setValue("frameSkip", vjs.frameSkip);
281         settings.setValue("useJaguarBIOS", vjs.useJaguarBIOS);
282         settings.setValue("DSPEnabled", vjs.DSPEnabled);
283         settings.setValue("usePipelinedDSP", vjs.usePipelinedDSP);
284         settings.setValue("fullscreen", vjs.fullscreen);
285         settings.setValue("useOpenGL", vjs.useOpenGL);
286         settings.setValue("glFilterType", vjs.glFilter);
287         settings.setValue("renderType", vjs.renderType);
288 }
289
290 // Here's how Byuu does it...
291 // I think I have it working now... :-)
292 #if 0
293 void Utility::resizeMainWindow()
294 {
295   unsigned region = config().video.context->region;
296   unsigned multiplier = config().video.context->multiplier;
297   unsigned width = 256 * multiplier;
298   unsigned height = (region == 0 ? 224 : 239) * multiplier;
299
300   if(config().video.context->correctAspectRatio)
301   {
302     if(region == 0)
303         {
304       width = (double)width * config().video.ntscAspectRatio + 0.5;  //NTSC adjust
305     }
306         else
307         {
308       width = (double)width * config().video.palAspectRatio  + 0.5;  //PAL adjust
309     }
310   }
311
312   if(config().video.isFullscreen == false)
313   {
314     //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
315     QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
316
317     //ensure window size will not be larger than viewable desktop area
318     constrainSize(height, width, deskRect.height()); //- frameHeight);
319     constrainSize(width, height, deskRect.width());  //- frameWidth );
320
321     mainWindow->canvas->setFixedSize(width, height);
322     mainWindow->show();
323   }
324   else
325   {
326     for(unsigned i = 0; i < 2; i++)
327         {
328       unsigned iWidth = width, iHeight = height;
329
330       constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height());
331       constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width());
332
333       //center canvas onscreen; ensure it is not larger than viewable area
334       mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
335       mainWindow->canvas->setFixedSize(iWidth, iHeight);
336       mainWindow->canvas->setMinimumSize(0, 0);
337
338       usleep(2000);
339       QApplication::processEvents();
340     }
341   }
342
343   //workaround for Qt/Xlib bug:
344   //if window resize occurs with cursor over it, Qt shows Qt::Size*DiagCursor;
345   //so force it to show Qt::ArrowCursor, as expected
346   mainWindow->setCursor(Qt::ArrowCursor);
347   mainWindow->canvasContainer->setCursor(Qt::ArrowCursor);
348   mainWindow->canvas->setCursor(Qt::ArrowCursor);
349
350   //workaround for DirectSound(?) bug:
351   //window resizing sometimes breaks audio sync, this call re-initializes it
352   updateAvSync();
353 }
354
355 void Utility::setScale(unsigned scale)
356 {
357   config().video.context->multiplier = scale;
358   resizeMainWindow();
359   mainWindow->shrink();
360   mainWindow->syncUi();
361 }
362
363 void QbWindow::shrink()
364 {
365   if(config().video.isFullscreen == false)
366   {
367     for(unsigned i = 0; i < 2; i++)
368         {
369       resize(0, 0);
370       usleep(2000);
371       QApplication::processEvents();
372     }
373   }
374 }
375 #endif