|
|
nono 1.7.0
//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//
//
// パレットモニターウィンドウ
//
#include "wxpalettemonitor.h"
#include "wxtextscreen.h"
#include "wxuimessage.h"
#include "bt45x.h"
#include "mainapp.h"
#include "videoctlr.h"
//
// パレットビットマップ
//
//
// 情報欄は WXTextScreen 同様に上下と左に DefaultPadding を手動で入れてある。
//
//
// +------------ DefaultPadding (情報欄の左側)
// |
// +-|------
// | v <- DefaultPadding (情報欄の上側)
// | "Text"
// | <- DefaultPadding (情報欄の下側、パレット欄の区切り)
// | "+0 +1 …"
// |-------- <- pal_y0 (ここから以下がパレット領域)
// | □‥
// : :
// | □‥
// | <- DefaultPadding (パレットの下側)
// +-^-------^
// | |
// +-------+---- DefaultPadding (パレットの左右)
//
// パレット欄は1マスが横 font_height (= font_width * 2)、縦 font_height [px]
// で、マスの右端と左端の1ピクセルを BGPANEL 色にして罫線にする。
// Bt454 は 16 色なので 16色 x 1行。
// Bt458 は 256 色なので 16色 x 16行。
// X68030 は 512 色なので 16色 x 16行 x 2列組。
// イベントテーブル
wxBEGIN_EVENT_TABLE(WXPalettePanel, inherited)
EVT_MOUSE_EVENTS(WXPalettePanel::OnMouse)
wxEND_EVENT_TABLE()
// コンストラクタ
WXPalettePanel::WXPalettePanel(wxWindow *parent)
: inherited(parent)
{
SetName("PalettePanel");
// デバイスを取得
bt45x = gMainApp.FindObject<BT45xDevice>(OBJ_BT45x);
videoctlr = gMainApp.FindObject<VideoCtlrDevice>(OBJ_VIDEOCTLR);
cursor = -1;
// パレットは1行に16個で、行数 (1 or 16) が可変。
// ここではサイズだけ確定させる。
const std::vector<Color> *hpal;
if (videoctlr) {
hpal = &videoctlr->GetHostPalette();
rows = 16;
idxlen = 3;
} else {
hpal = &bt45x->GetHostPalette();
rows = hpal->size() / 16;
idxlen = (rows == 1) ? 1 : 2;
}
FontChanged();
PaletteChanged();
// VM からの通知を受け取る
WXUIMessage::Connect(UIMessage::PALETTE, this,
wxCommandEventHandler(WXPalettePanel::OnPaletteChanged));
}
// デストラクタ
WXPalettePanel::~WXPalettePanel()
{
WXUIMessage::Disconnect(UIMessage::PALETTE, this,
wxCommandEventHandler(WXPalettePanel::OnPaletteChanged));
}
void
WXPalettePanel::FontChanged()
{
inherited::FontChanged();
pal0x = WXTextScreen::DefaultPadding; // 左余白
pal0x += font_width * 4; // "$00:"
pal0y = WXTextScreen::DefaultPadding; // 上余白
pal0y += font_height * 2; // テキスト
pal0y += WXTextScreen::DefaultPadding; // テキストとパレットの境界余白
pal0y += font_height; // ヘッダ("+0+1"…)
if (videoctlr) {
pal1x = pal0x + 17 * font_height;
pal0y += font_height; // Text/Graphic の表示
}
wxSize size;
size.x = pal0x; // パレットより左全部
size.x += 16 * font_height; // パレット部
if (videoctlr) {
size.x += 17 * font_height; // X68030 なら2列組。
}
size.x += WXTextScreen::DefaultPadding; // 右余白
size.y = pal0y; // パレットより上全部
size.y += rows * font_height; // パレット部
size.y += WXTextScreen::DefaultPadding; // 下余白
// バックバッファのサイズを固定。
SetMinBitmapSize(size);
SetSize(size);
SetMinSize(size);
}
// VM からのパレット変更通知
void
WXPalettePanel::OnPaletteChanged(wxCommandEvent& event)
{
PaletteChanged();
}
void
WXPalettePanel::PaletteChanged()
{
// ホスト/ゲストパレットをここでコピー。
if (videoctlr) {
pal = videoctlr->GetHostPalette();
vcpal = videoctlr->GetGuestPalette();
} else {
pal = bt45x->GetHostPalette();
btpal = bt45x->GetGuestPalette();
}
Refresh();
}
void
WXPalettePanel::Draw()
{
bitmap.Fill(BGPANEL);
// Bt454 (2 or 16色)
// 01234567
// [$0] Guest
// Host
//
// Bt458 (256色)
// 01234567
// [$00] Guest
// Host
//
// X68030 (512色)
// 01234567
// [$000] Guest
// Host
// テキスト (2行)
// XXX snprintf が色々うるさくてアレ…
char text1[36 + 1 + 40];
char text2[36 + 1];
if (cursor < 0) {
strlcpy(text1, "[ Guest", sizeof(text1));
text1[idxlen + 2] = ']';
strlcpy(text2, "Host R: G: B:", sizeof(text2));
} else {
// この位置のパレット情報を取得
if (videoctlr) {
// X68030 のパレットは %GGGGG'RRRRR'BBBBB'I の16ビット。
assert(cursor <= 0x1ff);
uint c = vcpal[cursor];
uint r = (c >> 6) & 0x1f;
uint g = (c >> 11) & 0x1f;
uint b = (c >> 1) & 0x1f;
uint i = c & 1;
snprintf(text1, sizeof(text1),
"[$%03x] Guest $%04x R:%02x G:%02x B:%02x I:%u",
cursor, c, r, g, b, i);
} else {
if (rows == 1) {
// Bt454 のパレットは $RR, $GG, $BB の3バイト。
// ただし上位4ビットと下位4ビットは同じにしてある。
assert(cursor <= 0xf);
const uint8 *c = &btpal[cursor * 3];
uint r = c[0] >> 4;
uint g = c[1] >> 4;
uint b = c[2] >> 4;
snprintf(text1, sizeof(text1),
"[$%x] Guest R:%x G:%x B:%x", cursor, r, g, b);
} else {
// Bt458 のパレットは $RR, $GG, $BB の3バイトで各8ビット。
assert(cursor <= 0xff);
const uint8 *c = &btpal[cursor * 3];
uint r = c[0];
uint g = c[1];
uint b = c[2];
snprintf(text1, sizeof(text1),
"[$%02x] Guest R:%02x G:%02x B:%02x", cursor, r, g, b);
}
}
snprintf(text2, sizeof(text2), "Host R:%02x G:%02x B:%02x",
pal[cursor].r,
pal[cursor].g,
pal[cursor].b);
}
const int padding = WXTextScreen::DefaultPadding;
DrawStringSJIS(padding, padding, text1);
DrawStringSJIS(padding + font_width * 7, padding + font_height, text2);
// ヘッダ
static const char xlabel[] = "+0+1+2+3+4+5+6+7+8+9+a+b+c+d+e+f";
DrawStringSJIS(pal0x, pal0y - font_height, xlabel);
for (int y = 0; y < rows; y++) {
char buf[8];
__assume(y < 16); // XXX snprintf 対策。うーん
snprintf(buf, sizeof(buf), "$%02x:", y * 16);
DrawStringSJIS(padding, pal0y + y * font_height, buf);
}
// パレット
Rect rect(0, 0, font_height - 1, font_height - 1);
for (int y = 0; y < rows; y++) {
for (int x = 0; x < 16; x++) {
int cc = y * 16 + x;
rect.x = pal0x + x * font_height;
rect.y = pal0y + y * font_height;
bitmap.FillRect(pal[cc], rect);
}
}
if (videoctlr) {
DrawStringSJIS(pal0x, pal0y - font_height * 2, "Graphic Palette");
DrawStringSJIS(pal1x, pal0y - font_height * 2,
"Text/Sprite/BG Palette");
DrawStringSJIS(pal1x, pal0y - font_height, xlabel);
uint cc = 256;
rect.y = pal0y;
for (uint y = 0; y < rows; y++) {
rect.x = pal1x;
for (uint x = 0; x < 16; x++) {
bitmap.FillRect(pal[cc++], rect);
rect.x += font_height;
}
rect.y += font_height;
}
}
}
void
WXPalettePanel::OnMouse(wxMouseEvent& event)
{
wxPoint pt = event.GetPosition();
int new_cursor = -1;
// pt がパネル内の座標なのに Leaving() になることがある。
// pt がパネル外の座標なのに Leaving() にならないことがある。
if (event.Leaving() == false && GetClientRect().Contains(pt)) {
// マウスカーソルがパネル上にある
int y = pt.y - pal0y;
if (y < 0) {
goto next;
}
y /= font_height;
if (y >= rows) {
goto next;
}
int x;
if (pal0x <= pt.x && pt.x < pal0x + font_height * 16) {
x = (pt.x - pal0x) / font_height;
} else if (pal1x != 0) {
// X68030 の右段
if (pal1x <= pt.x && pt.x < pal1x + font_height * 16) {
x = (pt.x - pal1x) / font_height;
y += 16;
} else {
goto next;
}
} else {
goto next;
}
new_cursor = y * 16 + x;
}
next:
if (new_cursor != cursor) {
cursor = new_cursor;
Refresh();
}
}
//
// パレットウィンドウ
//
// コンストラクタ
WXPaletteWindow::WXPaletteWindow(wxWindow *parent, const wxString& name)
: inherited(parent, wxID_ANY, name)
{
new WXPalettePanel(this);
Fit();
}
// デストラクタ
WXPaletteWindow::~WXPaletteWindow()
{
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.