1 /* Copyright (c) 2013-2015 Jeffrey Pfau
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "PaletteView.h"
7 
8 #include "CoreController.h"
9 #include "GBAApp.h"
10 #include "LogController.h"
11 #include "VFileDevice.h"
12 
13 #include <QFileDialog>
14 
15 #include <mgba/core/core.h>
16 #ifdef M_CORE_GBA
17 #include <mgba/internal/gba/gba.h>
18 #endif
19 #ifdef M_CORE_GB
20 #include <mgba/internal/gb/gb.h>
21 #endif
22 #include <mgba-util/export.h>
23 #include <mgba-util/vfs.h>
24 
25 using namespace QGBA;
26 
PaletteView(std::shared_ptr<CoreController> controller,QWidget * parent)27 PaletteView::PaletteView(std::shared_ptr<CoreController> controller, QWidget* parent)
28 	: QWidget(parent)
29 	, m_controller(controller)
30 {
31 	m_ui.setupUi(this);
32 
33 	connect(controller.get(), &CoreController::frameAvailable, this, &PaletteView::updatePalette);
34 	m_ui.bgGrid->setDimensions(QSize(16, 16));
35 	m_ui.objGrid->setDimensions(QSize(16, 16));
36 	int count = 256;
37 #ifdef M_CORE_GB
38 	if (controller->platform() == mPLATFORM_GB) {
39 		m_ui.bgGrid->setDimensions(QSize(4, 8));
40 		m_ui.objGrid->setDimensions(QSize(4, 8));
41 		m_ui.bgGrid->setSize(24);
42 		m_ui.objGrid->setSize(24);
43 		count = 32;
44 	}
45 #endif
46 	m_ui.selected->setSize(64);
47 	m_ui.selected->setDimensions(QSize(1, 1));
48 	updatePalette();
49 
50 	const QFont font = GBAApp::app()->monospaceFont();
51 
52 	m_ui.hexcode->setFont(font);
53 	m_ui.value->setFont(font);
54 	m_ui.index->setFont(font);
55 	m_ui.r->setFont(font);
56 	m_ui.g->setFont(font);
57 	m_ui.b->setFont(font);
58 
59 	connect(m_ui.bgGrid, &Swatch::indexPressed, this, &PaletteView::selectIndex);
60 	connect(m_ui.objGrid, &Swatch::indexPressed, [this, count] (int index) { selectIndex(index + count); });
61 	connect(m_ui.exportBG, &QAbstractButton::clicked, [this, count] () { exportPalette(0, count); });
62 	connect(m_ui.exportOBJ, &QAbstractButton::clicked, [this, count] () { exportPalette(count, count); });
63 
64 	connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
65 }
66 
updatePalette()67 void PaletteView::updatePalette() {
68 	if (!m_controller->thread() || !m_controller->thread()->core) {
69 		return;
70 	}
71 	const uint16_t* palette;
72 	int count;
73 	switch (m_controller->platform()) {
74 #ifdef M_CORE_GBA
75 	case mPLATFORM_GBA:
76 		palette = static_cast<GBA*>(m_controller->thread()->core->board)->video.palette;
77 		count = 256;
78 		break;
79 #endif
80 #ifdef M_CORE_GB
81 	case mPLATFORM_GB:
82 		palette = static_cast<GB*>(m_controller->thread()->core->board)->video.palette;
83 		count = 32;
84 		break;
85 #endif
86 	default:
87 		return;
88 	}
89 	for (int i = 0; i < count; ++i) {
90 		m_ui.bgGrid->setColor(i, palette[i]);
91 		m_ui.objGrid->setColor(i, palette[i + count]);
92 	}
93 	m_ui.bgGrid->update();
94 	m_ui.objGrid->update();
95 }
96 
selectIndex(int index)97 void PaletteView::selectIndex(int index) {
98 	const uint16_t* palette;
99 	switch (m_controller->platform()) {
100 #ifdef M_CORE_GBA
101 	case mPLATFORM_GBA:
102 		palette = static_cast<GBA*>(m_controller->thread()->core->board)->video.palette;
103 		break;
104 #endif
105 #ifdef M_CORE_GB
106 	case mPLATFORM_GB:
107 		palette = static_cast<GB*>(m_controller->thread()->core->board)->video.palette;
108 		break;
109 #endif
110 	default:
111 		return;
112 	}
113 	uint16_t color = palette[index];
114 	m_ui.selected->setColor(0, color);
115 	uint32_t r = M_R5(color);
116 	uint32_t g = M_G5(color);
117 	uint32_t b = M_B5(color);
118 	uint32_t hexcode = (r << 19) | (g << 11) | (b << 3);
119 	hexcode |= (hexcode >> 5) & 0x070707;
120 	m_ui.hexcode->setText(tr("#%0").arg(hexcode, 6, 16, QChar('0')));
121 	m_ui.value->setText(tr("0x%0").arg(color, 4, 16, QChar('0')));
122 	m_ui.index->setText(tr("0x%0 (%1)").arg(index, 3, 16, QChar('0')).arg(index, 3, 10, QChar('0')));
123 	m_ui.r->setText(tr("0x%0 (%1)").arg(r, 2, 16, QChar('0')).arg(r, 2, 10, QChar('0')));
124 	m_ui.g->setText(tr("0x%0 (%1)").arg(g, 2, 16, QChar('0')).arg(g, 2, 10, QChar('0')));
125 	m_ui.b->setText(tr("0x%0 (%1)").arg(b, 2, 16, QChar('0')).arg(b, 2, 10, QChar('0')));
126 }
127 
exportPalette(int start,int length)128 void PaletteView::exportPalette(int start, int length) {
129 	if (start >= 512) {
130 		return;
131 	}
132 	if (start + length > 512) {
133 		length = 512 - start;
134 	}
135 
136 	CoreController::Interrupter interrupter(m_controller);
137 	QString filename = GBAApp::app()->getSaveFileName(this, tr("Export palette"),
138 	                                                  tr("Windows PAL (*.pal);;Adobe Color Table (*.act)"));
139 	VFile* vf = VFileDevice::open(filename, O_WRONLY | O_CREAT | O_TRUNC);
140 	if (!vf) {
141 		LOG(QT, ERROR) << tr("Failed to open output palette file: %1").arg(filename);
142 		return;
143 	}
144 	if (filename.endsWith(".pal", Qt::CaseInsensitive)) {
145 		exportPaletteRIFF(vf, length, &static_cast<GBA*>(m_controller->thread()->core->board)->video.palette[start]);
146 	} else if (filename.endsWith(".act", Qt::CaseInsensitive)) {
147 		exportPaletteACT(vf, length, &static_cast<GBA*>(m_controller->thread()->core->board)->video.palette[start]);
148 	}
149 	vf->close(vf);
150 }
151