~sithlord48/hyne/trunk

42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
1
/****************************************************************************
2
 ** Hyne Final Fantasy VIII Save Editor
124 by myst6re
Merging Qt5 branch in trunk:
3
 ** Copyright (C) 2009-2013 Arzel Jérôme <myst6re@gmail.com>
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
4
 **
5
 ** This program is free software: you can redistribute it and/or modify
6
 ** it under the terms of the GNU General Public License as published by
7
 ** the Free Software Foundation, either version 3 of the License, or
8
 ** (at your option) any later version.
9
 **
10
 ** This program is distributed in the hope that it will be useful,
11
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 ** GNU General Public License for more details.
14
 **
15
 ** You should have received a copy of the GNU General Public License
16
 ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 ****************************************************************************/
18
19
#include "SavecardView.h"
20
#include "HeaderDialog.h"
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
21
#include "Config.h"
22
#include "Data.h"
23
#include "FF8Text.h"
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
24
25
SavecardView::SavecardView(SavecardWidget *parent) :
26
	QWidget(parent), cursorID(-1), blackID(-1),
27
	dropIndicatorID(-1), isExternalDrag(false),
28
	_dragStart(-1), notify(true), _data(0), _parent(parent),
110 by myst6re
Reenabling animation in save icons [SF#4].
29
	mouseMove(0), lastDropData(0), currentSaveIconFrame(0)
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
30
{
31
	setPalette(QPalette(Qt::black));
110 by myst6re
Reenabling animation in save icons [SF#4].
32
	connect(&SaveIcon::timer, SIGNAL(timeout()), SLOT(nextIcon()));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
33
	setMouseTracking(true);
34
	setAcceptDrops(true);
35
}
36
37
SavecardView::~SavecardView()
38
{
39
	if(lastDropData)	delete lastDropData;
40
}
41
42
void SavecardView::clear()
43
{
44
	if(_data) {
45
		_data = 0;
46
		update();
47
	}
48
}
49
50
SavecardData *SavecardView::savecard() const
51
{
52
	return _data;
53
}
54
55
void SavecardView::setSavecard(SavecardData *save)
56
{
57
	_data = save;
58
59
	if(_data) {
60
		setFixedSize(sizeHint());
61
		connect(_data->watcher(), SIGNAL(fileChanged(QString)), SLOT(notifyFileChanged(QString)));
110 by myst6re
Reenabling animation in save icons [SF#4].
62
		if(!SaveIcon::timer.isActive()) {
63
			SaveIcon::timer.start();
64
		}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
65
	}
66
}
67
68
void SavecardView::notifyFileChanged(const QString &path)
69
{
70
	if(!notify)	return;
71
	notify = false;
72
	if(!QFile::exists(path))
73
	{
124 by myst6re
Merging Qt5 branch in trunk:
74
		QMessageBox::warning(this->parentWidget(), tr("Fichier supprimé"),
75
							 tr("Le fichier '%1' a été supprimé par un programme externe !").arg(path));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
76
	}
77
	else
78
	{
124 by myst6re
Merging Qt5 branch in trunk:
79
		QMessageBox::warning(this->parentWidget(), tr("Fichier modifié"),
80
							 tr("Le fichier '%1' a été modifié par un programme externe.").arg(path));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
81
	}
82
	notify = true;
83
}
84
44 by myst6re
Optimize draw functions.
85
void SavecardView::updateSave(int saveID, bool withCursor)
86
{
87
	if(withCursor) {
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
88
		update(QRect(savePoint(saveID) - QPoint(horizontalMargin(), 0), saveSize() + QSize(horizontalMargin(), 0)));
44 by myst6re
Optimize draw functions.
89
	} else {
90
		update(saveRect(saveID));
91
	}
92
}
93
94
void SavecardView::updateSaves(const QList<int> &saveIDs, bool withCursor)
95
{
96
	if(saveIDs.isEmpty())	return;
97
	if(saveIDs.size() == 1) {
98
		updateSave(saveIDs.first(), withCursor);
99
		return;
100
	}
101
102
	int minID=_data->saveCount(), maxID=-1;
103
104
	foreach(int id, saveIDs) {
105
		if(id < 0 || id > _data->saveCount()) {
106
			continue;
107
		}
108
		if(id < minID)	minID = id;
109
		if(id > maxID)	maxID = id;
110
	}
111
112
	if(minID == maxID) {
113
		updateSave(minID, withCursor);
114
	} else {
115
		if(withCursor) {
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
116
			update(QRect(savePoint(minID) - QPoint(horizontalMargin(), 0),
117
						 QSize(saveWidth() + horizontalMargin(), saveHeight() * (maxID - minID + 1))));
44 by myst6re
Optimize draw functions.
118
		} else {
119
			update(QRect(savePoint(minID), QSize(saveWidth(), saveHeight() * (maxID - minID + 1))));
120
		}
121
	}
122
}
123
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
124
void SavecardView::moveCursor(int saveID)
125
{
44 by myst6re
Optimize draw functions.
126
	if(saveID == cursorID)	return;
127
128
	int oldCursorID = cursorID, minID, maxID;
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
129
	cursorID = saveID;
44 by myst6re
Optimize draw functions.
130
131
	if(oldCursorID < 0) {
132
		oldCursorID = cursorID;
133
	}
134
135
	if(oldCursorID < cursorID) {
136
		minID = oldCursorID;
137
		maxID = cursorID;
138
	} else {
139
		minID = cursorID;
140
		maxID = oldCursorID;
141
	}
142
143
	if(minID < 0) {
144
		minID = maxID;
145
	} else if(maxID < 0) {
146
		maxID = minID;
147
	}
148
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
149
	update(QRect(savePoint(minID) + QPoint(-36, 16), QSize(48, (maxID - minID)*saveHeight() + 46)));
44 by myst6re
Optimize draw functions.
150
}
151
152
void SavecardView::setDropIndicator(int saveID)
153
{
154
	if(dropIndicatorID == saveID) return;
155
156
	dropIndicatorID = saveID;
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
157
	update();
158
}
159
44 by myst6re
Optimize draw functions.
160
void SavecardView::setBlackSave(int saveID)
161
{
162
	if(blackID == saveID) return;
163
164
	int oldBlackID = blackID;
165
	blackID = saveID;
166
167
	if(blackID <= -1) {
168
		updateSave(oldBlackID, true);
169
	} else if(oldBlackID <= -1) {
170
		updateSave(blackID, true);
171
	} else {
172
		updateSaves(QList<int>() << oldBlackID << blackID, true);
173
	}
174
}
175
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
176
void SavecardView::moveDraggedSave(int saveID)
177
{
178
	if(!_data)	return;
179
	if(_dragStart < saveID) {
180
		saveID--;
181
	}
182
183
	if(_dragStart != saveID
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
184
			&& _dragStart >= 0 && _dragStart < _data->saveCount()) {
44 by myst6re
Optimize draw functions.
185
		_data->moveSave(_dragStart, saveID);
186
187
		updateSaves(QList<int>() << _dragStart << saveID);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
188
189
		emit changed();
190
	}
191
192
	_dragStart = -1;
193
}
194
195
void SavecardView::replaceSaveData(int saveID, const QByteArray &mimeData)
196
{
197
	if(!_data)	return;
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
198
	if(saveID >=0 && saveID < _data->saveCount()
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
199
			&& !mimeData.isEmpty()) {
200
		SaveData *saveData = _data->getSave(saveID);
201
202
		if(!saveData->isDelete()) {
124 by myst6re
Merging Qt5 branch in trunk:
203
			QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Écraser"), tr("Tout le contenu de la sauvegarde sera écrasé.\nContinuer ?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
204
			if(answer != QMessageBox::Yes) {
205
				return;
206
			}
207
		}
208
209
		if(mimeData.size() > SAVE_SIZE) {
210
			saveData->open(mimeData.left(SAVE_SIZE), mimeData.mid(SAVE_SIZE));
211
		} else if(mimeData.size() == SAVE_SIZE) {
212
			QByteArray MCHeader;
213
			if(saveData->hasMCHeader()) {
214
				HeaderDialog dialog(saveData, this, HeaderDialog::CreateView);
215
216
				if(dialog.exec() != QDialog::Accepted) {
217
					return;
218
				}
219
				MCHeader = saveData->MCHeader();
220
			}
221
			saveData->open(mimeData, MCHeader);
222
		} else {
223
			return;
224
		}
225
226
		_data->setModified(true);
227
		saveData->setModified(true);
228
		emit changed();
229
	}
230
}
231
232
void SavecardView::edit(int saveID)
233
{
234
	if(!_data)	return;
235
236
	if(saveID == -1) {
237
		saveID = this->saveID(startPos);
238
	}
239
240
	SaveData *saveData = _data->getSave(saveID);
241
	if(!saveData)	return;
242
243
	if(saveData->isFF8() && !saveData->isDelete())
244
		emit released(saveData);
245
}
246
247
void SavecardView::exportPC(int saveID)
248
{
249
	if(!_data)	return;
250
251
	if(saveID == -1) {
252
		saveID = this->saveID(startPos);
253
	}
254
255
	SaveData *saveData = _data->getSave(saveID);
256
	if(!saveData)	return;
257
102 by myst6re
Using an enumeration to list all config keys.
258
	QString path, savePath = Config::value(Config::SavePath);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
259
	int index;
260
102 by myst6re
Using an enumeration to list all config keys.
261
	if(savePath.isEmpty()) {
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
262
		index = _data->path().lastIndexOf('/');
263
		if(index != -1)		path = _data->path().left(index+1);
102 by myst6re
Using an enumeration to list all config keys.
264
	} else {
265
		path = savePath % "/";
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
266
	}
267
91 by myst6re
Fixing bug: when a save was removed in Slot mode, it was not really removed when saving.
268
	path = QFileDialog::getSaveFileName(this, tr("Exporter"), path % QString("save%1").arg(saveData->id()+1, 2, 10, QChar('0')), tr("FF8 PC save (* *.ff8)"));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
269
	if(path.isEmpty())		return;
270
271
	index = path.lastIndexOf('/');
102 by myst6re
Using an enumeration to list all config keys.
272
	Config::setValue(Config::SavePath, index == -1 ? path : path.left(index));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
273
102 by myst6re
Using an enumeration to list all config keys.
274
	if(!saveData->exportPC(path)) {
124 by myst6re
Merging Qt5 branch in trunk:
275
		QMessageBox::warning(this, tr("Échec"), tr("Enregistrement échoué, vérifiez que le fichier cible n'est pas utilisé."));
102 by myst6re
Using an enumeration to list all config keys.
276
	}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
277
}
278
279
void SavecardView::newGame(int saveID)
280
{
281
	if(!_data)	return;
282
283
	if(saveID == -1) {
284
		saveID = this->saveID(startPos);
285
	}
286
287
	SaveData *saveData = _data->getSave(saveID);
288
	if(!saveData)	return;
289
290
	if(!saveData->isDelete()) {
124 by myst6re
Merging Qt5 branch in trunk:
291
		QMessageBox::StandardButton b = QMessageBox::question(this, tr("Nouvelle partie"), tr("Tout le contenu de la sauvegarde sera remplacé par une nouvelle partie.\nContinuer ?"), QMessageBox::Yes | QMessageBox::No);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
292
		if(b != QMessageBox::Yes) {
293
			return;
294
		}
295
	}
296
297
	QFile newGameFile(":/data/newGame");
298
	if(!newGameFile.open(QIODevice::ReadOnly)) {
299
		qWarning() << "failed to open data/newGame" << newGameFile.errorString();
300
		return;
301
	}
302
303
	if(saveData->hasMCHeader() && (!saveData->isFF8() || saveData->isDelete())) {
304
		HeaderDialog dialog(saveData, this, HeaderDialog::RestoreView);
305
		if(dialog.exec()==QDialog::Accepted)
306
		{
307
			saveData->restore();
308
		}
309
		else
310
		{
311
			return;
312
		}
313
	}
314
315
	saveData->open(newGameFile.readAll(), saveData->MCHeader());
74 by myst6re
HEADER.linoa renamed into HEADER.rinoa
316
	// Set translated names
317
	saveData->setPerso(SQUALL, Data::names().at(SQUALL));
318
	saveData->setPerso(RINOA, Data::names().at(RINOA));
319
	saveData->setPerso(GRIEVER, Data::names().at(GRIEVER));
320
	saveData->setPerso(BOKO, Data::names().at(BOKO));
321
	saveData->setPerso(ANGELO, Data::names().at(ANGELO));
322
	int gfID=0;
323
	foreach(const QString &gfName, Data::gfnames().list()) {
324
		saveData->setGf(gfID++, gfName);
325
	}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
326
	saveData->setModified(true);
327
	emit changed();
328
	newGameFile.close();
329
330
	update();
331
}
332
333
void SavecardView::removeSave(int saveID)
334
{
335
	if(!_data)	return;
336
337
	if(saveID == -1) {
338
		saveID = this->saveID(startPos);
339
	}
340
341
	SaveData *saveData = _data->getSave(saveID);
342
	if(!saveData)	return;
343
344
	if(!saveData->isDelete()) {
124 by myst6re
Merging Qt5 branch in trunk:
345
		QMessageBox::StandardButton b = QMessageBox::question(this, tr("Vider"), tr("Tout le contenu de la sauvegarde sera vidé.\nContinuer ?"), QMessageBox::Yes | QMessageBox::No);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
346
		if(b != QMessageBox::Yes) {
347
			return;
348
		}
349
	}
350
351
	saveData->remove();
352
	emit changed();
353
354
	update();
355
}
356
357
void SavecardView::properties(int saveID)
358
{
359
	if(!_data)	return;
360
361
	if(saveID == -1) {
362
		saveID = this->saveID(startPos);
363
	}
364
365
	SaveData *saveData = _data->getSave(saveID);
366
	if(!saveData)	return;
367
368
	HeaderDialog dialog(saveData, this);
369
370
	if(dialog.exec() == QDialog::Accepted
371
			&& saveData->isModified()) {
372
		emit changed();
373
		if(!saveData->isFF8() && !saveData->isDelete()) {
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
374
			refreshIcon(saveData); // update icon
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
375
		}
376
	}
377
}
378
379
void SavecardView::restore(int saveID)
380
{
381
	if(!_data)	return;
382
	SaveData *saveData = _data->getSave(saveID);
383
	if(!saveData)	return;
384
124 by myst6re
Merging Qt5 branch in trunk:
385
	QMessageBox::StandardButton reponse = QMessageBox::question(this, tr("Sauvegarde supprimée"), tr("Cette sauvegarde a été supprimée, voulez-vous tenter de la réparer ? (succès non garanti)"),
68 by myst6re
SavecardData::ok() renamed into isOpen().
386
																QMessageBox::Yes | QMessageBox::No);
387
	if(reponse != QMessageBox::Yes)  return;
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
388
389
	HeaderDialog dialog(saveData, this, HeaderDialog::RestoreView);
390
391
	if(dialog.exec() == QDialog::Accepted)
392
	{
393
		saveData->restore();
394
		emit changed();
395
	}
396
}
397
398
int SavecardView::saveID(const QPoint &pos) const
399
{
400
	if(pos.x() < 0
401
			|| pos.x() >= width()
402
			|| pos.y() < 0
403
			|| pos.y() >= height())
404
		return -1;
405
406
	return pos.y() / saveHeight();
407
}
408
409
QSize SavecardView::sizeHint() const
410
{
411
	if(!_data)	return QSize();
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
412
	return QSize(horizontalMargin() * 2 + saveWidth(), saveHeight() * _data->saveCount());
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
413
}
414
415
QSize SavecardView::minimumSizeHint() const
416
{
417
	return sizeHint();
418
}
419
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
420
void SavecardView::refreshIcon(SaveData *saveData)
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
421
{
422
	if(!saveData->isDelete()) {
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
423
		repaint(QRect(savePoint(saveData->id()) + QPoint(36, 43), QSize(16, 16)));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
424
	}
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
425
}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
426
110 by myst6re
Reenabling animation in save icons [SF#4].
427
void SavecardView::nextIcon()
428
{
429
	if(!_data) return;
430
431
	++currentSaveIconFrame;
432
	foreach(SaveData *saveData, _data->getSaves()) {
433
		refreshIcon(saveData);
434
	}
435
}
436
437
void SavecardView::renderSave(QPainter *painter, const SaveData *saveData, int currentIconFrame, const QRect &sourceRect)
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
438
{
439
	QPixmap menuBg(QString(":/images/menu-fond%1.png").arg(!saveData->isTheLastEdited() && !saveData->isDelete() ? "" : "2"));
440
	QPixmap menuTitle(":/images/numbers_title.png");
44 by myst6re
Optimize draw functions.
441
	QImage numberPixmap(":/images/numbers.png");
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
442
110 by myst6re
Reenabling animation in save icons [SF#4].
443
	renderSave(painter, saveData, menuBg, menuTitle, numberPixmap, currentIconFrame, sourceRect);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
444
}
445
110 by myst6re
Reenabling animation in save icons [SF#4].
446
void SavecardView::renderSave(QPixmap *pixmap, const SaveData *saveData, int currentIconFrame, const QRect &sourceRect)
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
447
{
448
	QPainter p(pixmap);
110 by myst6re
Reenabling animation in save icons [SF#4].
449
	renderSave(&p, saveData, currentIconFrame, sourceRect);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
450
}
451
110 by myst6re
Reenabling animation in save icons [SF#4].
452
void SavecardView::renderSave(QPainter *painter, const SaveData *saveData, const QPixmap &menuBg, const QPixmap &fontPixmap, QImage &numberPixmap, int currentIconFrame, const QRect &sourceRect)
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
453
{
44 by myst6re
Optimize draw functions.
454
	QRect toBePainted;
455
	if(sourceRect.isNull()) {
456
		toBePainted = QRect(QPoint(0, 0), saveSize());
457
	} else {
458
		toBePainted = sourceRect;
459
	}
460
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
461
	painter->save();
462
44 by myst6re
Optimize draw functions.
463
	// Background
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
464
	painter->setBrush(QBrush(menuBg));
465
	drawFrame(painter, saveWidth(), saveHeight());
466
44 by myst6re
Optimize draw functions.
467
	// Save Number (Frame title)
468
	if(!(toBePainted & QRect(4, 0, 36, 22)).isEmpty()) {
469
		QString title = QString("%1").arg(saveData->id()+1, 2, 10, QChar('0'));
470
		painter->drawPixmap(4, 0, fontPixmap.copy(title.at(0).digitValue()*16, 0, 16, 22));
471
		painter->drawPixmap(20, 0, fontPixmap.copy(title.at(1).digitValue()*16, 0, 16, 22));
472
	}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
473
474
	if(saveData->isFF8())
475
	{
44 by myst6re
Optimize draw functions.
476
		// Portrait chars
58 by myst6re
Editors:
477
		if(saveData->constDescData().party[0] != 255
44 by myst6re
Optimize draw functions.
478
				&& !(toBePainted & QRect(44, 4, 64, 96)).isEmpty())
58 by myst6re
Editors:
479
			painter->drawPixmap(44, 4, QPixmap(QString(":/images/icons/perso%1.png").arg(saveData->constDescData().party[0] & 15)));
480
		if(saveData->constDescData().party[1] != 255
44 by myst6re
Optimize draw functions.
481
				&& !(toBePainted & QRect(112, 4, 64, 96)).isEmpty())
58 by myst6re
Editors:
482
			painter->drawPixmap(112, 4, QPixmap(QString(":/images/icons/perso%1.png").arg(saveData->constDescData().party[1] & 15)));
483
		if(saveData->constDescData().party[2] != 255
44 by myst6re
Optimize draw functions.
484
				&& !(toBePainted & QRect(180, 4, 64, 96)).isEmpty())
58 by myst6re
Editors:
485
			painter->drawPixmap(180, 4, QPixmap(QString(":/images/icons/perso%1.png").arg(saveData->constDescData().party[2] & 15)));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
486
44 by myst6re
Optimize draw functions.
487
		// Main char name
488
		if(!(toBePainted & QRect(271, 8, saveWidth()-271, 24)).isEmpty()) {
58 by myst6re
Editors:
489
			int persoIndex = saveData->constDescData().party[0] != 255 ? saveData->constDescData().party[0] : (saveData->constDescData().party[1] != 255 ? saveData->constDescData().party[1] : saveData->constDescData().party[2]);
44 by myst6re
Optimize draw functions.
490
			bool langIndep = persoIndex==SQUALL || persoIndex==RINOA || persoIndex==GRIEVER || persoIndex==BOKO || persoIndex==ANGELO;
491
			FF8Text::drawTextArea(painter, QPoint(271, 8), saveData->perso(persoIndex), langIndep ? (saveData->isJp() ? 2 : 1) : 0);
492
		}
493
494
		// Level
495
		if(!(toBePainted & QRect(271, 36, saveWidth()-271, 24)).isEmpty()) {
58 by myst6re
Editors:
496
			FF8Text::drawTextArea(painter, QPoint(271, 36), tr("NV%1").arg(saveData->constDescData().nivLeader,3,10,QChar(' ')), 1);
44 by myst6re
Optimize draw functions.
497
		}
498
499
		// Disc number
500
		if(!(toBePainted & QRect(391, 38, saveWidth()-391, 16)).isEmpty()) {
102 by myst6re
Using an enumeration to list all config keys.
501
			QPixmap disc(QString(":/images/disc_%1.png").arg(Config::value(Config::Lang)=="fr" ? "fr" : "en"));
44 by myst6re
Optimize draw functions.
502
			painter->drawPixmap(391, 38, disc);
58 by myst6re
Editors:
503
			num2pix(painter, &numberPixmap, 395+disc.width(), 38, saveData->constDescData().disc+1);
44 by myst6re
Optimize draw functions.
504
		}
505
506
		// Play time
507
		if(!(toBePainted & QRect(511, 16, saveWidth()-511, 16)).isEmpty()) {
102 by myst6re
Using an enumeration to list all config keys.
508
			painter->drawPixmap(511, 16, QPixmap(QString(":/images/play_%1.png").arg(Config::value(Config::Lang)=="fr" ? "fr" : "en")));
44 by myst6re
Optimize draw functions.
509
58 by myst6re
Editors:
510
			int hour = Config::hour(saveData->constDescData().time, saveData->freqValue());
44 by myst6re
Optimize draw functions.
511
			int color = (hour>=100) + (hour>=200) + (hour>=300) + (hour>=400) + (hour>=500);
512
			num2pix(painter, &numberPixmap, 576, 16, hour, 2, QChar(' '), color);
513
514
			QImage deux_points(":/images/deux-points.png");
515
			colors(&deux_points, color);
516
			painter->drawImage(612, 18, deux_points);
58 by myst6re
Editors:
517
			num2pix(painter, &numberPixmap, 624, 16, Config::min(saveData->constDescData().time, saveData->freqValue()), 2, QChar('0'), color);
44 by myst6re
Optimize draw functions.
518
		}
519
520
		// Gils
521
		if(!(toBePainted & QRect(511, 40, saveWidth()-511, 16)).isEmpty()) {
58 by myst6re
Editors:
522
			num2pix(painter, &numberPixmap, 511, 40, saveData->constDescData().gils, 8);
44 by myst6re
Optimize draw functions.
523
			painter->drawPixmap(640, 44, QPixmap(":/images/gils.png"));
524
		}
525
526
		if(!(toBePainted & QRect(256, 62, 416, 44)).isEmpty()) {
527
			// Sub-Frame
528
			painter->translate(256, 62);
529
			painter->setBrush(QBrush());
530
			drawFrame(painter, 416, 44);
531
532
			// Location
533
			if(!(toBePainted & QRect(256+12, 62+12, saveWidth()-(256+12), 24)).isEmpty()) {
58 by myst6re
Editors:
534
				FF8Text::drawTextArea(painter, QPoint(12, 12), saveData->constDescData().locationID<251 ? Data::locations().at(saveData->constDescData().locationID) : QString("??? (%1)").arg(saveData->constDescData().locationID));
44 by myst6re
Optimize draw functions.
535
			}
536
		}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
537
	}
538
	else
539
	{
44 by myst6re
Optimize draw functions.
540
		if(!(toBePainted & QRect(36, 43, saveWidth()-36, 24)).isEmpty()) {
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
541
			if(saveData->isRaw())
542
			{
543
				// Unavailable block
124 by myst6re
Merging Qt5 branch in trunk:
544
				FF8Text::drawTextArea(painter, QPoint(36, 43), tr("Bloc occupé"));
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
545
			}
546
			else if(saveData->isDelete())
44 by myst6re
Optimize draw functions.
547
			{
548
				// Available block
549
				FF8Text::drawTextArea(painter, QPoint(36, 43), tr("Bloc Disponible"));
550
			}
551
			else
552
			{
553
				// Icon + description
110 by myst6re
Reenabling animation in save icons [SF#4].
554
				painter->drawPixmap(36, 43, saveData->saveIcon().icon(currentIconFrame % saveData->saveIcon().nbFrames()));
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
555
				QString short_desc = saveData->shortDescription();
44 by myst6re
Optimize draw functions.
556
				if(!short_desc.isEmpty())
557
				{
558
					painter->setPen(Qt::white);
559
					painter->drawText(68, 59, short_desc);
560
				}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
561
			}
562
		}
563
	}
564
565
	painter->restore();
566
567
	// Save modification state
568
	if(saveData->isModified() || saveData->wasModified()) {
569
		QPen pen(saveData->isModified() ? QColor(0xd1,0x1d,0x1d) : QColor(0x1d,0xd1,0x1d), 3);
570
		painter->setPen(pen);
571
		painter->drawLine(670, 3, 670, 103);
572
	}
573
}
574
575
void SavecardView::paintEvent(QPaintEvent *event)
576
{
577
	QPainter painter(this);
578
	painter.fillRect(event->rect(), palette().color(QPalette::Window));
579
580
	if(_data) {
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
581
		painter.translate(horizontalMargin(), 0);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
582
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
583
		int curSaveID, minSaveID, maxSaveID;
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
584
		minSaveID = saveID(event->rect().topLeft());
44 by myst6re
Optimize draw functions.
585
		maxSaveID = saveID(event->rect().bottomRight());
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
586
587
		QPixmap menuBg(":/images/menu-fond.png");
588
		QPixmap menuBg2(":/images/menu-fond2.png");
589
		QPixmap menuTitle(":/images/numbers_title.png");
44 by myst6re
Optimize draw functions.
590
		QImage numberPixmap(":/images/numbers.png");
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
591
44 by myst6re
Optimize draw functions.
592
		// Translate painter to the first save to be drawn
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
593
		if(minSaveID > 0) {
594
			painter.translate(0, minSaveID * saveHeight());
595
		}
596
597
		for(curSaveID = minSaveID ; curSaveID <= maxSaveID && curSaveID < _data->saveCount() ; ++curSaveID) {
598
			if(blackID != curSaveID) {
599
				SaveData *saveData = _data->getSaves().at(curSaveID);
44 by myst6re
Optimize draw functions.
600
601
				QRect sourceRect = (event->rect() & saveRect(curSaveID));
602
				sourceRect.moveTopLeft(sourceRect.topLeft() - savePoint(curSaveID));
603
604
				// Paint save
605
				renderSave(&painter, saveData,
606
						   !saveData->isTheLastEdited()
607
						   && !saveData->isDelete() ? menuBg : menuBg2,
608
						   menuTitle, numberPixmap,
110 by myst6re
Reenabling animation in save icons [SF#4].
609
						   currentSaveIconFrame,
44 by myst6re
Optimize draw functions.
610
						   sourceRect);
611
612
				// Paint cursor hand
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
613
				if(cursorID == curSaveID) {
614
					painter.drawPixmap(-36, 16, QPixmap(":/images/cursor.png"));
615
				}
616
			}
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
617
			// Drop indicator
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
618
			if(dropIndicatorID == curSaveID) {
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
619
				if(isExternalDrag) { // Overwrite
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
620
					QPen pen(Qt::white, 3);
621
					painter.setPen(pen);
622
					painter.setBrush(QBrush());
623
					painter.drawRect(0, 2, saveWidth(), saveHeight()-4);
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
624
				} else { // Insert
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
625
					QPen pen(Qt::white, 8);
626
					painter.setPen(pen);
627
					painter.drawLine(0, 0, saveWidth(), 0);
628
				}
629
			}
630
631
			painter.translate(0, saveHeight());
43 by myst6re
Adding SavecardData::saveCount function for cleaner code.
632
		}
633
		// Insert indicator after the last item
634
		if(dropIndicatorID >= curSaveID && curSaveID == _data->saveCount()) {
635
			if(!isExternalDrag) {
636
				QPen pen(Qt::white, 8);
637
				painter.setPen(pen);
638
				painter.drawLine(0, 0, saveWidth(), 0);
639
			}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
640
		}
641
	}
642
}
643
644
void SavecardView::drawFrame(QPainter *painter, int width, int height)
645
{
44 by myst6re
Optimize draw functions.
646
	QLine lines[4];
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
647
	QPen pen(QColor(41,41,41));
44 by myst6re
Optimize draw functions.
648
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
649
	pen.setWidth(2);
650
	pen.setJoinStyle(Qt::MiterJoin);
651
	painter->setPen(pen);
44 by myst6re
Optimize draw functions.
652
	painter->drawRect(QRect(1, 1, width-2, height-2));
653
654
	painter->setPen(QColor(132, 132, 132));
655
	lines[0] = QLine(4, 2, width-5, 2);
656
	lines[1] = QLine(4, 3, width-5, 3);
657
	lines[2] = QLine(2, 4, 2, height-5);
658
	lines[3] = QLine(3, 4, 3, height-5);
659
	painter->drawLines(lines, 4);
660
661
	painter->setPen(QColor(58, 58, 58));
662
	lines[0] = QLine(4, height-4, width-3, height-4);
663
	lines[1] = QLine(4, height-3, width-3, height-3);
664
	lines[2] = QLine(width-4, 4, width-4, height-5);
665
	lines[3] = QLine(width-3, 4, width-3, height-5);
666
	painter->drawLines(lines, 4);
667
668
	painter->setPen(QColor(82, 82, 82));
669
	lines[0] = QLine(width-4, 2, width-3, 2);
670
	lines[1] = QLine(width-4, 3, width-3, 3);
671
	lines[2] = QLine(2, height-4, 3, height-4);
672
	lines[3] = QLine(2, height-3, 3, height-3);
673
	painter->drawLines(lines, 4);
674
675
	painter->setPen(QColor(99, 99, 99));
676
	painter->drawPoint(QPoint(2, 2));
677
	painter->drawPoint(QPoint(3, 2));
678
	painter->drawPoint(QPoint(2, 3));
679
	painter->drawPoint(QPoint(3, 3));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
680
}
681
44 by myst6re
Optimize draw functions.
682
void SavecardView::num2pix(QPainter *painter, QImage *numberPixmap, int x, int y, quint32 num, quint8 space, QChar fill, int color)
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
683
{
684
	colors(numberPixmap, color);
685
	QString strNum = QString("%1").arg(num, space, 10, fill).right(space);
686
687
	for(quint8 i=0 ; i<space ; ++i)
688
	{
689
		QChar c = strNum.at(i);
690
		if(c.isDigit())
691
			painter->drawImage(x+16*i, y, numberPixmap->copy(14*c.digitValue(), 0, 14, 16));
692
	}
693
}
694
695
void SavecardView::colors(QImage *image, int color)
696
{
697
	switch(color) {
698
	case 1://Red
699
		image->setColorTable(QVector<QRgb>() << qRgb(0xff,0x18,0x18) << qRgb(0x20,0x20,0x20) << qRgb(0x8b,0x18,0x18) << 0);
700
		return;
701
	case 2://Blue
702
		image->setColorTable(QVector<QRgb>() << qRgb(0x6a,0xb4,0xee) << qRgb(0x29,0x29,0x29) << qRgb(0x52,0x73,0x94) << 0);
703
		return;
704
	case 3://Yellow
705
		image->setColorTable(QVector<QRgb>() << qRgb(0xde,0xde,0x08) << qRgb(0x29,0x29,0x29) << qRgb(0x83,0x83,0x18) << 0);
706
		return;
707
	case 4://Green
708
		image->setColorTable(QVector<QRgb>() << qRgb(0x00,0xff,0x00) << qRgb(0x39,0x39,0x31) << qRgb(0x00,0xbd,0x00) << 0);
709
		return;
710
	case 5://Purple
711
		image->setColorTable(QVector<QRgb>() << qRgb(0xff,0x00,0xff) << qRgb(0x29,0x29,0x29) << qRgb(0x94,0x10,0x94) << 0);
712
		return;
713
	default:
714
		image->setColorTable(QVector<QRgb>() << qRgb(0xee,0xee,0xee) << qRgb(0x41,0x41,0x31) << qRgb(0xa4,0xa4,0xa4) << 0);
715
		return;
716
	}
717
}
718
719
void SavecardView::mousePressEvent(QMouseEvent *event)
720
{
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
721
	int xStart = horizontalMargin();
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
722
	int xEnd = width()-xStart;
723
724
	if(event->x() < xStart || event->x() > xEnd) {
725
		return;
726
	}
727
728
	if(event->button() == Qt::LeftButton) {
729
		mouseMove = 1;
730
		startPos = event->pos();
731
	}
732
}
733
734
void SavecardView::mouseMoveEvent(QMouseEvent *event)
735
{
736
	// Change cursor position
44 by myst6re
Optimize draw functions.
737
	moveCursor(saveID(event->pos()));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
738
739
	if(!mouseMove || !(event->buttons() & Qt::LeftButton)
740
			|| (startPos - event->pos()).manhattanLength() < QApplication::startDragDistance())
741
		return;
742
743
	mouseMove = 2;
744
745
	SaveData *saveData = _data->getSave(saveID(startPos));
746
	if(!saveData)	return;
747
748
	QDrag *drag = new QDrag(this);
749
	QMimeData *mimeData = new QMimeData;
750
751
	_dragStart = saveData->id();
752
	mimeData->setData("application/ff8save", saveData->save() + saveData->MCHeader());
753
	drag->setMimeData(mimeData);
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
754
	drag->setHotSpot(QPoint(event->pos().x() - horizontalMargin(), event->pos().y() % saveHeight()));
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
755
	QPixmap pixmap(saveSize());
110 by myst6re
Reenabling animation in save icons [SF#4].
756
	renderSave(&pixmap, saveData, currentSaveIconFrame);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
757
	drag->setPixmap(pixmap);
758
44 by myst6re
Optimize draw functions.
759
	setBlackSave(saveData->id());
760
	updateSave(saveData->id());
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
761
	drag->exec(Qt::MoveAction, Qt::MoveAction);// !Qt event loop blocked on Windows!
44 by myst6re
Optimize draw functions.
762
	setBlackSave(-1);
763
	updateSave(saveData->id());
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
764
}
765
766
void SavecardView::mouseReleaseEvent(QMouseEvent *event)
767
{
44 by myst6re
Optimize draw functions.
768
	setBlackSave(-1);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
769
	if(mouseMove == 2) {
770
		mouseMove = 0;
771
		return;
772
	} else {
773
		mouseMove = 0;
774
	}
775
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
776
	int xStart = horizontalMargin();
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
777
	int xEnd = width()-xStart;
778
779
	if(event->x() < xStart || event->x() > xEnd) {
780
		return;
781
	}
782
783
	SaveData *saveData = _data->getSave(saveID(event->pos()));
784
	if(!saveData)	return;
785
786
	if(event->button() == Qt::LeftButton)
787
	{
788
		if(saveData->isFF8()) {
789
			if(saveData->isDelete())
790
				restore(saveData->id());
791
			else
792
				edit(saveData->id());
793
		}
794
		else
795
		{
796
			if(saveData->isDelete()) {
797
				contextMenuEvent(new QContextMenuEvent(QContextMenuEvent::Other, event->pos(), event->globalPos(), event->modifiers()));
798
				return;
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
799
			} else if(!saveData->isRaw()) {
800
				properties(saveData->id());
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
801
			}
802
		}
803
	}
804
	else if(event->button() == Qt::MidButton)
805
	{
806
		if(saveData->isDelete()) {
807
			contextMenuEvent(new QContextMenuEvent(QContextMenuEvent::Other, event->pos(), event->globalPos(), event->modifiers()));
808
			return;
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
809
		} else if(!saveData->isRaw()) {
810
			properties(saveData->id());
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
811
		}
812
	}
813
}
814
815
void SavecardView::contextMenuEvent(QContextMenuEvent *event)
816
{
67 by myst6re
SaveCardView: Some modifications to make the code more readable (for size/position).
817
	int xStart = horizontalMargin();
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
818
	int xEnd = width()-xStart;
819
820
	if(event->x() < xStart || event->x() > xEnd) {
821
		return;
822
	}
823
824
	SaveData *saveData = _data->getSave(saveID(event->pos()));
825
	if(!saveData)	return;
826
827
	startPos = event->pos();
828
829
	QMenu menu(this);
830
	if(!saveData->isDelete() && saveData->isFF8()) {
831
		menu.setDefaultAction(menu.addAction(tr("&Modifier..."), this, SLOT(edit())));
832
		menu.addAction(tr("&Exporter en sauv. PC..."), this, SLOT(exportPC()));
833
	}
834
	menu.addAction(tr("&Nouvelle partie"), this, SLOT(newGame()));
835
	if(!saveData->isDelete()) {
836
		menu.addAction(tr("&Vider"), this, SLOT(removeSave()));
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
837
		if(!saveData->isRaw()) {
124 by myst6re
Merging Qt5 branch in trunk:
838
			QAction *action = menu.addAction(tr("&Propriétés..."), this, SLOT(properties()));
54 by myst6re
HeaderDialog: changing the "Save" button to "OK"
839
			if(!saveData->isFF8()) {
840
				menu.setDefaultAction(action);
841
			}
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
842
		}
843
	}
844
	menu.exec(event->globalPos());
845
}
846
847
void SavecardView::changeEvent(QEvent *event)
848
{
849
	if(event->type() == QEvent::LanguageChange) {
850
		update();
851
		event->accept();
852
	} else {
853
		QWidget::changeEvent(event);
854
	}
855
}
856
857
void SavecardView::dragEnterEvent(QDragEnterEvent *event)
858
{
859
	if(event->mimeData()->hasFormat("application/ff8save")) {
79 by myst6re
New option to open a new window. It's useful for Mac OSX because you can start just one instance of the application.
860
		isExternalDrag = event->source() != this; // external source
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
861
		event->acceptProposedAction();
862
	}
863
}
864
865
void SavecardView::dragMoveEvent(QDragMoveEvent *event)
866
{
867
	int saveID = this->saveID(event->pos());
868
	if(saveID >= 0) {
869
		setDropIndicator(saveID + int(event->pos().y() % saveHeight() > saveHeight()/2));
870
		_parent->scrollToDrag(event->pos());
871
	}
872
}
873
874
void SavecardView::dragLeaveEvent(QDragLeaveEvent *)
875
{
44 by myst6re
Optimize draw functions.
876
	setDropIndicator(-1);
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
877
}
878
879
void SavecardView::dropEvent(QDropEvent *event)
880
{
881
	lastDropID = dropIndicatorID;
882
	dragLeaveEvent(0);
883
884
	event->acceptProposedAction();
79 by myst6re
New option to open a new window. It's useful for Mac OSX because you can start just one instance of the application.
885
	isExternalDrag = event->source() != this;
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
886
	if(isExternalDrag) {
887
		if(lastDropData)	delete lastDropData;
888
		lastDropData = new QByteArray(event->mimeData()->data("application/ff8save"));
889
	}
44 by myst6re
Optimize draw functions.
890
	QTimer::singleShot(0, this, SLOT(drop()));// defer function call
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
891
}
892
44 by myst6re
Optimize draw functions.
893
void SavecardView::drop()
42 by myst6re
New list view that use a simple QScrollArea/QWidget instead of a QListWidget with widget items.
894
{
895
	if(isExternalDrag) {
896
		replaceSaveData(lastDropID, *lastDropData);
897
		delete lastDropData;
898
		lastDropData = 0;
899
	} else {
900
		moveDraggedSave(lastDropID);
901
	}
902
}