File:  [Isaki's NoNo m68k/m88k emulator] / nono / wx / wxtvrammonitor.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:48 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, HEAD
nono 1.5.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// TVRAM モニタ (LUNA ではビットマップモニタ)
//

#include "wxtvrammonitor.h"
#include "wxuimessage.h"
#include "wxtextscreen.h"
#include "bt45x.h"
#include "mainapp.h"
#include "planevram.h"
#include "videoctlr.h"

enum {
	ID_PLANE0 = IDGROUP_TVRAM,
	ID_PLANE1,
	ID_PLANE2,
	ID_PLANE3,
	ID_PLANE4,
	ID_PLANE5,
	ID_PLANE6,
	ID_PLANE7,
	ID_PALETTE,
	ID_SCALE,

	ID_local_end,	// 最後に置く (チェック用)
};
static_assert(ID_local_end - 1 <= (int)IDGROUP_TVRAM_END, "ID exceeded");

#define ID_PLANE(id)	(ID_PLANE0 + (id))

//
// テキスト画面パネル (LUNA だとビットマップ画面パネル)
//

// コンストラクタ
WXTVRAMPanel::WXTVRAMPanel(wxWindow *parent)
	: inherited(parent)
{
	// デバイスを取得。
	planevram = GetPlaneVRAMDevice();
	// どちらか一方は NULL のはず。
	bt45x = gMainApp.FindObject<BT45xDevice>(OBJ_BT45x);
	videoctlr = gMainApp.FindObject<VideoCtlrDevice>(OBJ_VIDEOCTLR);

	// サイズを取得して、コンストラクタの続き。
	const auto& composite = planevram->GetComposite();
	Ctor(composite.GetWidth(), composite.GetHeight());

	// VM からの通知を受け取る。
	WXUIMessage::Connect(UIMessage::PALETTE, this,
		wxCommandEventHandler(WXTVRAMPanel::OnPaletteChanged));
}

// デストラクタ
WXTVRAMPanel::~WXTVRAMPanel()
{
	WXUIMessage::Disconnect(UIMessage::PALETTE, this,
		wxCommandEventHandler(WXTVRAMPanel::OnPaletteChanged));
}

// XXX 実際にはこの辺かどこかで更新チェックをしないといけない。
// 今は表示領域を毎回描画しているので無駄。

// ビットマッププレーンの内容を描画する
void
WXTVRAMPanel::Draw()
{
	assert(view.GetRight()  < virtual_width);
	assert(view.GetBottom() < virtual_height);

	const BitmapI8& src = planevram->GetComposite();

	if (scale > 1) {
		Rect dr(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
		bitmap.DrawBitmapI8Scale(dr, src, &pal[0],
			view.x, scale, 1,
			view.y, scale, 1);
	} else {
		bitmap.DrawBitmapI8(0, 0, src, &pal[0], view);
	}
}

// プレーン選択変更
void
WXTVRAMPanel::EnablePlane(int plane, bool value)
{
	if (value) {
		planemask |= 1U << plane;
	} else {
		planemask &= ~(1U << plane);
	}

	// パレット生成
	GenPalette();
}

// パレット適用変更
void
WXTVRAMPanel::EnablePalette(bool value)
{
	apply_palette = value;

	// パレット生成
	GenPalette();
}

// VM からのパレット変更通知
void
WXTVRAMPanel::OnPaletteChanged(wxCommandEvent& event)
{
	// パレット生成
	GenPalette();
}

// パレット生成
void
WXTVRAMPanel::GenPalette()
{
	if (apply_palette) {
		// パレットを適用する場合
		// (雑に X680x0/LUNA 対応)
		const Color *vmpal;
		uint vmpal_size;
		if (videoctlr) {
			vmpal = videoctlr->GetHostPalettePtr(256);
			vmpal_size = 16;
		} else {
			const std::vector<Color>& vec = bt45x->GetHostPalette();
			vmpal = &vec[0];
			vmpal_size = vec.size();
		}
		const Color bg = vmpal[0];
		for (uint d = 0; d < pal.size(); d++) {
			uint s = d % vmpal_size;
			if ((s & planemask)) {
				pal[d] = vmpal[s];
			} else {
				pal[d] = bg;
			}
		}
	} else {
		// パレットを適用しない場合
		for (uint i = 0; i < pal.size(); i++) {
			if ((i & planemask)) {
				pal[i] = Color(255, 255, 255);
			} else {
				pal[i] = Color(0, 0, 0);
			}
		}
	}
}


//
// テキスト画面ウィンドウ
//

// イベントテーブル
wxBEGIN_EVENT_TABLE(WXTVRAMWindow, inherited)
	EVT_COMMAND_RANGE(ID_PLANE0, ID_PLANE7, wxEVT_CHECKBOX,
		WXTVRAMWindow::OnPlane)
	EVT_CHECKBOX(ID_PALETTE, WXTVRAMWindow::OnApplyPalette)
	EVT_CHOICE(ID_SCALE, WXTVRAMWindow::OnScale)
wxEND_EVENT_TABLE()

// コンストラクタ
WXTVRAMWindow::WXTVRAMWindow(wxWindow *parent, const wxString& name)
	: inherited(parent, name)
{
	// デバイスを取得
	planevram = GetPlaneVRAMDevice();

	int nplane = planevram->GetPlaneCount();

	// コントロールパネル用の横 Sizer
	auto *ctrlbox = new wxBoxSizer(wxHORIZONTAL);

	// プレーン選択チェックボックス
	auto *csbox = new wxStaticBoxSizer(wxHORIZONTAL, ctrlpanel,
		_("Planes to display"));
	// GTK3 標準のレンダリングだとコントロールの周りの空きがなさすぎて
	// 特にスタティックボックスは読みづらいので自力で少し空ける。どうして…。
	ctrlbox->Add(csbox, 0, wxALIGN_CENTER | wxALL, 3);
	// X68030 なら 4プレーン。
	// LUNA で 1bpp なら 4プレーン (上位3つは Disabled)、
	// LUNA で 4bpp なら 4プレーン、
	// LUNA で 8bpp なら 8プレーン。
	std::vector<wxCheckBox*> planesw {};
	int nplane4 = (nplane == 1) ? 4 : nplane;
	for (int i = 0; i < nplane4; i++) {
		auto *ctrl = new wxCheckBox(ctrlpanel, ID_PLANE(i),
			string_format("%d", i));
		planesw.push_back(ctrl);
	}
	// 降順に並べる
	for (int i = nplane4 - 1; i >= 0; i--) {
		csbox->Add(planesw[i]);
	}

	// パレット合成チェックボックス
	auto applysw = new wxCheckBox(ctrlpanel, ID_PALETTE, _("Apply palette"));
	ctrlbox->Add(applysw, 0, wxALIGN_CENTER | wxALL, 3);

	// セパレータを出したいのだが…
	ctrlbox->Add(new wxStaticText(ctrlpanel, wxID_ANY, "|"), 0,
		wxALIGN_CENTER | wxALL, 3);

	// 倍率
	wxString scale_choice[] = {
		"x1",
		"x2",
		"x4",
	};
	auto scalesw = new wxChoice(ctrlpanel, ID_SCALE,
		wxDefaultPosition, wxDefaultSize,
		countof(scale_choice), scale_choice);
	ctrlbox->Add(scalesw, 0, wxALIGN_CENTER | wxALL, 3);

	// sizer と下敷きパネルを紐付ける
	ctrlpanel->SetSizer(ctrlbox);
	ctrlbox->SetSizeHints(ctrlpanel);

	// 情報パネル。
	constexpr int status_col = 60;
	statuspanel = new WXTextScreen(this, nnSize(status_col, nplane));
	statuspanel->SetMinSize(statuspanel->GetBestSize());

	// 表示パネル。
	// 大きさは適当だがフォントサイズを大きくした後で再び小さくすると
	// このパネルはどうしたらいいのか難しいのと、最初から広いほうが見やすい
	// というのもあるしね…ということにして、とりあえずステータスパネルを
	// 最初からフォントサイズ 24 の時の幅にしておいて誤魔化す。高さは適当。
	viewpanel = new WXTVRAMPanel(this);
	viewpanel->SetSize(wxSize(status_col * 12, status_col * 12 / 2));

	// コンストラクタの続き。
	Ctor();

	// 1bpp ならプレーン選択はすべて無効、それ以外はすべて有効。
	if (nplane == 1) {
		for (int i = 0; i < planesw.size(); i++) {
			planesw[i]->Enable(false);
		}
	}

	// 初期値をコントロールにセットする
	if (nplane == 1) {
		// 初回 1bpp なら #0 プレーンのみオン。
		for (int i = 0; i < planesw.size(); i++) {
			planesw[i]->SetValue((i == 0));
		}
		applysw->SetValue(true);
	} else {
		// 初回 4bpp なら全プレーンオン。
		for (int i = 0; i < planesw.size(); i++) {
			planesw[i]->SetValue(true);
		}
		applysw->SetValue(true);
	}
	scalesw->SetSelection(0);

	// SetValue() ではイベントが飛ばないので、
	// 直接呼び出してイベントが来たことにする。うーん…。
	for (int i = 0; i < planesw.size(); i++) {
		DoPlane(i, planesw[i]->IsChecked());
	}
	DoApplyPalette(applysw->IsChecked());
	DoScale(scalesw->GetSelection());
}

// デストラクタ
WXTVRAMWindow::~WXTVRAMWindow()
{
}

// プレーン選択のチェックボックスイベント
void
WXTVRAMWindow::OnPlane(wxCommandEvent& event)
{
	int plane = event.GetId() - ID_PLANE0;
	bool value = event.IsChecked();

	DoPlane(plane, value);
}

// プレーン選択 ON/OFF 処理
void
WXTVRAMWindow::DoPlane(int plane, bool value)
{
	// コントロールに指示
	auto textviewpanel = dynamic_cast<WXTVRAMPanel *>(viewpanel);
	textviewpanel->EnablePlane(plane, value);
}

// パレット合成のチェックボックスイベント
void
WXTVRAMWindow::OnApplyPalette(wxCommandEvent& event)
{
	bool value = event.IsChecked();

	DoApplyPalette(value);
}

// パレット合成 ON/OFF 処理
void
WXTVRAMWindow::DoApplyPalette(bool value)
{
	// コントロールに指示
	auto textviewpanel = dynamic_cast<WXTVRAMPanel *>(viewpanel);
	textviewpanel->EnablePalette(value);
}

// 情報パネル更新。
void
WXTVRAMWindow::UpdateInfo(TextScreen& screen, int x, int y)
{
	planevram->UpdateInfo(screen, x, y);
}

unix.superglobalmegacorp.com

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