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

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

//
// ログモニター
//

#include "wxlogmonitor.h"
#include "logger.h"
#include "mainapp.h"
#include "monitor.h"
#include "sjis.h"

//#define WINDOW_DEBUG 1

#if defined(WINDOW_DEBUG)
#define DPRINTF(fmt...) printf(fmt)
#else
#define DPRINTF(fmt...) /**/
#endif

// コンストラクタ
WXLogMonitor::WXLogMonitor(wxWindow *parent)
	: inherited(parent, wxID_ANY, _("Log"), DEFAULT_STYLE | wxRESIZE_BORDER)
{
	DPRINTF("%s begin\n", __method__);

	// +-----------------+---------+
	// | LogMonitorPanel | VScroll |
	// +-----------------+---------+

	// モニタ
	logger = gMainApp.GetLogger();
	screen = new LogMonitorPanel(this, logger->GetMonitor());

	// スクロールバー
	vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL);

	// 自前レイアウト。
	SetMyLayout();

	// ウィンドウサイズを確定させる
	FontChanged();

	// スクロールのために (パネル領域での) MouseWheel イベントもここで
	// 受け取りたい。スクロールバー上のマウスホイール操作はスクロールバーが
	// 処理しているので問題ないが、パネル領域でのマウスホイール操作はここ
	// (wxFrame)ではなくパネルに対して飛んでくる。
	// ここで一緒に処理したほうが楽なので、こちらに回す。
	screen->Bind(wxEVT_MOUSEWHEEL, &WXLogMonitor::OnMouseWheel, this);

	// スクロールバーからの位置変更通知イベントは表示パネルへ回す。
	vscroll->Bind(NONO_EVT_SCROLL, &WXLogMonitor::OnScroll, this);

	// XXX ログウィンドウのコピーはまだ動いてない
	screen->DisconnectContextMenu();
	DPRINTF("%s done\n", __method__);
}

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

void
WXLogMonitor::FontChanged()
{
	screen->FontChanged();
	vscroll->FontChanged();
	DPRINTF("%s %d\n", __method__, screen->GetFontHeight());

	Fit();
}

// 自前レイアウト方式のサイズに関する情報を返す。
bool
WXLogMonitor::GetMySizeHints(wxSize *newp, wxSize *minp, wxSize *maxp,
	wxSize *incp)
{
	auto ssize = screen->GetSize();
	auto vsize = vscroll->GetSize();

	int x = ssize.x + vsize.x;
	int min_y = std::max(vscroll->GetMinSize().y, screen->GetScreenHeight(1));
	int new_y = std::max(ssize.y, min_y);
	wxSize newsize(x, new_y);
	wxSize minsize(x, min_y);
	wxSize maxsize(x, GetMaxClientSize().y);
	wxSize incsize(0, screen->GetFontHeight());

	if (newp) *newp = newsize;
	if (minp) *minp = minsize;
	if (maxp) *maxp = maxsize;
	if (incp) *incp = incsize;
	return true;
}

bool
WXLogMonitor::Layout()
{
	if (MyLayout() == false) {
		// コントロールを配置。
		wxSize client = GetClientSize();
		const wxSize vsize = vscroll->GetSize();

		int panel_width  = client.x - vsize.x;
		int panel_height = client.y;
		// 最低でも 1px ないと GTK とかに怒られる。今は起きないはず?
		if (__predict_false(panel_width < 1)) {
			panel_width = 1;
		}
		if (__predict_false(panel_height < 1)) {
			panel_height = 1;
		}

		screen->SetSize(0, 0, panel_width, panel_height);
		vscroll->SetSize(panel_width, 0, vsize.x, panel_height);

		// スクロールバーを再設定
		SetScroll();
	}
	return true;
}

// スクロールバーを再設定
void
WXLogMonitor::SetScroll()
{
	int displines;
	int row;
	int pos;
	int thumbsize;
	int range;
	int pagesize;

	displines = logger->GetDispLines();
	row = screen->GetRow();

	if (displines <= row) {
		pos = 0;
		range = row;
	} else {
		pos = (displines - row) - screen->GetUserData();
		range = displines;
	}
	thumbsize = row;
	pagesize = thumbsize - 1;
	vscroll->SetScrollParam(pos, thumbsize, range, pagesize);
}

// マウスホイールイベント (WXTextScreen 上で起きたやつをこっちに回してある)
void
WXLogMonitor::OnMouseWheel(wxMouseEvent& event)
{
	// GetWheelRotation() は上(奥)向きに回すと +120、下(手前)に回すと -120。
	// どこの決まりか知らんけど、スクロールバーのほうはホイール1段階で3行
	// スクロールするのでそれに合わせる。
	int pos = vscroll->GetThumbPosition();
	pos = pos - event.GetWheelRotation() / 40;

	int maxpos = vscroll->GetRange() - vscroll->GetThumbSize();
	if (pos < 0)
		pos = 0;
	if (pos > maxpos)
		pos = maxpos;

	DoScroll(pos);
	// スクロールバーの位置を追従
	vscroll->SetThumbPosition(pos);
}

// スクロールバーからの通知イベント
void
WXLogMonitor::OnScroll(wxScrollEvent& event)
{
	DoScroll(event.GetPosition());
}

// スクロール処理 (OnScroll() と OnMouseWheel() から呼ばれる)
void
WXLogMonitor::DoScroll(int pos)
{
	// pos 即ちスクロールバーの Thumb の位置は上端の位置。
	// 対してログウィンドウでは下端を基準にしたほうが処理しやすい。
	// userdata = 0 だと Thumb が下に接していてパネルの最下行が最新行、
	// userdata = 1 だと Thumb が下から1段階分上にありパネルの最下行は
	// 最新行の一つ前の行、となる。
	//
	// Range=6		Range=6
	// Pos=4		Pos=0
	// ThumbSz=2	ThumbSz=2
	// userdata=0	userdata=4
	// △			△
	// □			■
	// □			■
	// □			□
	// □			□
	// ■			□
	// ■			□
	// ▽			▽

	// パネル最下行に表示する行の最新行からのオフセット
	// (0 なら Thumb が下端に接している)
	int vpos = vscroll->GetRange() - vscroll->GetThumbSize() - pos;
	screen->SetUserData(vpos);
}


//
// モニターオブジェクト
//

// コンストラクタ
LogMonitorPanel::LogMonitorPanel(WXLogMonitor *parent_, Monitor *monitor_)
	: inherited(parent_, monitor_)
{
	parent = parent_;
}

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

void
LogMonitorPanel::DoRefresh()
{
	inherited::DoRefresh();

	// スクロールバーを再設定。
	parent->SetScroll();
}

unix.superglobalmegacorp.com

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