--- nono/wx/wxlcdwindow.cpp 2026/04/29 17:05:12 1.1.1.6 +++ nono/wx/wxlcdwindow.cpp 2026/04/29 17:05:58 1.1.1.11 @@ -5,44 +5,79 @@ // // -// LUNA LCD パネル +// LUNA LCD パネル、モニタ // #include "wxlcdwindow.h" -#include "wxcolor.h" #include "wxuimessage.h" #include "lcd.h" +#include "monitor.h" -// パネルの大きさ (定数) -// N はとりあえずの倍率。 -#define N (2) -#define PANEL_WIDTH ((N) * (5 + 1) * 16 + 1) -#define PANEL_HEIGHT ((N) * (8 + 1) * 2 + 1) +// +// LUNA 前面 LCD パネル +// +// BitmapPanel の継承で十分だが FontChanged() に連動させるため、 +// TextPanel からの継承としている。 +// +// 全体図。横16文字 x 縦2行 +// □ は1キャラクタ分。5x8ピクセル。 +// _ は1ピクセル分のアキ。 // -// LUNA LCD パネル +// +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +// 横 _□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_ +// _□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_ // +// 1 2 +// 縦 _□_□_ // コンストラクタ WXLCDPanel::WXLCDPanel(wxWindow *parent) - : inherited(parent, wxSize(PANEL_WIDTH, PANEL_HEIGHT)) + : inherited(parent) { - ddram = gLCD->GetDDRAM(); + SetName("LCDPanel"); + + u_width = 5 * 16 + 17; + u_height = 8 * 2 + 3; + + lcd = GetLCDDevice(); + ddram = lcd->GetDDRAM(); // VM からの通知を受け取る WXUIMessage::Connect(UIMessage::LCD, this, wxCommandEventHandler(WXLCDPanel::OnLCDChanged)); + FontChanged(); SetBitmapBGColor(UD_CREAM); + Fill(); } // デストラクタ WXLCDPanel::~WXLCDPanel() { - WXUIMessage::Disconnect(UIMessage::LCD, + WXUIMessage::Disconnect(UIMessage::LCD, this, wxCommandEventHandler(WXLCDPanel::OnLCDChanged)); } +// フォントサイズ変更通知 +void +WXLCDPanel::FontChanged() +{ + inherited::FontChanged(); + + // このパネル内の描画の基本単位。 + // 12, 16, 24 を 2, 3, 4 にする。 + unit = (font_height + 5) / 6; + wxSize size(u_width * unit, u_height * unit); + + // バックバッファのサイズを固定。 + SetMinBitmapSize(size); + + // コントロールの大きさを変更。 + SetSize(size); + SetMinSize(size); +} + // LCD 状態変更イベント (UIMessage) void WXLCDPanel::OnLCDChanged(wxCommandEvent& event) @@ -69,24 +104,25 @@ WXLCDPanel::DrawChar(int x, int y, uint8 const Color pal[2] = { UD_YELLOW_GREEN, UD_BROWN }; const uint8 *font; - font = gLCD->GetFont(ch); + font = lcd->GetFont(ch); BitmapI1 src(font, 5, 8); - bitmap.DrawScaleUp((1 + x * 6) * N, (1 + y * 9) * N, N, src, pal); + int dx = (1 + x * 6) * unit; + int dy = (1 + y * 9) * unit; + bitmap.DrawBitmapI1Scale(dx, dy, src, pal, unit); } // -// LCD ウィンドウ +// LUNA 前面 LCD ウィンドウ // // コンストラクタ WXLCDWindow::WXLCDWindow(wxWindow *parent) : inherited(parent, wxID_ANY, _("Front LCD")) { - panel = new WXLCDPanel(this); - - DoSize(); + new WXLCDPanel(this); + Fit(); } // デストラクタ @@ -96,17 +132,35 @@ WXLCDWindow::~WXLCDWindow() // -// LCD キャラクタパネル +// モニタの LCD キャラクタ部パネル // -#define PAD (1) -#define CP_WIDTH (N * (PAD + 6 * (16 + 1 + 16) + PAD)) -#define CP_HEIGHT (N * (PAD + 9 * 8 + PAD)) +// BitmapPanel の継承で十分だが FontChanged() に連動させるため、 +// TextPanel からの継承としている。 +// +// 全体図。横16文字 + 横16文字の2段組。 +// □ は1キャラクタ分。5x8ピクセル。 +// _ は1ピクセル分のアキ。 +// +// 余白 +// +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0 +1 +f +// 横 _□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_□□□_□ … □_ +// +// 00 10 20 30 40 50 60 70 +// 縦 _□_□_□_□_□_□_□_□_ // コンストラクタ WXLCDCharPanel::WXLCDCharPanel(wxWindow *parent) - : inherited(parent, wxSize(CP_WIDTH, CP_HEIGHT)) + : inherited(parent) { + SetName("LCDCharPanel"); + + lcd = GetLCDDevice(); + + u_width = 5 * 33 + 32; // 横 5px * (32+1)文字、余白が計 32 + u_height = 8 * 8 + 9; // 縦 8px * 8行、余白が計 9 + + FontChanged(); } // デストラクタ @@ -114,6 +168,25 @@ WXLCDCharPanel::~WXLCDCharPanel() { } +// フォントサイズ変更通知 +void +WXLCDCharPanel::FontChanged() +{ + inherited::FontChanged(); + + // このパネル内の描画の基本単位。 + // 12, 16, 24 を 2, 3, 4 にする。 + unit = (font_height + 5) / 6; + wxSize size(u_width * unit, u_height * unit); + + // バックバッファのサイズを固定。 + SetMinBitmapSize(size); + + // コントロールの大きさを変更。 + SetSize(size); + SetMinSize(size); +} + // バックグラウンドバッファに描画 void WXLCDCharPanel::Draw() @@ -125,22 +198,25 @@ WXLCDCharPanel::Draw() // モードはサポートしていないので今の所全部 5x8 としてある。 // cx, cy はこの文字の左上座標 (スケール前) - int cx = PAD; - int cy = PAD; + int cx = 1; + int cy = 1; for (int ch = 0; ch < 256; ch++) { - const uint8 *font = gLCD->GetFont(ch); + const uint8 *font = lcd->GetFont(ch); BitmapI1 src(font, 5, 8); - bitmap.DrawScaleUp(cx * N, cy * N, N, src, pal); + bitmap.DrawBitmapI1Scale(cx * unit, cy * unit, src, pal, unit); cx += 6; if (ch % 16 == 15) { - // 行折り返し - cx -= 6 * 16; - cy += 9; - // 0x80 以降は右側に作る if (ch == 127) { - cx += 6 * (16 + 1/*中央の余白*/); + // 0x80 以降は右側に作る。 + // 余白も含めた 6px ずつ加算してきたが中間のアキは計 5px + // なので、過剰分の 1 引く必要がある。 + cx += 5 - 1; cy = 1; + } else { + // 行折り返し + cx -= 6 * 16; + cy += 9; } } } @@ -153,32 +229,72 @@ WXLCDCharPanel::Draw() // コンストラクタ WXLCDMonitor::WXLCDMonitor(wxWindow *parent) - : inherited(parent, wxID_ANY, _("LCD")) + : inherited(parent, wxID_ANY, "LCD (HD44780)") { // +------------+ // | TextScreen | // +------------+ // | CharPanel | // +------------+ - auto *topsizer = new wxBoxSizer(wxVERTICAL); // 上段、テキストスクリーン monpanel = new WXMonitorPanel(this, gMonitorManager->Get(ID_MONITOR_LCD)); // 下辺は CharPanel の上余白が隣接しているため、自分のほうは付けない。 monpanel->SetPadding(-1, -1, -1, 0); - topsizer->Add(monpanel, 0, wxEXPAND); // 下段、キャラクタパネル chrpanel = new WXLCDCharPanel(this); - topsizer->Add(chrpanel, 0, wxEXPAND); - SetSizer(topsizer); + // 空き地用。 + space = new WXBitmapPanel(this); - // 大きさをそれに固定 - SetClientSize(GetSizer()->GetMinSize()); + SetAutoLayout(true); + FontChanged(); } // デストラクタ WXLCDMonitor::~WXLCDMonitor() { } + +void +WXLCDMonitor::FontChanged() +{ + monpanel->FontChanged(); + chrpanel->FontChanged(); + + const wxSize& monsize = monpanel->GetSize(); + const wxSize& chrsize = chrpanel->GetSize(); + wxSize size(std::max(monsize.x, chrsize.x), monsize.y + chrsize.y); + SetClientSize(size); +} + +bool +WXLCDMonitor::Layout() +{ + // inherited::Layout() は(実質何もしないので)、呼ばずに自力で行う。 + + wxSize client = GetClientSize(); + const wxSize& monsize = monpanel->GetSize(); + const wxSize& chrsize = chrpanel->GetSize(); + + // コントロールを配置。 + monpanel->SetSize(0, 0, monsize.x, monsize.y); + chrpanel->SetSize(0, monsize.y, chrsize.x, chrsize.y); + + // monpanel と chrpanel はフォントサイズによる拡大倍率が違うため + // フォントサイズを変更した時に相似にならず、現状では必ずどちらかが + // 大きい (がどちらかは固定されない) という状態になる。 + // そこで小さい方のコントロールの右に空き地が出来てしまう。そのままだと + // GTK3 のウィンドウ下地色が見えてしまうため、BGPANEL 色のパネルを敷く。 + + if (monsize.x < chrsize.x) { + // 上が小さいので、右上に空き地を置く。 + space->SetSize(monsize.x, 0, client.x - monsize.x, monsize.y); + } else { + // 下が小さいので、左下に空き地を置く。 + space->SetSize(chrsize.x, monsize.y, client.x - chrsize.x, chrsize.y); + } + + return true; +}