Qt: Palette viewer
Jeffrey Pfau jeffrey@endrift.com
Sun, 05 Apr 2015 23:46:48 -0700
9 files changed,
548 insertions(+),
0 deletions(-)
M
CHANGES
→
CHANGES
@@ -2,6 +2,7 @@ 0.3.0: (Future)
Features: - Ability to hide individual background layers, or OBJs - Ability to mute individual audio channels + - Palette viewer Bugfixes: - GBA: Fix timers not updating timing when writing to only the reload register - All: Fix sanitize-deb script not cleaning up after itself
M
src/platform/qt/CMakeLists.txt
→
src/platform/qt/CMakeLists.txt
@@ -58,11 +58,13 @@ LoadSaveState.cpp
LogView.cpp MultiplayerController.cpp OverrideView.cpp + PaletteView.cpp SavestateButton.cpp SensorView.cpp SettingsView.cpp ShortcutController.cpp ShortcutView.cpp + Swatch.cpp Window.cpp VFileDevice.cpp VideoView.cpp)@@ -73,6 +75,7 @@ GIFView.ui
LoadSaveState.ui LogView.ui OverrideView.ui + PaletteView.ui SensorView.ui SettingsView.ui ShortcutView.ui
A
src/platform/qt/PaletteView.cpp
@@ -0,0 +1,59 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "PaletteView.h" + +#include <QFontDatabase> + +using namespace QGBA; + +PaletteView::PaletteView(GameController* controller, QWidget* parent) + : QWidget(parent) + , m_controller(controller) +{ + m_ui.setupUi(this); + + connect(m_controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(updatePalette())); + m_ui.bgGrid->setDimensions(QSize(16, 16)); + m_ui.objGrid->setDimensions(QSize(16, 16)); + m_ui.selected->setSize(64); + m_ui.selected->setDimensions(QSize(1, 1)); + updatePalette(); + + const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + + m_ui.hexcode->setFont(font); + m_ui.value->setFont(font); + m_ui.index->setFont(font); + m_ui.r->setFont(font); + m_ui.g->setFont(font); + m_ui.b->setFont(font); + + connect(m_ui.bgGrid, SIGNAL(indexPressed(int)), this, SLOT(selectIndex(int))); + connect(m_ui.objGrid, &Swatch::indexPressed, [this] (int index) { selectIndex(index + 256); }); +} + +void PaletteView::updatePalette() { + const uint16_t* palette = m_controller->thread()->gba->video.palette; + for (int i = 0; i < 256; ++i) { + m_ui.bgGrid->setColor(i, palette[i]); + m_ui.objGrid->setColor(i, palette[i + 256]); + } +} + +void PaletteView::selectIndex(int index) { + uint16_t color = m_controller->thread()->gba->video.palette[index]; + m_ui.selected->setColor(0, color); + uint32_t r = color & 0x1F; + uint32_t g = (color >> 5) & 0x1F; + uint32_t b = (color >> 10) & 0x1F; + uint32_t hexcode = (r << 19) | (g << 11) | (b << 3); + m_ui.hexcode->setText(tr("#%0").arg(hexcode, 6, 16, QChar('0'))); + m_ui.value->setText(tr("0x%0").arg(color, 4, 16, QChar('0'))); + m_ui.index->setText(tr("%0").arg(index, 3, 10, QChar('0'))); + m_ui.r->setText(tr("0x%0 (%1)").arg(r, 2, 16, QChar('0')).arg(r, 2, 10, QChar('0'))); + m_ui.g->setText(tr("0x%0 (%1)").arg(g, 2, 16, QChar('0')).arg(g, 2, 10, QChar('0'))); + m_ui.b->setText(tr("0x%0 (%1)").arg(b, 2, 16, QChar('0')).arg(b, 2, 10, QChar('0'))); +}
A
src/platform/qt/PaletteView.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_PALETTE_VIEW +#define QGBA_PALETTE_VIEW + +#include <QWidget> + +#include "GameController.h" +#include "Swatch.h" + +#include "ui_PaletteView.h" + +class GameController; + +namespace QGBA { + +class Swatch; + +class PaletteView : public QWidget { +Q_OBJECT + +public: + PaletteView(GameController* controller, QWidget* parent = nullptr); + +public slots: + void updatePalette(); + +private slots: + void selectIndex(int); + +private: + Ui::PaletteView m_ui; + + GameController* m_controller; +}; + +} + +#endif
A
src/platform/qt/PaletteView.ui
@@ -0,0 +1,321 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PaletteView</class> + <widget class="QWidget" name="PaletteView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>452</width> + <height>349</height> + </rect> + </property> + <property name="windowTitle"> + <string>Palette</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Background</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGBA::Swatch" name="bgGrid"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>175</width> + <height>175</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Objects</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGBA::Swatch" name="objGrid"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>175</width> + <height>175</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Selection</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QGBA::Swatch" name="selected"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>64</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Red</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Green</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Blue</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <property name="leftMargin"> + <number>8</number> + </property> + <item> + <widget class="QLabel" name="r"> + <property name="text"> + <string>0x00 (00)</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="g"> + <property name="text"> + <string>0x00 (00)</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="b"> + <property name="text"> + <string>0x00 (00)</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>16-bit value</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>Hex code</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Palette index</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="leftMargin"> + <number>8</number> + </property> + <item> + <widget class="QLabel" name="value"> + <property name="text"> + <string>0x0000</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="hexcode"> + <property name="text"> + <string>#000000</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="index"> + <property name="text"> + <string>000</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QGBA::Swatch</class> + <extends>QLabel</extends> + <header>Swatch.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui>
A
src/platform/qt/Swatch.cpp
@@ -0,0 +1,62 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "Swatch.h" + +#include <QMouseEvent> +#include <QPainter> + +using namespace QGBA; + +Swatch::Swatch(QWidget* parent) + : QLabel(parent) +{ + m_size = 10; + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); +} + +void Swatch::setSize(int size) { + m_size = size; + setDimensions(m_dims); +} + +void Swatch::setDimensions(const QSize& size) { + m_dims = size; + m_backing = QPixmap(size * (m_size + 1) - QSize(1, 1)); + m_backing.fill(Qt::transparent); + int elem = size.width() * size.height(); + m_colors.resize(elem); + for (int i = 0; i < elem; ++i) { + updateFill(i); + } +} + +void Swatch::setColor(int index, uint16_t color) { + m_colors[index].setRgb( + (color << 3) & 0xF8, + (color >> 2) & 0xF8, + (color >> 7) & 0xF8); + updateFill(index); +} + +void Swatch::paintEvent(QPaintEvent* event) { + setPixmap(m_backing); + QLabel::paintEvent(event); +} + +void Swatch::mousePressEvent(QMouseEvent* event) { + int x = event->x() / (m_size + 1); + int y = event->y() / (m_size + 1); + emit indexPressed(y * m_dims.width() + x); +} + +void Swatch::updateFill(int index) { + QPainter painter(&m_backing); + int x = index % m_dims.width(); + int y = index / m_dims.width(); + QRect r(x * (m_size + 1), y * (m_size + 1), m_size, m_size); + painter.fillRect(r, m_colors[index]); + update(r); +}
A
src/platform/qt/Swatch.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_SWATCH +#define QGBA_SWATCH + +#include <QColor> +#include <QLabel> +#include <QVector> + +namespace QGBA { + +class Swatch : public QLabel { +Q_OBJECT + +public: + Swatch(QWidget* parent = nullptr); + + void setDimensions(const QSize&); + void setSize(int size); + +public slots: + void setColor(int index, uint16_t); + +signals: + void indexPressed(int index); + +protected: + void paintEvent(QPaintEvent*) override; + void mousePressEvent(QMouseEvent*) override; + +private: + int m_size; + QVector<QColor> m_colors; + QPixmap m_backing; + QSize m_dims; + + void updateFill(int index); +}; + +} + +#endif
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -27,6 +27,7 @@ #include "LoadSaveState.h"
#include "LogView.h" #include "MultiplayerController.h" #include "OverrideView.h" +#include "PaletteView.h" #include "SensorView.h" #include "SettingsView.h" #include "ShortcutController.h"@@ -284,6 +285,11 @@
void Window::openCheatsWindow() { CheatsView* cheatsWindow = new CheatsView(m_controller); openView(cheatsWindow); +} + +void Window::openPaletteWindow() { + PaletteView* paletteWindow = new PaletteView(m_controller); + openView(paletteWindow); } #ifdef BUILD_SDL@@ -872,6 +878,13 @@ QAction* gamepad = new QAction(tr("Remap gamepad..."), toolsMenu);
connect(gamepad, SIGNAL(triggered()), this, SLOT(openGamepadWindow())); addControlledAction(toolsMenu, gamepad, "remapGamepad"); #endif + + toolsMenu->addSeparator(); + + QAction* paletteView = new QAction(tr("View &palette..."), toolsMenu); + connect(paletteView, SIGNAL(triggered()), this, SLOT(openPaletteWindow())); + m_gameActions.append(paletteView); + addControlledAction(toolsMenu, paletteView, "paletteWindow"); ConfigOption* skipBios = m_config->addOption("skipBios"); skipBios->connect([this](const QVariant& value) {
M
src/platform/qt/Window.h
→
src/platform/qt/Window.h
@@ -73,6 +73,8 @@ void openOverrideWindow();
void openSensorWindow(); void openCheatsWindow(); + void openPaletteWindow(); + #ifdef BUILD_SDL void openGamepadWindow(); #endif