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

// 通知イベント。
// このボタンが押された時にイベントが発生する。
// 引数は wxCommandEvent だが、イベントタイプは EVT_BUTTON ではなく
// NONO_EVT_BUTTON を使用していることが異なる。
wxDEFINE_EVENT(NONO_EVT_BUTTON, wxCommandEvent);

// イベント
wxBEGIN_EVENT_TABLE(WXButton, inherited)
	EVT_SIZE(WXButton::OnSize)
	EVT_MOUSE_EVENTS(WXButton::OnMouse)
	EVT_TIMER(wxID_ANY, WXButton::OnTimer)
wxEND_EVENT_TABLE()

// コンストラクタ
WXButton::WXButton(wxWindow *parent, wxWindowID id,
	const wxSize& size, const wxString& text, const wxPoint& position)
	: inherited(parent, id, position, size)
{
	SetName("Button[" + text + "]");

	// テキストを SJIS に変換し std::string として保存しておく
	wxCSConv conv("SJIS");
	sjistext = text.mb_str(conv);

	timer.SetOwner(this);

	FontChanged();
}

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

bool
WXButton::Enable(bool enable_)
{
	// 無効にするとイベントが来なくなるため、
	// 押し下げた状態で無効にする場合は押し下げを解放してからにする。
	if (enable_ == false && IsPressed()) {
		Press(false);
	}

	return inherited::Enable(enable_);
}

void
WXButton::FontChanged()
{
	inherited::FontChanged();

	// テキスト部分のメトリックはここで決まる。
	textsize.x = sjistext.size() * font_width;
	textsize.y = font_height;

	Fit();

	// テキストサイズが変わったのでキャンバスを一旦破棄。
	Fill();
	Refresh();
}

void
WXButton::Fit()
{
	// 現在のテキストが入る最小サイズを求める。
	// テキストの上下左右 2ピクセルずつがボタン描画用のスペース。
	wxSize minsize(textsize.x + 2 + 2, textsize.y + 2 + 2);

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

	// 最小サイズの影響を受けさせる。
	SetMinSize(minsize);
	wxSize size = GetSize();
	size.x = std::max(size.x, minsize.x);
	size.y = std::max(size.y, minsize.y);
	if (size != GetSize()) {
		SetSize(size);
	}
}

void
WXButton::OnSize(wxSizeEvent& event)
{
	// サイズが変わったらセンタリングを維持。
	const wxSize size = event.GetSize();
	textpos.x = (size.x - textsize.x) / 2;
	textpos.y = (size.y - textsize.y) / 2;

	event.Skip();
}

void
WXButton::OnMouse(wxMouseEvent& event)
{
	if (event.LeftDown() || event.LeftDClick()) {
		// ボタンを押して..
		Press(true);

		// 押しっぱなし判定のためタイマーを開始。
		timer.Start(500);
	}
	if (event.LeftUp()) {
		Press(false);
	}
}

// タイマーイベント
void
WXButton::OnTimer(wxTimerEvent& event)
{
	if (IsPressed()) {
		// 左クリックが続いていたらもう一度
		Press(true);

		// キーリピートと同じ要領で2回目以降は短くする。
		timer.Start(100);
	} else {
		// 左クリックが終わっていたら終了
		timer.Stop();
	}
}

// ボタンを押したか離したときの処理
void
WXButton::Press(bool pressed_)
{
	// 状態が変化すれば再描画
	if (pressed != pressed_) {
		Refresh();
	}

	// 代入
	pressed = pressed_;

	// 状態変化に関わらず、今押していればイベント発行
	if (IsPressed()) {
		wxCommandEvent newev(NONO_EVT_BUTTON, GetId());
		newev.SetEventObject(this);
		AddPendingEvent(newev);
	}
}

void
WXButton::Draw()
{
	// 起きないはずだけど一応。
	if (__predict_false(fixedsize.x < 1 || fixedsize.y < 1)) {
		return;
	}

	// 文字
	Color c = IsEnabled() ? UD_BLACK : UD_GREY;
	DrawStringSJIS(c, textpos.x, textpos.y, sjistext.c_str());

	// ボタンの枠はバックバッファではなく表示枠に合わせて描画する。
	// ただし枠の描画には最低でも 4x4 ピクセルが必要なので、
	// 足りない時は仕方ないのでバックバッファのサイズで描画するか。
	wxSize size = GetSize();
	if (size.x < 4) {
		size.x = fixedsize.x;
	}
	if (size.y < 4) {
		size.y = fixedsize.y;
	}

	int l = 0;
	int t = 0;
	int r = size.x - 1;
	int b = size.y - 1;

	if (__predict_true(IsPressed() == false)) {
		// この場合外寸 7x7、内寸 3x3。
		// 空白「 」のところが内側。
		// 「・」は背景色で塗りつぶす (オンオフ逆側の陰影があるため)
		//
		// □□□□□□■ <- (1)
		// □・・・・灰■ <- (2)
		// □・   灰■
		// □・   灰■
		// □・   灰■
		// □灰灰灰灰灰■ <- (3)
		// ■■■■■■■ <- (4)
		// ^ ^       ^ ^
		//(5)(6)    (7)(8)

		bitmap.DrawLineH(UD_WHITE, l, t, r);				// (1)
		bitmap.DrawLineH(BGPANEL,  l + 1, t + 1, r -1);		// (2)
		bitmap.DrawLineH(UD_GREY,  l + 1, b - 1, r);		// (3)
		bitmap.DrawLineH(UD_BLACK, l, b, r + 1);			// (4)
		bitmap.DrawLineV(UD_WHITE, l, t + 1, b);			// (5)
		bitmap.DrawLineV(BGPANEL,  l + 1, t + 2, b - 1);	// (6)
		bitmap.DrawLineV(UD_GREY,  r - 1, t + 1, b - 1);	// (7)
		bitmap.DrawLineV(UD_BLACK, r, t, b);				// (8)
	} else {
		// ■■■■■■□ <- (1)
		// ■灰灰灰灰灰□ <- (2)
		// ■灰   ・□
		// ■灰   ・□
		// ■灰   ・□
		// ■灰・・・・□ <- (3)
		// □□□□□□□ <- (4)
		// ^ ^       ^ ^
		//(5)(6)    (7)(8)
		bitmap.DrawLineH(UD_BLACK, l, t, r);				// (1)
		bitmap.DrawLineH(UD_GREY,  l + 1, t + 1, r);		// (2)
		bitmap.DrawLineH(BGPANEL,  l + 2, b - 1, r);		// (3)
		bitmap.DrawLineH(UD_WHITE, l, b, r + 1);			// (4)
		bitmap.DrawLineV(UD_BLACK, l, t + 1, b);			// (5)
		bitmap.DrawLineV(UD_GREY,  l + 1, t + 1, b);		// (6)
		bitmap.DrawLineV(BGPANEL,  r - 1, t + 2, b);		// (7)
		bitmap.DrawLineV(UD_WHITE, r, t, b);				// (8)
	}
}

unix.superglobalmegacorp.com

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