File:  [Isaki's NoNo m68k/m88k emulator] / nono / wx / wxpalettemonitor.cpp
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:58 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
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()
{
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.