--- nono/wx/wxplanemonitor.cpp 2026/04/29 17:05:12 1.1.1.1 +++ nono/wx/wxplanemonitor.cpp 2026/04/29 17:05:44 1.1.1.7 @@ -11,10 +11,19 @@ #include "wxplanemonitor.h" #include "wxcolor.h" #include "wxuimessage.h" -#include "bt454.h" +#include "bt45x.h" +#include "mainapp.h" #include "planevram.h" #include "videoctlr.h" +//#define WINDOW_DEBUG 1 + +#if defined(WINDOW_DEBUG) +#define DPRINTF(fmt...) printf(fmt) +#else +#define DPRINTF(fmt...) /**/ +#endif + enum { ID_PLANE0 = IDGROUP_PLANEVRAM, ID_PLANE1, @@ -37,17 +46,30 @@ static_assert(ID_local_end - 1 <= (int)I // プレーン VRAM ビットマップ // +// イベントテーブル +wxBEGIN_EVENT_TABLE(WXPlaneVRAMBitmapPanel, inherited) + EVT_MOUSE_EVENTS(WXPlaneVRAMBitmapPanel::OnMouse) +wxEND_EVENT_TABLE() + // コンストラクタ WXPlaneVRAMBitmapPanel::WXPlaneVRAMBitmapPanel(wxWindow *parent) : inherited(parent) { - plane_width = gPlaneVRAM->GetComposite().GetWidth(); - plane_height = gPlaneVRAM->GetComposite().GetHeight(); + // デバイスを取得 + planevram = GetPlaneVRAMDevice(); + // どちらか一方は NULL のはず + bt45x = gMainApp.FindObject(OBJ_BT45x); + videoctlr = gMainApp.FindObject(OBJ_VIDEOCTLR); + + plane_width = planevram->GetComposite().GetWidth(); + plane_height = planevram->GetComposite().GetHeight(); // まず等倍でセット scale = 1; SetScale(1); + cursor = wxDefaultPosition; + // VM からの通知を受け取る WXUIMessage::Connect(UIMessage::PALETTE, this, wxCommandEventHandler(WXPlaneVRAMBitmapPanel::OnPaletteChanged)); @@ -56,7 +78,7 @@ WXPlaneVRAMBitmapPanel::WXPlaneVRAMBitma // デストラクタ WXPlaneVRAMBitmapPanel::~WXPlaneVRAMBitmapPanel() { - WXUIMessage::Disconnect(UIMessage::PALETTE, + WXUIMessage::Disconnect(UIMessage::PALETTE, this, wxCommandEventHandler(WXPlaneVRAMBitmapPanel::OnPaletteChanged)); } @@ -70,13 +92,15 @@ WXPlaneVRAMBitmapPanel::Draw() assert(view.GetRight() < virtual_width); assert(view.GetBottom() < virtual_height); - const BitmapI8& src = gPlaneVRAM->GetComposite(); + const BitmapI8& src = planevram->GetComposite(); if (scale > 1) { Rect dr(0, 0, bitmap.GetWidth(), bitmap.GetHeight()); - bitmap.DrawScale(dr, src, &pal[0], view.x, scale, 1, view.y, scale, 1); + bitmap.DrawBitmapI8Scale(dr, src, &pal[0], + view.x, scale, 1, + view.y, scale, 1); } else { - bitmap.DrawBitmap(0, 0, src, &pal[0], view); + bitmap.DrawBitmapI8(0, 0, src, &pal[0], view); } } @@ -118,20 +142,23 @@ WXPlaneVRAMBitmapPanel::GenPalette() { if (apply_palette) { // パレットを適用する場合 - const ColorXBGR *vmpal; - // 雑に X680x0/LUNA 対応 - if (gVideoCtlr) { - vmpal = gVideoCtlr->GetHostPalette(); + // (雑に X680x0/LUNA 対応) + const std::vector *vmpal; + if (videoctlr) { + vmpal = &videoctlr->GetHostPalette(); } else { - vmpal = gBT454->GetHostPalette(); + vmpal = &bt45x->GetHostPalette(); } - const Color bg = vmpal[0].ToColor(); - for (int i = 0; i < pal.size(); i++) { - if ((i & planemask)) { - int n = i % 16; - pal[i] = vmpal[n].ToColor(); + int vmpal_size = vmpal->size(); + const Color bg = (*vmpal)[0]; + int d = 0; + int s; + for (; d < pal.size(); d++) { + s = d % vmpal_size; + if ((s & planemask)) { + pal[d] = (*vmpal)[s]; } else { - pal[i] = bg; + pal[d] = bg; } } } else { @@ -164,7 +191,7 @@ WXPlaneVRAMBitmapPanel::SetScale(int sca view.w = view.w * scale / before; view.h = view.h * scale / before; - SetMaxClientSize(wxSize(virtual_width, virtual_height)); + SetMaxSize(wxSize(virtual_width, virtual_height)); } // スクロール位置変更通知 @@ -181,16 +208,41 @@ WXPlaneVRAMBitmapPanel::OnScroll(wxScrol } } +// マウスイベント +void +WXPlaneVRAMBitmapPanel::OnMouse(wxMouseEvent& event) +{ + auto window = dynamic_cast(GetGrandParent()); + assert(window); + + // pt はこのパネル左上からの位置 + const wxPoint& pt = event.GetPosition(); + + // pt がパネル内の座標なのに Leaving() になることがある。 + // pt がパネル外の座標なのに Leaving() にならないことがある。 + if (event.Leaving() == false && GetClientRect().Contains(pt)) { + // cursor は仮想画面上の座標 + cursor.x = (view.x + pt.x) / scale; + cursor.y = (view.y + pt.y) / scale; + assertmsg(cursor.x < plane_width, "cursor.x=%d", cursor.x); + assertmsg(cursor.y < plane_height, "cursor.y=%d", cursor.y); + } else { + cursor = wxDefaultPosition; + } +} + // // プレーン VRAM パネル // -// イベントテーブル -wxBEGIN_EVENT_TABLE(WXPlaneVRAMPanel, inherited) - EVT_SIZE(WXPlaneVRAMPanel::OnSize) - EVT_TIMER(wxID_ANY, WXPlaneVRAMPanel::OnTimer) -wxEND_EVENT_TABLE() +// +------------------------+------------------+ +// | WXPlaneVRAMBitmapPanel | WXScrollBar(V) | +// | VRAM 表示パネル | 縦スクロールバー | +// +------------------------+------------------+ +// | WXScrollBar(H) | WXBitmapPanel | +// | 横スクロールバー | 空き地 | +// +------------------------+------------------+ // コンストラクタ WXPlaneVRAMPanel::WXPlaneVRAMPanel(wxWindow *parent) @@ -208,13 +260,7 @@ WXPlaneVRAMPanel::WXPlaneVRAMPanel(wxWin // Sizer 使わず自前でレイアウトする。 SetAutoLayout(true); - - // 最小値は適当 - int vscr_width = vscroll->GetClientSize().x; - int hscr_height = hscroll->GetClientSize().y; - SetMinClientSize(wxSize(16 + vscr_width, 16 + hscr_height)); - SetMaxClientSize(wxSize(viewctl->virtual_width + vscr_width, - viewctl->virtual_height + hscr_height)); + FontChanged(); // スクロールバーからの通知イベントは表示パネルへ回す vscroll->Connect(NONO_EVT_SCROLL, @@ -222,9 +268,7 @@ WXPlaneVRAMPanel::WXPlaneVRAMPanel(wxWin hscroll->Connect(NONO_EVT_SCROLL, wxScrollEventHandler(WXPlaneVRAMBitmapPanel::OnScroll), NULL, viewctl); - // 更新タイマーはモニターパネル同様の 30Hz にしておく。 - timer.SetOwner(this); - timer.Start(33); + DPRINTF("Panel.ctor end\n"); } // デストラクタ @@ -232,54 +276,79 @@ WXPlaneVRAMPanel::~WXPlaneVRAMPanel() { } -bool -WXPlaneVRAMPanel::Layout() +// フォントサイズ変更 +void +WXPlaneVRAMPanel::FontChanged() { - if (inherited::Layout() == false) { - return false; - } + // このパネル自体はフォントを出力しないが + // フォントサイズ変更に反応する必要があるため、用意している。 - // コントロールを配置 - const wxSize size = GetClientSize(); - int vscr_width = vscroll->GetClientSize().x; - int hscr_height = hscroll->GetClientSize().y; - int view_width = size.x - vscr_width; - int view_height = size.y - hscr_height; - viewctl->SetSize(0, 0, view_width, view_height); - vscroll->SetSize(view_width, 0, vscr_width, view_height); - hscroll->SetSize(0, view_height, view_width, hscr_height); - corner->SetSize(view_width, view_height, vscr_width, hscr_height); + // 自身がフォントを使わないので呼ばなくてもいいが、お作法として。 + inherited::FontChanged(); + DPRINTF("Panel.FontChanged %d\n", font_height); - // XXX 内部のコントロールのサイズが確定してからでないと DoSize() できない - DoSize(size); + // SubWindow はパネルの FontChanged() までは呼んでくれるけど、 + // パネルが子を持ってるケースは自力で伝搬させるとかする必要がある。 + hscroll->FontChanged(); + vscroll->FontChanged(); - return true; + Fit(); + + DPRINTF("Panel.FontChanged end\n"); } -// サイズ変更イベント void -WXPlaneVRAMPanel::OnSize(wxSizeEvent& event) +WXPlaneVRAMPanel::Fit() { - // Mac ではウィンドウ作成時に 0 以下の値が来ることがある。 - // GTK では 1 で来ることがある。 - wxSize size = event.GetSize(); - if (size.x <= 1 || size.y <= 1) { - return; - } + // 最小/最大サイズを再計算。 + wxSize vmin = vscroll->GetMinSize(); + wxSize hmin = hscroll->GetMinSize(); + wxSize minsize(hmin.x + vmin.x, vmin.y + hmin.y); + wxSize maxsize(viewctl->virtual_width + vmin.x, + viewctl->virtual_height + hmin.y); + SetSizeHints(minsize, maxsize); - // Layout() を呼ぶために必要 - event.Skip(); + // 新しいサイズはビューサイズから決定。 + wxSize viewsize = viewctl->GetSize(); + wxSize newsize(viewsize.x + vmin.x, viewsize.y + hmin.y); + DPRINTF("Panel.Fit (%d,%d) min=(%d,%d) max=(%d,%d)\n", + newsize.x, newsize.y, minsize.x, minsize.y, maxsize.x, maxsize.y); + SetSize(newsize); - // XXX レイアウトが終わった後でないと DoSize() できない -// DoSize(size); + GetParent()->Fit(); +} + +bool +WXPlaneVRAMPanel::Layout() +{ + const wxSize size = GetSize(); + DPRINTF("Panel.Layout size=(%d,%d)\n", size.x, size.y); + wxSize vscr = vscroll->GetSize(); + wxSize hscr = hscroll->GetSize(); + + // コントロールを配置。 + int view_width = size.x - vscr.x; + int view_height = size.y - hscr.y; + DPRINTF("Panel.Layout view=(%d,%d)\n", view_width, view_height); + + viewctl->SetSize(0, 0, view_width, view_height); + vscroll->SetSize(view_width, 0, vscr.x, view_height); + hscroll->SetSize(0, view_height, view_width, hscr.y); + corner->SetSize(view_width, view_height, vscr.x, hscr.y); + + SetScroll(); + DPRINTF("Panel.Layout done\n"); + + return true; } // サイズ変更処理。パネルサイズと倍率が変わったら呼ぶこと。 // 倍率が変わった場合もスクロールバーの再設定とかがあるため。 void -WXPlaneVRAMPanel::DoSize(wxSize size) +WXPlaneVRAMPanel::SetScroll() { - wxSize viewsize = viewctl->GetClientSize(); + wxSize viewsize = viewctl->GetSize(); + DPRINTF("Panel.%s: view=(%d,%d)\n", __func__, viewsize.x, viewsize.y); int virtual_width = viewctl->virtual_width; int virtual_height = viewctl->virtual_height; Rect& view = viewctl->view; @@ -301,7 +370,7 @@ WXPlaneVRAMPanel::DoSize(wxSize size) // 下端も同様 if (view.y > 0 && (view.y + view.h >= virtual_height || - view.y + size.y >= virtual_height)) + view.y + viewsize.y >= virtual_height)) { view.y = virtual_height - viewsize.y; if (view.y < 0) { @@ -327,13 +396,6 @@ WXPlaneVRAMPanel::DoSize(wxSize size) vscroll->SetScrollParam(vpos, vthumbsize, vrange, vpagesize); } -// タイマーイベント -void -WXPlaneVRAMPanel::OnTimer(wxTimerEvent& event) -{ - Refresh(); -} - // プレーン選択変更 void WXPlaneVRAMPanel::EnablePlane(int plane, bool value) @@ -354,12 +416,12 @@ WXPlaneVRAMPanel::SetScale(int scale_) { viewctl->SetScale(scale_); - int vscr_width = vscroll->GetClientSize().x; - int hscr_height = hscroll->GetClientSize().y; - SetMaxClientSize(wxSize(viewctl->virtual_width + vscr_width, + int vscr_width = vscroll->GetSize().x; + int hscr_height = hscroll->GetSize().y; + SetMaxSize(wxSize(viewctl->virtual_width + vscr_width, viewctl->virtual_height + hscr_height)); - DoSize(GetSize()); + SetScroll(); } @@ -367,12 +429,21 @@ WXPlaneVRAMPanel::SetScale(int scale_) // プレーン VRAM ウィンドウ // +// ↓+-----------------------------+ +// | wx コントロール用パネル | +// +-----------------------------+ +// | WXTextScreen *statuspanel | ← 情報欄 +// +-----------------------------+ +// | WXPlaneVRAMPanel *viewpanel | ← ビットマップ (スクロールバー込み) +// +-----------------------------+ + // イベントテーブル wxBEGIN_EVENT_TABLE(WXPlaneVRAMWindow, inherited) EVT_COMMAND_RANGE(ID_PLANE0, ID_PLANE7, wxEVT_CHECKBOX, WXPlaneVRAMWindow::OnPlane) EVT_CHECKBOX(ID_PALETTE, WXPlaneVRAMWindow::OnApplyPalette) EVT_CHOICE(ID_SCALE, WXPlaneVRAMWindow::OnScale) + EVT_TIMER(wxID_ANY, WXPlaneVRAMWindow::OnTimer) wxEND_EVENT_TABLE() // コンストラクタ @@ -380,28 +451,46 @@ WXPlaneVRAMWindow::WXPlaneVRAMWindow(wxW : inherited(parent, wxID_ANY, name, inherited::DEFAULT_STYLE | wxRESIZE_BORDER) { - auto *topsizer = new wxBoxSizer(wxVERTICAL); + // デバイスを取得 + planevram = GetPlaneVRAMDevice(); + + int nplane = planevram->GetPlaneCount(); - // 上にコントロールパネル(のまず下敷き) - ctrlpanel = new WXBitmapPanel(this); - topsizer->Add(ctrlpanel, 0, wxEXPAND); + // 上段、コントロールパネル(のまず下敷き) + ctrlpanel = new wxPanel(this); + ctrlpanel->SetName("WXPlaneVRAMWindow.CtrlPanel"); // コントロールパネル用の横 Sizer auto *ctrlbox = new wxBoxSizer(wxHORIZONTAL); - // プレーン選択チェックボックス (#3, #2, #1, #0 の順に並べる) - for (int i = planesw.size() - 1; i >= 0; i--) { - planesw[i] = new wxCheckBox(ctrlpanel, ID_PLANE(i), - string_format("#%d", i)); - ctrlbox->Add(planesw[i], 0, wxALIGN_CENTER); + // プレーン選択チェックボックス + auto *csbox = new wxStaticBoxSizer(wxHORIZONTAL, ctrlpanel, + _("Planes to display")); + // GTK3 標準のレンダリングだとコントロールの周りの空きがなさすぎて + // 特にスタティックボックスは読みづらいので自力で少し空ける。どうして…。 + ctrlbox->Add(csbox, 0, wxALIGN_CENTER | wxALL, 3); + // X68030 なら 4プレーン。 + // LUNA で 1bpp なら 4プレーン (上位3つは Disabled)、 + // LUNA で 4bpp なら 4プレーン、 + // LUNA で 8bpp なら 8プレーン。 + int nplane4 = (nplane == 1) ? 4 : nplane; + for (int i = 0; i < nplane4; i++) { + auto *ctrl = new wxCheckBox(ctrlpanel, ID_PLANE(i), + string_format("%d", i)); + planesw.push_back(ctrl); + } + // 降順に並べる + for (int i = nplane4 - 1; i >= 0; i--) { + csbox->Add(planesw[i]); } // パレット合成チェックボックス applysw = new wxCheckBox(ctrlpanel, ID_PALETTE, _("Apply palette")); - ctrlbox->Add(applysw, 0, wxALIGN_CENTER); + ctrlbox->Add(applysw, 0, wxALIGN_CENTER | wxALL, 3); // セパレータを出したいのだが… - ctrlbox->Add(new wxStaticText(ctrlpanel, wxID_ANY, "|"), 0, wxALIGN_CENTER); + ctrlbox->Add(new wxStaticText(ctrlpanel, wxID_ANY, "|"), 0, + wxALIGN_CENTER | wxALL, 3); // 倍率 wxString scale_choice[] = { @@ -412,25 +501,33 @@ WXPlaneVRAMWindow::WXPlaneVRAMWindow(wxW scalesw = new wxChoice(ctrlpanel, ID_SCALE, wxDefaultPosition, wxDefaultSize, countof(scale_choice), scale_choice); - ctrlbox->Add(scalesw, 0, wxALIGN_CENTER); + ctrlbox->Add(scalesw, 0, wxALIGN_CENTER | wxALL, 3); // sizer と下敷きパネルを紐付ける ctrlpanel->SetSizer(ctrlbox); ctrlbox->SetSizeHints(ctrlpanel); + // 中段、情報パネルは大きさを固定 + constexpr int status_col = 60; + statuspanel = new WXTextScreen(this, nnSize(status_col, nplane)); + statuspanel->SetMinSize(statuspanel->GetBestSize()); + + // 中段の右側の空き地用。 + spacer = new WXBitmapPanel(this); + + // 下段、表示パネル。 + // 大きさは適当だがフォントサイズを大きくした後で再び小さくすると + // このパネルはどうしたらいいのか難しいのと、最初から広いほうが見やすい + // というのもあるしね…ということにして、とりあえずステータスパネルを + // 最初からフォントサイズ 24 の時の幅にしておいて誤魔化す。高さは適当。 viewpanel = new WXPlaneVRAMPanel(this); - topsizer->Add(viewpanel, 1, wxEXPAND); + viewpanel->SetSize(wxSize(status_col * 12, status_col * 12 / 2)); - SetSizer(topsizer); - - // 最小サイズは上コントロール部の横幅が最小基準 - wxSize minsize = ctrlpanel->GetMinClientSize(); - minsize.y += viewpanel->GetMinClientSize().y; - SetMinClientSize(minsize); - // 最大サイズは DoScale() 内で設定している + SetAutoLayout(true); + FontChanged(); - // 1bpp ならプレーン選択はすべて無効、4bpp ならすべて有効。 - if (gPlaneVRAM->GetPlaneCount() == 1) { + // 1bpp ならプレーン選択はすべて無効、それ以外はすべて有効。 + if (nplane == 1) { for (int i = 0; i < planesw.size(); i++) { planesw[i]->Enable(false); } @@ -445,7 +542,7 @@ WXPlaneVRAMWindow::WXPlaneVRAMWindow(wxW applysw->SetValue(sticky_apply); scalesw->SetSelection(sticky_scale); } else { - if (gPlaneVRAM->GetPlaneCount() == 1) { + if (nplane == 1) { // 初回 1bpp なら #0 プレーンのみオン。 for (int i = 0; i < planesw.size(); i++) { planesw[i]->SetValue((i == 0)); @@ -468,6 +565,12 @@ WXPlaneVRAMWindow::WXPlaneVRAMWindow(wxW } DoApplyPalette(applysw->IsChecked()); DoScale(scalesw->GetSelection()); + + // 更新タイマーはモニターパネル同様の 30Hz にしておく。 + timer.SetOwner(this); + timer.Start(33); + + DPRINTF("Window.ctor end\n"); } // デストラクタ @@ -476,12 +579,118 @@ WXPlaneVRAMWindow::~WXPlaneVRAMWindow() } void -WXPlaneVRAMWindow::FontChanged() +WXPlaneVRAMWindow::Fit() +{ + // 全部準備出来る前に呼ばれることがある。spacer は見ないので不要。 + if (ctrlpanel == NULL || statuspanel == NULL || viewpanel == NULL) { + return; + } + + // 最大最小サイズを設定。 + DoSizeHints(); + + // コントロールからウィンドウサイズを計算。 + const wxSize& ctrlsize = ctrlpanel->GetSize(); + const wxSize& statsize = statuspanel->GetSize(); + const wxSize& viewsize = viewpanel->GetSize(); + + int size_x = ctrlsize.x; + if (size_x < statsize.x) { + size_x = statsize.x; + } + if (size_x < viewsize.x) { + size_x = viewsize.x; + } + wxSize size(size_x, ctrlsize.y + statsize.y + viewsize.y); + DPRINTF("Window.Fit (%d,%d)\n", size.x, size.y); + SetClientSize(size); +} + +void +WXPlaneVRAMWindow::DoSizeHints() +{ + // 最小サイズを再計算。 + const wxSize& ctrlmin = ctrlpanel->GetMinSize(); + const wxSize& statmin = statuspanel->GetMinSize(); + const wxSize& viewmin = viewpanel->GetMinSize(); + DPRINTF("Window.%s ctrlmin=(%d,%d) statmin=(%d,%d) viewmin=(%d,%d)\n", + __func__, + ctrlmin.x, ctrlmin.y, statmin.x, statmin.y, viewmin.x, viewmin.y); + + int minsize_x = ctrlmin.x; + if (minsize_x < statmin.x) { + minsize_x = statmin.x; + } + if (minsize_x < viewmin.x) { + minsize_x = viewmin.x; + } + min_height = ctrlmin.y + statmin.y + viewmin.y; + wxSize minsize(minsize_x, min_height); + + // 最大サイズは viewsize に依存しそうだから手抜き。 + const wxSize& viewmax = viewpanel->GetMaxSize(); + wxSize maxsize(viewmax.x, ctrlmin.y + statmin.y + viewmax.y); + + // 最大最小サイズを再設定。 + DPRINTF("Window.%s min=(%d,%d), max=(%d,%d)\n", __func__, + minsize.x, minsize.y, maxsize.x, maxsize.y); + SetSizeHints(wxDefaultCoord, wxDefaultCoord); + SetSizeHints(ClientToWindowSize(minsize), ClientToWindowSize(maxsize)); +} + +bool +WXPlaneVRAMWindow::Layout() { - // 親 (wxSubWindow) の FontChanged() を実行しないようにするための - // 空のオーバーライド。親の FontChanged() が呼ぶ DoSize() が - // ウィンドウサイズを変更しようとするが、ここはテキストフォントを - // 持っていないのでその操作は不要。うーん。 + // sizer があるので呼ばないといけない。 + bool r = inherited::Layout(); + + // 全部準備出来る前に呼ばれることがある。 + if (ctrlpanel == NULL || statuspanel == NULL || viewpanel == NULL || + spacer == NULL) + { + return r; + } + + wxSize client = GetClientSize(); + DPRINTF("Window.Layout (%d,%d)\n", client.x, client.y); + const wxSize& ctrlsize = ctrlpanel->GetSize(); + const wxSize& statsize = statuspanel->GetSize(); + + // wxmonitor.cpp の Layout() 内のコメント参照。 + wxSize min = GetMinClientSize(); + if (min.y >= min_height) { + // 正常なリサイズなのでこのサイズを覚えておく。 + correct_clientsize = client; + } else { + // 変なリサイズが行われたので、やり直す。 + client = correct_clientsize; + DoSizeHints(); + SetClientSize(client); + + min = GetMinClientSize(); + DPRINTF("Window.%s patch client=(%d,%d) min=(%d,%d)\n", __func__, + client.x, client.y, min.x, min.y); + + // SetClientSize() によってこの場で Layout() が呼ばれて戻ってきた + // はずなので、これ以降はもう処理しなくていい。 + return true; + } + + ctrlpanel->SetSize(0, 0, client.x, ctrlsize.y); + statuspanel->SetSize(0, ctrlsize.y, statsize.x, statsize.y); + viewpanel->SetSize(0, ctrlsize.y + statsize.y, + client.x, client.y - ctrlsize.y - statsize.y); + + // ステータスパネル右に空き地が出来るなら埋める。 + if (statsize.x < client.x) { + spacer->SetSize(statsize.x, ctrlsize.y, + client.x - statsize.x, statsize.y); + spacer->Show(); + } else { + spacer->Hide(); + } + + return true; } // プレーン選択のチェックボックスイベント @@ -543,16 +752,32 @@ WXPlaneVRAMWindow::DoScale(int scale_ind viewpanel->SetScale(1 << scale_index); // 最大サイズは表示部の最大サイズから - wxSize maxsize = viewpanel->GetMaxClientSize(); - maxsize.y += ctrlpanel->GetMinClientSize().y; + wxSize maxsize = viewpanel->GetMaxSize(); + maxsize.y += ctrlpanel->GetMinSize().y; + maxsize.y += statuspanel->GetMinSize().y; SetMaxClientSize(maxsize); // 保存しておくのはインデックスのほう sticky_scale = scale_index; } +// タイマーイベント +void +WXPlaneVRAMWindow::OnTimer(wxTimerEvent& event) +{ + viewpanel->Refresh(); + + // この位置の情報で screen を更新 + TextScreen& screen = statuspanel->GetScreen(); + const wxPoint& cursor = viewpanel->GetCursor(); + + // UpdateInfo() は cursor.x が範囲外の時の描画も行っている。 + planevram->UpdateInfo(screen, cursor.x, cursor.y); + statuspanel->Refresh(); +} + // static 変数 -std::array WXPlaneVRAMWindow::sticky_plane; +std::array WXPlaneVRAMWindow::sticky_plane; bool WXPlaneVRAMWindow::sticky_apply; int WXPlaneVRAMWindow::sticky_scale; bool WXPlaneVRAMWindow::sticky_used;