--- nono/wx/wxlcdwindow.cpp 2026/04/29 17:04:53 1.1.1.2 +++ nono/wx/wxlcdwindow.cpp 2026/04/29 17:05:16 1.1.1.7 @@ -5,140 +5,118 @@ // // -// LUNA LCD パネル +// LUNA LCD パネル、モニタ // #include "wxlcdwindow.h" -#include "wxbmp.h" #include "wxcolor.h" -#include "wxtextscreen.h" +#include "wxuimessage.h" #include "lcd.h" -// パネルの大きさ (定数) -// N はとりあえずの倍率。 -#define N (2) -#define PANEL_WIDTH ((N) * (5 + 1) * 16 + 1) -#define PANEL_HEIGHT ((N) * (8 + 1) * 2 + 1) - // -// LUNA LCD パネル +// LUNA 前面 LCD パネル // -// イベントテーブル -wxBEGIN_EVENT_TABLE(WXLCDPanel, inherited) - EVT_TIMER(wxID_ANY, WXLCDPanel::OnTimer) - EVT_PAINT(WXLCDPanel::OnPaint) -wxEND_EVENT_TABLE() +// BitmapPanel の継承で十分だが FontChanged() に連動させるため、 +// TextPanel からの継承としている。 +// +// 全体図。横16文字 x 縦2行 +// □ は1キャラクタ分。5x8ピクセル。 +// _ は1ピクセル分のアキ。 +// +// +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +// 横 _□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_ +// _□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_□_ +// +// 1 2 +// 縦 _□_□_ // コンストラクタ WXLCDPanel::WXLCDPanel(wxWindow *parent) - : inherited(parent, wxID_ANY, wxDefaultPosition, - wxSize(PANEL_WIDTH, PANEL_HEIGHT)) + : inherited(parent) { - bitmap.Create(PANEL_WIDTH, PANEL_HEIGHT); + u_width = 5 * 16 + 17; + u_height = 8 * 2 + 3; - count = (uint32)-1; - ddram = gLCD->GetDDRAM(); + lcd = GetLCDDevice(); + ddram = lcd->GetDDRAM(); - // 更新タイマー。そんなに応答速度速くなくていい - timer.SetOwner(this); - timer.Start(50); + // VM からの通知を受け取る + WXUIMessage::Connect(UIMessage::LCD, this, + wxCommandEventHandler(WXLCDPanel::OnLCDChanged)); + + FontChanged(); + SetBitmapBGColor(UD_CREAM); + Fill(); } // デストラクタ WXLCDPanel::~WXLCDPanel() { + WXUIMessage::Disconnect(UIMessage::LCD, this, + wxCommandEventHandler(WXLCDPanel::OnLCDChanged)); } -// タイマーイベント +// フォントサイズ変更通知 void -WXLCDPanel::OnTimer(wxTimerEvent& event) +WXLCDPanel::FontChanged() { - uint32 devcount; + inherited::FontChanged(); - // 更新があれば.. - devcount = gLCD->GetCounter(); - if (count != devcount) { - count = devcount; + // このパネル内の描画の基本単位。 + // 12, 16, 24 を 2, 3, 4 にする。 + unit = (font_height + 5) / 6; - // 再描画を起こす - Refresh(); - } + // コントロールの大きさを変更 + wxSize size(u_width * unit, u_height * unit); + SetClientSize(size); + SetMinClientSize(size); } -// 描画イベント (UI スレッドから呼ばれる) +// LCD 状態変更イベント (UIMessage) void -WXLCDPanel::OnPaint(wxPaintEvent& event) +WXLCDPanel::OnLCDChanged(wxCommandEvent& event) { - // メモリ DC に描画 - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - Draw(memDC); - - // 実画面 DC にコピー - wxPaintDC dstDC(this); - dstDC.Blit(0, 0, PANEL_WIDTH, PANEL_HEIGHT, &memDC, 0, 0); + Refresh(); } // バックグラウンドバッファに描画 void -WXLCDPanel::Draw(wxDC& dc) +WXLCDPanel::Draw() { - // 背景 - dc.SetPen(UD_CREAM); - dc.SetBrush(UD_CREAM); - dc.DrawRectangle(wxPoint(0, 0), bitmap.GetSize()); - for (int y = 0; y < 2; y++) { for (int x = 0; x < 16; x++) { uint8 ch = ddram[0x40 * y + x]; - DrawChar(dc, x, y, ch); + DrawChar(x, y, ch); } } } // 1文字描画 void -WXLCDPanel::DrawChar(wxDC& dc, int x, int y, uint8 ch) +WXLCDPanel::DrawChar(int x, int y, uint8 ch) { - wxSize dotsize = wxSize(N, N); + const Color pal[2] = { UD_YELLOW_GREEN, UD_BROWN }; const uint8 *font; - font = gLCD->GetFont(ch); - - for (int py = 0; py < 8; py++) { - uint8 line = *font++; - line <<= 3; - for (int px = 0; px < 5; px++) { - wxColour color; - if ((int8)line < 0) { - color = UD_BROWN; - } else { - color = UD_YELLOW_GREEN; - } - dc.SetPen(color); - dc.SetBrush(color); - dc.DrawRectangle( - wxPoint((1 + x * 6 + px) * N, (1 + y * 9 + py) * N), - dotsize); + font = lcd->GetFont(ch); + BitmapI1 src(font, 5, 8); - line <<= 1; - } - } + bitmap.DrawScaleUp((1 + x * 6) * unit, (1 + y * 9) * unit, unit, src, pal); } + // -// LCD ウィンドウ +// LUNA 前面 LCD ウィンドウ // // コンストラクタ -WXLCDWindow::WXLCDWindow(wxWindow *parent, wxWindowID id) - : inherited(parent, id, _("Front LCD")) +WXLCDWindow::WXLCDWindow(wxWindow *parent) + : inherited(parent, wxID_ANY, _("Front LCD")) { panel = new WXLCDPanel(this); - // 大きさをそれに固定 - Fit(); + DoSize(); } // デストラクタ @@ -146,23 +124,35 @@ WXLCDWindow::~WXLCDWindow() { } + // -// LCD キャラクタパネル +// モニタの LCD キャラクタ部パネル // -#define CP_WIDTH (N * (1 + 6 * (16 + 1 + 16))) -#define CP_HEIGHT (N * (1 + 9 * 8)) - -// イベントテーブル -wxBEGIN_EVENT_TABLE(WXLCDCharPanel, inherited) - EVT_PAINT(WXLCDCharPanel::OnPaint) -wxEND_EVENT_TABLE() +// 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) { - bitmap.Create(CP_WIDTH, CP_HEIGHT); + lcd = GetLCDDevice(); + + u_width = 5 * 33 + 32; // 横 5px * (32+1)文字、余白が計 32 + u_height = 8 * 8 + 9; // 縦 8px * 8行、余白が計 9 + + FontChanged(); } // デストラクタ @@ -170,30 +160,27 @@ WXLCDCharPanel::~WXLCDCharPanel() { } -// 描画イベント (UI スレッドから呼ばれる) +// フォントサイズ変更通知 void -WXLCDCharPanel::OnPaint(wxPaintEvent& event) +WXLCDCharPanel::FontChanged() { - // メモリ DC に描画 - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - Draw(memDC); - - // 実画面 DC にコピー - wxPaintDC dstDC(this); - dstDC.Blit(0, 0, CP_WIDTH, CP_HEIGHT, &memDC, 0, 0); + inherited::FontChanged(); + + // このパネル内の描画の基本単位。 + // 12, 16, 24 を 2, 3, 4 にする。 + unit = (font_height + 5) / 6; + + // コントロールの大きさを変更 + wxSize size(u_width * unit, u_height * unit); + SetClientSize(size); + SetMinClientSize(size); } // バックグラウンドバッファに描画 void -WXLCDCharPanel::Draw(wxDC& dc) +WXLCDCharPanel::Draw() { - wxSize dotsize = wxSize(N, N); - - // 背景 - dc.SetPen(BGPANEL); - dc.SetBrush(BGPANEL); - dc.DrawRectangle(wxPoint(0, 0), bitmap.GetSize()); + const Color pal[2] = { UD_WHITE, UD_BLACK }; // フォントは 5x8 (最下行はカーソル用に空けてあるので実際は 5x7)。 // 実際には 0xe0 以降には 5x10 フォントが混在しているのだが、その @@ -203,98 +190,57 @@ WXLCDCharPanel::Draw(wxDC& dc) int cx = 1; int cy = 1; for (int ch = 0; ch < 256; ch++) { - const uint8 *font = gLCD->GetFont(ch); - for (int py = 0; py < 8; py++) { - uint8 line = *font++; - line <<= 3; - for (int px = 0; px < 5; px++) { - wxColour color; - if ((int8)line < 0) { - color = *wxBLACK; - } else { - color = *wxWHITE; - } - dc.SetPen(color); - dc.SetBrush(color); - dc.DrawRectangle( - wxPoint((cx + px) * N, (cy + py) * N), - dotsize); - - line <<= 1; - } - } + const uint8 *font = lcd->GetFont(ch); + BitmapI1 src(font, 5, 8); + bitmap.DrawScaleUp(cx * unit, cy * unit, unit, src, pal); 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; } } } } + // // LCD モニタウィンドウ // // コンストラクタ -WXLCDMonitor::WXLCDMonitor(wxWindow *parent, wxWindowID id) - : inherited(parent, id, _("LCD")) +WXLCDMonitor::WXLCDMonitor(wxWindow *parent) + : inherited(parent, wxID_ANY, "LCD (HD44780)") { - // top - // | +--------------------------+ - // v | 上余白 | - // +------+------------+------+ - // |左余白| TextScreen |右余白| - // +------+-----------++------+ - // |左余白| CharPanel | 右余白| - // +------+-----------+-------+ - // | 下余白 | - // +--------------------------+ - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - - // 上余白 - topsizer->Add(new WXPaddingPanel(this), 0, wxEXPAND); - - // 2段目 - wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL); - topsizer->Add(hbox1, 0, wxEXPAND); - - // 2段目の左余白 - hbox1->Add(new WXPaddingPanel(this), 0, wxEXPAND); - - monpanel = new WXTextScreen(this, *gLCD); - hbox1->Add(monpanel, 0, wxEXPAND); - - // 2段目の右余白 - hbox1->Add(new WXPaddingPanel(this), 0, wxEXPAND); - - // 3段目 - wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL); - topsizer->Add(hbox2, 0, wxEXPAND); - - // 3段目の左余白 - hbox2->Add(new WXPaddingPanel(this), 0, wxEXPAND); + // +------------+ + // | 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); - hbox2->Add(chrpanel, 0, wxEXPAND); - - // 3段目の右余白 - // ここの1でこの右余白が空き全部を使用するので空き地が埋まる - hbox2->Add(new WXPaddingPanel(this), 1, wxEXPAND); - - // 下余白 - topsizer->Add(new WXPaddingPanel(this), 0, wxEXPAND); + topsizer->Add(chrpanel, 0, wxEXPAND); SetSizer(topsizer); // 大きさをそれに固定 - Fit(); + SetClientSize(GetSizer()->GetMinSize()); } // デストラクタ