--- nono/wx/wxlcdwindow.cpp 2026/04/29 17:04:39 1.1 +++ nono/wx/wxlcdwindow.cpp 2026/04/29 17:05:09 1.1.1.5 @@ -11,6 +11,7 @@ #include "wxlcdwindow.h" #include "wxcolor.h" #include "wxtextscreen.h" +#include "wxuimessage.h" #include "lcd.h" // パネルの大きさ (定数) @@ -23,128 +24,70 @@ // LUNA LCD パネル // -// イベントテーブル -wxBEGIN_EVENT_TABLE(WXLCDPanel, inherited) - EVT_TIMER(wxID_ANY, WXLCDPanel::OnTimer) - EVT_PAINT(WXLCDPanel::OnPaint) -wxEND_EVENT_TABLE() - // コンストラクタ WXLCDPanel::WXLCDPanel(wxWindow *parent) - : inherited(parent, wxID_ANY, wxDefaultPosition, - wxSize(PANEL_WIDTH, PANEL_HEIGHT)) + : inherited(parent, wxSize(PANEL_WIDTH, PANEL_HEIGHT)) { - 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); + // VM からの通知を受け取る + WXUIMessage::Connect(UIMessage::LCD, this, + wxCommandEventHandler(WXLCDPanel::OnLCDChanged)); + + SetBitmapBGColor(UD_CREAM); } // デストラクタ WXLCDPanel::~WXLCDPanel() { - bitmap.reset(); - image.reset(); - bmpbuf.reset(); -} - -// タイマーイベント -void -WXLCDPanel::OnTimer(wxTimerEvent& event) -{ - uint32 devcount; - - // 更新があれば.. - devcount = gLCD->GetCounter(); - if (count != devcount) { - count = devcount; - - // 再描画を起こす - Refresh(); - } + WXUIMessage::Disconnect(UIMessage::LCD, + wxCommandEventHandler(WXLCDPanel::OnLCDChanged)); } -// 描画イベント (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); + BitmapI1 src(font, 5, 8); - 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); - - line <<= 1; - } - } + bitmap.DrawScaleUp((1 + x * 6) * N, (1 + y * 9) * N, N, src, pal); } + // // 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 +95,88 @@ WXLCDWindow::~WXLCDWindow() { } + // // 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() +#define PAD (1) +#define CP_WIDTH (N * (PAD + 6 * (16 + 1 + 16) + PAD)) +#define CP_HEIGHT (N * (PAD + 9 * 8 + PAD)) // コンストラクタ WXLCDCharPanel::WXLCDCharPanel(wxWindow *parent) - : inherited(parent, wxID_ANY, wxDefaultPosition, - wxSize(CP_WIDTH, CP_HEIGHT)) + : inherited(parent, wxSize(CP_WIDTH, CP_HEIGHT)) { - 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)); } // デストラクタ WXLCDCharPanel::~WXLCDCharPanel() { - bitmap.reset(); - image.reset(); - bmpbuf.reset(); -} - -// 描画イベント (UI スレッドから呼ばれる) -void -WXLCDCharPanel::OnPaint(wxPaintEvent& event) -{ - // メモリ DC に描画 - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - Draw(memDC); - - // 実画面 DC にコピー - wxPaintDC dstDC(this); - dstDC.Blit(0, 0, CP_WIDTH, CP_HEIGHT, &memDC, 0, 0); } // バックグラウンドバッファに描画 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; + // cx, cy はこの文字の左上座標 (スケール前) + int cx = PAD; + int cy = PAD; + 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); + BitmapI1 src(font, 5, 8); + bitmap.DrawScaleUp(cx * N, cy * N, N, src, pal); - line <<= 1; + cx += 6; + if (ch % 16 == 15) { + // 行折り返し + cx -= 6 * 16; + cy += 9; + // 0x80 以降は右側に作る + if (ch == 127) { + cx += 6 * (16 + 1/*中央の余白*/); + cy = 1; } } } } + // // LCD モニタウィンドウ // // コンストラクタ -WXLCDMonitor::WXLCDMonitor(wxWindow *parent, wxWindowID id) - : inherited(parent, id, _("LCD")) +WXLCDMonitor::WXLCDMonitor(wxWindow *parent) + : inherited(parent, wxID_ANY, _("LCD")) { - 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 WXTextScreen(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()); } // デストラクタ