--- nono/wx/wxlcdwindow.cpp 2026/04/29 17:04:39 1.1.1.1 +++ nono/wx/wxlcdwindow.cpp 2026/04/29 17:05:31 1.1.1.9 @@ -5,146 +5,121 @@ // // -// LUNA LCD パネル +// LUNA LCD パネル、モニタ // #include "wxlcdwindow.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) +#include "monitor.h" // -// 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) { - bmpbuf.reset(new uint8 [PANEL_WIDTH * PANEL_HEIGHT * 3]); - memset(&bmpbuf[0], 0x70, PANEL_WIDTH * PANEL_HEIGHT * 3); - image.reset(new wxImage(PANEL_WIDTH, PANEL_HEIGHT, bmpbuf.get(), true)); - bitmap.reset(new wxBitmap(*image)); - - count = (uint32)-1; - ddram = gLCD->GetDDRAM(); - - // 更新タイマー。そんなに応答速度速くなくていい - timer.SetOwner(this); - timer.Start(50); + 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() { - bitmap.reset(); - image.reset(); - bmpbuf.reset(); + 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), wxSize(PANEL_WIDTH, PANEL_HEIGHT)); - 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; - } - } + 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, wxWindowID id) - : inherited(parent, id, _("Front LCD")) +WXLCDWindow::WXLCDWindow(wxWindow *parent) + : inherited(parent, wxID_ANY, _("Front LCD")) { panel = new WXLCDPanel(this); - // 大きさをそれに固定 - Layout(); - Fit(); + DoSize(); } // デストラクタ @@ -152,116 +127,123 @@ WXLCDWindow::~WXLCDWindow() { } + // -// LCD キャラクタパネル +// モニタの LCD キャラクタ部パネル // -#define CP_WIDTH (N * (1 + 6 * 16)) -#define CP_HEIGHT (N * (1 + 9 * 16)) - -// イベントテーブル -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, wxID_ANY, wxDefaultPosition, - wxSize(CP_WIDTH, CP_HEIGHT)) + : inherited(parent) { - bmpbuf.reset(new uint8 [CP_WIDTH * CP_HEIGHT * 3]); - memset(&bmpbuf[0], 0x70, CP_WIDTH * CP_HEIGHT * 3); - image.reset(new wxImage(CP_WIDTH, CP_HEIGHT, bmpbuf.get(), true)); - bitmap.reset(new wxBitmap(*image)); + lcd = GetLCDDevice(); + + u_width = 5 * 33 + 32; // 横 5px * (32+1)文字、余白が計 32 + u_height = 8 * 8 + 9; // 縦 8px * 8行、余白が計 9 + + FontChanged(); } // デストラクタ WXLCDCharPanel::~WXLCDCharPanel() { - bitmap.reset(); - image.reset(); - bmpbuf.reset(); } -// 描画イベント (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); - - // 背景 - // XXX LIGHT_GREY を textscreen と共用すること - dc.SetPen(*wxLIGHT_GREY); - dc.SetBrush(*wxLIGHT_GREY); - dc.DrawRectangle(wxPoint(0, 0), wxSize(CP_WIDTH, CP_HEIGHT)); + const Color pal[2] = { UD_WHITE, UD_BLACK }; // フォントは 5x8 (最下行はカーソル用に空けてあるので実際は 5x7)。 // 実際には 0xe0 以降には 5x10 フォントが混在しているのだが、その // モードはサポートしていないので今の所全部 5x8 としてある。 - for (int ch = 0; ch < 256; ch++) { - // この文字の左上座標 (スケール前) - int cx = 1 + (ch % 16) * 6; - int cy = 1 + (ch / 16) * 9; - - 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; + // cx, cy はこの文字の左上座標 (スケール前) + int cx = 1; + int cy = 1; + for (int ch = 0; ch < 256; ch++) { + const uint8 *font = lcd->GetFont(ch); + BitmapI1 src(font, 5, 8); + bitmap.DrawBitmapI1Scale(cx * unit, cy * unit, src, pal, unit); + + cx += 6; + if (ch % 16 == 15) { + if (ch == 127) { + // 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)") { - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - - monpanel = new WXTextScreen(this, *gLCD); - topsizer->Add(monpanel, 0, wxEXPAND | wxALL, DefaultPadding); + // +------------+ + // | 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 | wxRIGHT | wxLEFT | wxBOTTOM, - DefaultPadding); + topsizer->Add(chrpanel, 0, wxEXPAND); SetSizer(topsizer); // 大きさをそれに固定 - Layout(); - Fit(); + SetClientSize(GetSizer()->GetMinSize()); } // デストラクタ