2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License along
13 with this program; if not, write to the Free Software Foundation, Inc.,
14 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 #include "braininavat.h"
19 #include "brainview.h"
25 // Constructor which creates the main window.
27 BrainInAVat::BrainInAVat() {
29 scrollArea
= new QScrollArea(this);
30 ourView
= new BrainView();
31 scrollArea
->setWidget(ourView
);
32 setCentralWidget(scrollArea
);
35 setWindowTitle(tr("openc2e's Brain in a Vat"));
40 openAct
= new QAction(tr("&Open..."), this);
41 openAct
->setShortcut(tr("Ctrl+O"));
42 openAct
->setStatusTip(tr("Open a genome file"));
43 connect(openAct
, SIGNAL(triggered()), this, SLOT(open()));
45 for (int i
= 0; i
< MaxRecentFiles
; ++i
) {
46 recentFileActs
[i
] = new QAction(this);
47 recentFileActs
[i
]->setVisible(false);
48 connect(recentFileActs
[i
], SIGNAL(triggered()), this, SLOT(openRecentFile()));
51 exitAct
= new QAction(tr("E&xit"), this);
52 exitAct
->setShortcut(tr("Ctrl+Q"));
53 exitAct
->setStatusTip(tr("Exit Brain in a Vat"));
54 connect(exitAct
, SIGNAL(triggered()), qApp
, SLOT(closeAllWindows()));
56 fileMenu
= menuBar()->addMenu(tr("&File"));
57 fileMenu
->addAction(openAct
);
58 separatorAct
= fileMenu
->addSeparator();
59 for (int i
= 0; i
< MaxRecentFiles
; ++i
)
60 fileMenu
->addAction(recentFileActs
[i
]);
61 fileMenu
->addSeparator();
62 fileMenu
->addAction(exitAct
);
63 updateRecentFileActions();
67 neuronActGroup
= new QActionGroup(this);
68 dendriteActGroup
= new QActionGroup(this);
69 thresholdActGroup
= new QActionGroup(this);
71 // neuron/dendrite variable selection
72 for (unsigned int i
= 0; i
< 8; i
++) {
73 // TODO: friendly names for neuron/dendrite vars
75 neuronActs
[i
] = new QAction(tr("Neuron var %1").arg(i
), this);
76 neuronActGroup
->addAction(neuronActs
[i
]);
77 neuronActs
[i
]->setCheckable(true);
78 connect(neuronActs
[i
], SIGNAL(triggered()), this, SLOT(setSomeVar()));
79 dendriteActs
[i
] = new QAction(tr("Dendrite var %1").arg(i
), this);
80 dendriteActGroup
->addAction(dendriteActs
[i
]);
81 dendriteActs
[i
]->setCheckable(true);
82 connect(dendriteActs
[i
], SIGNAL(triggered()), this, SLOT(setSomeVar()));
84 neuronActs
[0]->setChecked(true);
85 dendriteActs
[0]->setChecked(true);
87 // threshold for element visibility
88 noThresholdAct
= new QAction(tr("Show all elements"), this);
89 thresholdActGroup
->addAction(noThresholdAct
);
90 noThresholdAct
->setCheckable(true);
91 noThresholdAct
->setChecked(true);
92 connect(noThresholdAct
, SIGNAL(triggered()), this, SLOT(setNoThreshold()));
93 nonZeroThresholdAct
= new QAction(tr("Show elements with non-zero values only"), this);
94 thresholdActGroup
->addAction(nonZeroThresholdAct
);
95 nonZeroThresholdAct
->setCheckable(true);
96 connect(nonZeroThresholdAct
, SIGNAL(triggered()), this, SLOT(setNonZeroThreshold()));
97 showNoneAct
= new QAction(tr("Show no elements"), this);
98 thresholdActGroup
->addAction(showNoneAct
);
99 showNoneAct
->setCheckable(true);
100 connect(showNoneAct
, SIGNAL(triggered()), this, SLOT(setShowNone()));
102 viewMenu
= menuBar()->addMenu(tr("&View"));
103 for (unsigned int i
= 0; i
< 8; i
++)
104 viewMenu
->addAction(neuronActs
[i
]);
105 viewMenu
->addSeparator();
106 for (unsigned int i
= 0; i
< 8; i
++)
107 viewMenu
->addAction(dendriteActs
[i
]);
108 viewMenu
->addSeparator();
109 viewMenu
->addAction(noThresholdAct
);
110 viewMenu
->addAction(nonZeroThresholdAct
);
111 viewMenu
->addAction(showNoneAct
);
115 tickAct
= new QAction(tr("&Tick"), this);
116 tickAct
->setStatusTip(tr("Run the brain through one iteration"));
117 tickAct
->setEnabled(false);
118 connect(tickAct
, SIGNAL(triggered()), this, SLOT(tick()));
120 sleepToggleAct
= new QAction(tr("&Sleep"), this);
121 sleepToggleAct
->setStatusTip(tr("Set whether the brain is asleep (and dreaming) or not"));
122 sleepToggleAct
->setCheckable(true);
123 sleepToggleAct
->setEnabled(false);
124 connect(sleepToggleAct
, SIGNAL(triggered()), this, SLOT(toggleSleep()));
126 controlMenu
= menuBar()->addMenu(tr("&Control"));
127 controlMenu
->addAction(tickAct
);
128 controlMenu
->addAction(sleepToggleAct
);
130 controlToolbar
= addToolBar(tr("Control"));
131 controlToolbar
->addAction(tickAct
);
135 menuBar()->addSeparator();
137 aboutAct
= new QAction(tr("&About"), this);
138 aboutAct
->setStatusTip(tr("Find out about Brain in a Vat"));
139 connect(aboutAct
, SIGNAL(triggered()), this, SLOT(about()));
141 helpMenu
= menuBar()->addMenu(tr("&Help"));
142 helpMenu
->addAction(aboutAct
);
145 BrainInAVat::~BrainInAVat() {
153 void BrainInAVat::open() {
154 QString fileName
= QFileDialog::getOpenFileName(this, tr("Pick a genome"), QString(), tr("Genomes (*.gen)"));
155 if (!fileName
.isEmpty())
159 void BrainInAVat::openRecentFile() {
160 QAction
*action
= qobject_cast
<QAction
*>(sender());
163 loadFile(action
->data().toString());
166 void BrainInAVat::about() {
167 QMessageBox::about(this, tr("openc2e's Brain in a Vat"), tr("An openc2e tool to monitor and experiment upon creature brains."));
170 void BrainInAVat::tick() {
171 // brain updates are every 4 ticks
172 // TODO: this is icky
173 for (unsigned int i
= 0; i
< 4; i
++)
179 void BrainInAVat::setSomeVar() {
180 QAction
*action
= qobject_cast
<QAction
*>(sender());
182 for (unsigned int i
= 0; i
< 8; i
++) {
183 if (action
== neuronActs
[i
])
184 ourView
->neuron_var
= i
;
185 else if (action
== dendriteActs
[i
])
186 ourView
->dendrite_var
= i
;
192 void BrainInAVat::setNoThreshold() {
193 ourView
->threshold
= -1000.0f
;
197 void BrainInAVat::setNonZeroThreshold() {
198 ourView
->threshold
= 0.0f
;
202 void BrainInAVat::setShowNone() {
203 ourView
->threshold
= 1000.0f
;
207 void BrainInAVat::toggleSleep() {
208 ourCreature
->setDreaming(!ourCreature
->isDreaming());
209 sleepToggleAct
->setChecked(ourCreature
->isDreaming());
212 // code to Do Things!
214 void BrainInAVat::loadFile(const QString
&fileName
) {
215 // zot any existing file
216 setCurrentFile(QString());
220 ourView
->setCreature(ourCreature
);
222 tickAct
->setEnabled(false);
223 sleepToggleAct
->setChecked(false);
224 sleepToggleAct
->setEnabled(false);
227 ifstream
f(fileName
.toAscii(), std::ios::binary
);
229 QMessageBox::warning(this, tr("openc2e's Brain in a Vat"), tr("Cannot read file %1.").arg(fileName
));
233 QApplication::setOverrideCursor(Qt::WaitCursor
);
237 shared_ptr
<genomeFile
> gfile(new genomeFile());
240 } catch (genomeException
&e
) {
241 QApplication::restoreOverrideCursor();
242 QMessageBox::warning(this, tr("openc2e's Brain in a Vat"), tr("Failed loading the genome due to error '%1'!").arg(e
.what()));
246 // TODO: dialog to pick age, gender, variant?
249 if (gfile
->getVersion() == 3) {
251 ourCreature
= new c2eCreature(gfile
, true, 0);
252 } catch (creaturesException
&e
) {
253 QApplication::restoreOverrideCursor();
254 QMessageBox::warning(this, tr("openc2e's Brain in a Vat"), e
.what());
258 QApplication::restoreOverrideCursor();
259 QMessageBox::warning(this, tr("openc2e's Brain in a Vat"), tr("This genome is of version %1, which is unsupported.").arg(gfile
->getVersion()));
263 QApplication::restoreOverrideCursor();
265 ourView
->setCreature(ourCreature
);
267 // we're done; update title/recent files, and display a temporary status message
268 tickAct
->setEnabled(true);
269 sleepToggleAct
->setEnabled(true);
270 ourView
->resize(ourView
->minimumSize());
272 setCurrentFile(fileName
);
273 statusBar()->showMessage(tr("Loaded %1 genes").arg(gfile
->genes
.size()), 2000);
276 // Some Recent Files magic.
278 void BrainInAVat::setCurrentFile(const QString
&fileName
) {
280 if (curFile
.isEmpty()) {
281 setWindowTitle(tr("openc2e's Brain in a Vat"));
282 return; // TODO: is this correct?
284 setWindowTitle(tr("%1 - %2").arg(strippedName(curFile
)).arg(tr("openc2e's Brain in a Vat")));
286 // read the list of recent files
287 QSettings
settings("ccdevnet.org", "Brain In A Vat");
288 QStringList files
= settings
.value("recentFileList").toStringList();
290 // make sure the current file is at the top!
291 files
.removeAll(fileName
);
292 files
.prepend(fileName
);
293 // remove any which are over the size
294 while (files
.size() > MaxRecentFiles
)
297 // store the list of recent files
298 settings
.setValue("recentFileList", files
);
300 // update ourselves..
301 updateRecentFileActions(); // obviously assumes we only have one window
304 void BrainInAVat::updateRecentFileActions() {
305 // read the list of recent files
306 QSettings
settings("ccdevnet.org", "Brain In A Vat");
307 QStringList files
= settings
.value("recentFileList").toStringList();
309 // enable recent files actions as needed
310 int numRecentFiles
= qMin(files
.size(), (int)MaxRecentFiles
);
311 for (int i
= 0; i
< numRecentFiles
; ++i
) {
312 QString text
= tr("&%1 %2").arg(i
+ 1).arg(strippedName(files
[i
]));
313 recentFileActs
[i
]->setText(text
);
314 recentFileActs
[i
]->setData(files
[i
]);
315 recentFileActs
[i
]->setVisible(true);
318 // make sure the rest are disabled [ie, hidden]
319 for (int j
= numRecentFiles
; j
< MaxRecentFiles
; ++j
)
320 recentFileActs
[j
]->setVisible(false);
322 // only show the separator if there are recent files
323 separatorAct
->setVisible(numRecentFiles
> 0);
326 QString
BrainInAVat::strippedName(const QString
&fullFileName
) {
327 return QFileInfo(fullFileName
).fileName();