File:  [Isaki's NoNo m68k/m88k emulator] / nono / wx / wxlogsetting.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 "wxlogsetting.h"
#include "wxbutton.h"
#include "wxtextscreen.h"
#include "mainapp.h"
#include <algorithm>

//
// パネル部分
//

enum {
	ID_BUTTON0 = IDGROUP_LOGSETTING,
	ID_local_end = ID_BUTTON0 + 100 * 2,	// 適当
};
static_assert(ID_local_end - 1 <= (int)IDGROUP_LOGSETTING_END, "ID exceeded");

// コンストラクタ
WXLogSettingPanel::WXLogSettingPanel(wxWindow *parent)
	: inherited(parent)
{
	SetName("LogSettingPanel");

	// エイリアスを持つオブジェクトだけ抜き出す
	for (const auto obj : gMainApp.GetObjects()) {
		if (obj->GetAliases().empty() == false) {
			objs.emplace_back(obj);
		}
	}

	// ログ名でソート。
	// ただし普通にソートすると "(BusErr)" とかの括弧付きがアルファベット
	// より上に来てしまうが、ここではこれらは重要ではないので下にしたい。
	std::sort(objs.begin(), objs.end(), [](Object *a, Object *b) {
		std::string aname = a->GetName();
		std::string bname = b->GetName();
		if (aname[0] == '(') {
			aname[0] = '{';
		}
		if (bname[0] == '(') {
			bname[0] = '{';
		}
		return aname < bname;
	});

	// 名前の最大長
	maxnamelen = 0;
	for (const auto obj : objs) {
		maxnamelen = std::max(maxnamelen, (int)obj->GetName().length());
	}

	// ボタンを用意
	int nbuttons = objs.size() * 2;
	assertmsg(ID_BUTTON0 + nbuttons < ID_local_end, "nbuttons=%d", nbuttons);
	for (int i = 0; i < nbuttons; i++) {
		auto btn = new WXButton(this, ID_BUTTON0 + i, wxDefaultSize,
			(i % 2 == 0 ? "<" : ">"));
		buttons.push_back(btn);

		// イベントを接続
		btn->Bind(NONO_EVT_BUTTON, &WXLogSettingPanel::OnButton, this);
	}

	// Sizer 使わず自前でレイアウトする。
	SetAutoLayout(true);
	FontChanged();
}

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

// 桁数 col の左端ピクセル座標を返す
inline int
WXLogSettingPanel::Col2PX(int col) const
{
	return col * GetFontWidth() + Padding;
}

// 行数 row の上端ピクセル座標を返す
inline int
WXLogSettingPanel::Row2PY(int row) const
{
	// 縦はボタン描画の分少し広げてある
	return row * (GetFontHeight() + 4) + Padding;
}

// フォントサイズ変更
void
WXLogSettingPanel::FontChanged()
{
	inherited::FontChanged();

	// 子コントロールに伝搬。
	for (auto *btn : buttons) {
		btn->FontChanged();
	}

	Fit();
}

void
WXLogSettingPanel::Fit()
{
	// 行数×桁数を基本とする
	int col = maxnamelen + 10;
	int row = objs.size() + 1;
	wxSize size(Col2PX(col) + Padding, Row2PY(row) + Padding);

	// バックバッファのサイズを固定。
	SetMinBitmapSize(size);

	SetSize(size);
}

bool
WXLogSettingPanel::Layout()
{
	// ボタンを再配置。
	wxSize btnsize(GetFontWidth() * 2 + 4, GetFontHeight() + 4);
	for (int i = 0, end = buttons.size(); i < end; i++) {
		int x;
		if (i % 2 == 0) {
			x = Col2PX(maxnamelen + 1) + 2;
		} else {
			x = Col2PX(maxnamelen + 8) - 2;
		}
		int y = Row2PY((i / 2) + 1);
		buttons[i]->SetSize(x - 2, y - 2, btnsize.x, btnsize.y);
	}

	return true;
}

// 描画本体
void
WXLogSettingPanel::Draw()
{
	const int width  = GetFontWidth();
	const int height = GetFontHeight();
	int row;
	int y;

	// ヘッダ
	y = Row2PY(0);
	DrawStringSJIS(Col2PX(0), y, "Name");
	DrawStringSJIS(Col2PX(maxnamelen + 1), y, "LogLevel");

	row = 1;
	for (const auto obj : objs) {
		Rect rect;
		Color c;

		y = Row2PY(row);

		// 名前
		DrawStringSJIS(Col2PX(0), y, obj->GetName().c_str());

		// 値
		char lvstr[2];
		if (__predict_false(obj->loglevel < 0)) {
			lvstr[0] = '-';
		} else if (__predict_true(obj->loglevel < 10)) {
			lvstr[0] = obj->loglevel + '0';
		} else {
			lvstr[0] = '?';
		}
		lvstr[1] = '\0';
		DrawStringSJIS(Col2PX(maxnamelen + 5), y, lvstr);

		// 値の枠
		int x = Col2PX(maxnamelen + 4);
		rect = Rect(x, y - 1, width * 3, height + 1);
		int l = rect.x;
		int t = rect.y;
		int r = rect.GetRight();
		int b = rect.GetBottom();
		bitmap.DrawLineH(UD_GREY,  l, t, r);
		bitmap.DrawLineH(UD_WHITE, l, b, r + 1);
		bitmap.DrawLineV(UD_GREY,  l, t + 1, b);
		bitmap.DrawLineV(UD_WHITE, r, t, b);

		// ボタンは Layout() で配置してある

		row++;
	}
}

void
WXLogSettingPanel::OnButton(wxCommandEvent& event)
{
	int n = event.GetId() - ID_BUTTON0;	// ボタン番号
	int idx = n / 2;					// オブジェクト番号
	bool isdown = (n % 2 == 0);			// "<" なら true

	Object *obj = objs[idx];
	int level = obj->loglevel;

	if (isdown) {
		if (level > -1) {
			level--;
		}
	} else {
		// 今の所上限は未定だけど、表示上の都合で一桁にしておくか
		if (level < 9) {
			level++;
		}
	}

	if (level != obj->loglevel) {
		obj->SetLogLevel(level);

		// レベルが上下端ならボタンを無効に、そうでなければ有効にする
		int down;
		int up;
		if (isdown) {
			down = n;
			up = n + 1;
		} else {
			down = n - 1;
			up = n;
		}
		buttons[down]->Enable((level > -1));
		buttons[up]->Enable((level < 9));

		Refresh();
	}
}


//
// ウィンドウ
//

// コンストラクタ
WXLogSettingWindow::WXLogSettingWindow(wxWindow *parent)
	: inherited(parent, wxID_ANY, _("Log Level Setting"))
{
	new WXLogSettingPanel(this);
	Fit();
}

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

unix.superglobalmegacorp.com

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