File:  [Isaki's NoNo m68k/m88k emulator] / nono / wx / wxsubwindow.cpp
Revision 1.1.1.11 (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
//

//
// サブウィンドウ
//
// wxWindow::SetSizeHints() の挙動がアレなのに対応するハック付き。

#include "wxsubwindow.h"
#include "fontmanager.h"
#include "wxmainframe.h"
#include "wxtextscreen.h"

//
// サブウィンドウ (基本クラス)
//

//#define WINDOW_DEBUG 1

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

// イベントテーブル
wxBEGIN_EVENT_TABLE(WXSubWindow, inherited)
	EVT_CLOSE(WXSubWindow::OnClose)
wxEND_EVENT_TABLE()

// コンストラクタ
WXSubWindow::WXSubWindow(wxWindow *parent, wxWindowID id, const wxString& name,
	int style)
	: inherited(parent, id, name, wxDefaultPosition, wxDefaultSize, style)
{
}

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

// クローズイベント
void
WXSubWindow::OnClose(wxCloseEvent& event)
{
	// ウィンドウリストから自身を削除
	auto mainframe = dynamic_cast<WXMainFrame*>(GetParent());
	mainframe->DeleteWindow(this);
}

// フォントサイズ変更
void
WXSubWindow::FontChanged()
{
	// WXTextPanel 派生の子コントロールに対し FontChanged() を呼ぶ
	for (auto child : GetChildren()) {
		auto textpanel = dynamic_cast<WXTextPanel*>(child);
		if (textpanel) {
			textpanel->FontChanged();
		}
	}

	Fit();
}

// 自前レイアウト方式を使うことを宣言する。
// ついでに必要な SetAutoLayout() も実行しておく。
// おそらくコンストラクタで使うことになるはず。
void
WXSubWindow::SetMyLayout()
{
	my_layout = true;

	SetAutoLayout(true);
}

// 中身の状況に応じてこのウィンドウの大きさを変更。
//  1) 自前方式か
//  2) このウィンドウに top sizer が指定されているか
//  3) 子コントロールが1つしかないか
// のいずれかの場合に使える。
//
// コントロールが複数あって上記のいずれでもない場合は、コントロールを
// どう配置するのか決定できないので、assert する。
void
WXSubWindow::Fit()
{
	wxSize csize;

	if (my_layout) {
		// 1) 自前方式なら継承先がサイズを知っている。
		csize = DoMySizeHints();
		assert(csize.x > 0);
		assert(csize.y > 0);
	} else {
		auto *topsizer = GetSizer();
		if (topsizer) {
			// 2) Sizer があればそれがサイズを知っている。
			csize = topsizer->ComputeFittingClientSize(this);
		} else {
			// 3) どちらでもない場合、子コントロールが1人なら対応出来る。
			// これはネイティブの Fit() と等価のはず。
			auto& children = GetChildren();
			assert(children.GetCount() == 1);
			auto child = children[0];
			csize = child->GetSize();
		}
	}
	SetClientSize(csize);
}

// サイズが変わった場合に呼ばれて、子コントロールの再配置を行う。
bool
WXSubWindow::Layout()
{
	if (my_layout) {
		return MyLayout();
	} else {
		return inherited::Layout();
	}
}

// 自前方式の時の Layout()。
// 何度か呼び出されて仕事をしないと適切なサイズになってくれないため。
//
// Layout() は何かしたら true を返すので、ここもそれに倣う。
// MyLayout() が何かしたら true を返すので継承側は何もせずに true を返すこと。
// MyLayout() が false を返したら、継承側は子コントロールを配置してよい。
// その場合も呼び出し元には true を返すこと
// つまり、継承側はこうなるはず。
//  bool Children::Layout() {
//    if (MyLayout() == false) {
//      ここで子コントロールを配置。
//    }
//    return true;
//  }
bool
WXSubWindow::MyLayout()
{
	wxSize client = GetClientSize();
	const wxSize& win = GetSize();
	const wxSize& border = win - client;

	if (border != prev_border) {
		// ウィンドウマネージャ管轄のサイズが変わったので最小サイズを再設定。
		my_layout_pass2 = true;
		prev_border = border;
		// ここでは出来ないのでこの関数を抜けた後 CallAfter 内で設定する。
		CallAfter([this]() {
			DoMySizeHints();
		});
		return true;

	} else if (my_layout_pass2) {
		// SetSizeHints() 後に呼ばれるところ。
		// なぜか設定したサイズと変わっている(ことがある?)ので、その場合は
		// 仕方ないのでここで元の要求サイズに再設定する。
		// ウィンドウマネージャによっては表示サイズが変わらない(?)ので
		// Hide()/Show() で叩き起こすと直るようだ??。
		my_layout_pass2 = false;
		DPRINTF("%s ClientSize(%d,%d)->", __method__, client.x, client.y);
		GetMySizeHints(&client, NULL, NULL, NULL);
		DPRINTF("(%d,%d)\n", client.x, client.y);
		SetClientSize(client);

		Hide();
		Show();

		DPRINTF("%s done(pass2)\n", __method__);
		return true;
	}

	// ここまで来るとようやくコントロールを再配置を継承側で行える。
	// それを示すため false を返す。
	// wxTopLevelWindow::Layout() は何かすれば true、
	// sizer がないか子コントロールが複数あって何も出来ることがない場合は
	// false を返すと書いてあるので都合よく借りておく。
	DPRINTF("%s done false\n", __method__);
	return false;
}

// SetSizeHints() を実行して、希望するクライアントサイズを返す。
// 自前方式に対応していない場合は何もせず wxDefaultSize を返す。
wxSize
WXSubWindow::DoMySizeHints()
{
	wxSize newsize;
	wxSize minsize;
	wxSize maxsize;
	wxSize incsize;

	if (GetMySizeHints(&newsize, &minsize, &maxsize, &incsize)) {
		wxSize minwin = ClientToWindowSize(minsize);
		wxSize maxwin = ClientToWindowSize(maxsize);
		SetSizeHints(minwin, maxwin, incsize);
		return newsize;
	} else {
		// 対応していない。
		return wxDefaultSize;
	}
}

// 自前方式のサイズに関する情報を取得する。
// 継承先で用意すること。ここにあるのは継承しなかった時の何もしない版。
//
// 継承側はそれぞれ以下の値を書き戻して true を返す。
// *newsz は希望するクライアントサイズ。子コントロールの配置とサイズで決まる。
// *minsz は最小クライアントサイズ。指定しないなら (-1, -1)。
// *maxsz は最大クライアントサイズ。指定しないなら (-1, -1)。
// *incsz はウィンドウサイズ変更時の増減サイズ。
// newsz, minsz, maxsz, incsz はいずれも NULL でなければ代入する。
bool
WXSubWindow::GetMySizeHints(wxSize *newsz, wxSize *minsz, wxSize *maxsz,
	wxSize *incsz)
{
	return false;
}

unix.superglobalmegacorp.com

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