|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2020 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // プレーン VRAM モニターウィンドウ ! 9: // ! 10: ! 11: #include "wxplanemonitor.h" ! 12: #include "wxcolor.h" ! 13: #include "wxuimessage.h" ! 14: #include "bt454.h" ! 15: #include "planevram.h" ! 16: #include "videoctlr.h" ! 17: ! 18: enum { ! 19: ID_PLANE0 = IDGROUP_PLANEVRAM, ! 20: ID_PLANE1, ! 21: ID_PLANE2, ! 22: ID_PLANE3, ! 23: ID_PLANE4, ! 24: ID_PLANE5, ! 25: ID_PLANE6, ! 26: ID_PLANE7, ! 27: ID_PALETTE, ! 28: ID_SCALE, ! 29: ! 30: ID_local_end, // 最後に置く (チェック用) ! 31: }; ! 32: static_assert(ID_local_end - 1 <= (int)IDGROUP_PLANEVRAM_END, "ID exceeded"); ! 33: ! 34: #define ID_PLANE(id) (ID_PLANE0 + (id)) ! 35: ! 36: // ! 37: // プレーン VRAM ビットマップ ! 38: // ! 39: ! 40: // コンストラクタ ! 41: WXPlaneVRAMBitmapPanel::WXPlaneVRAMBitmapPanel(wxWindow *parent) ! 42: : inherited(parent) ! 43: { ! 44: plane_width = gPlaneVRAM->GetComposite().GetWidth(); ! 45: plane_height = gPlaneVRAM->GetComposite().GetHeight(); ! 46: ! 47: // まず等倍でセット ! 48: scale = 1; ! 49: SetScale(1); ! 50: ! 51: // VM からの通知を受け取る ! 52: WXUIMessage::Connect(UIMessage::PALETTE, this, ! 53: wxCommandEventHandler(WXPlaneVRAMBitmapPanel::OnPaletteChanged)); ! 54: } ! 55: ! 56: // デストラクタ ! 57: WXPlaneVRAMBitmapPanel::~WXPlaneVRAMBitmapPanel() ! 58: { ! 59: WXUIMessage::Disconnect(UIMessage::PALETTE, ! 60: wxCommandEventHandler(WXPlaneVRAMBitmapPanel::OnPaletteChanged)); ! 61: } ! 62: ! 63: // XXX 実際にはこの辺かどこかで更新チェックをしないといけない。 ! 64: // 今は表示領域を毎回描画しているので無駄。 ! 65: ! 66: // ビットマッププレーンの内容を描画する ! 67: void ! 68: WXPlaneVRAMBitmapPanel::Draw() ! 69: { ! 70: assert(view.GetRight() < virtual_width); ! 71: assert(view.GetBottom() < virtual_height); ! 72: ! 73: const BitmapI8& src = gPlaneVRAM->GetComposite(); ! 74: ! 75: if (scale > 1) { ! 76: Rect dr(0, 0, bitmap.GetWidth(), bitmap.GetHeight()); ! 77: bitmap.DrawScale(dr, src, &pal[0], view.x, scale, 1, view.y, scale, 1); ! 78: } else { ! 79: bitmap.DrawBitmap(0, 0, src, &pal[0], view); ! 80: } ! 81: } ! 82: ! 83: // プレーン選択変更 ! 84: void ! 85: WXPlaneVRAMBitmapPanel::EnablePlane(int plane, bool value) ! 86: { ! 87: if (value) { ! 88: planemask |= 1U << plane; ! 89: } else { ! 90: planemask &= ~(1U << plane); ! 91: } ! 92: ! 93: // パレット生成 ! 94: GenPalette(); ! 95: } ! 96: ! 97: // パレット適用変更 ! 98: void ! 99: WXPlaneVRAMBitmapPanel::EnablePalette(bool value) ! 100: { ! 101: apply_palette = value; ! 102: ! 103: // パレット生成 ! 104: GenPalette(); ! 105: } ! 106: ! 107: // VM からのパレット変更通知 ! 108: void ! 109: WXPlaneVRAMBitmapPanel::OnPaletteChanged(wxCommandEvent& event) ! 110: { ! 111: // パレット生成 ! 112: GenPalette(); ! 113: } ! 114: ! 115: // パレット生成 ! 116: void ! 117: WXPlaneVRAMBitmapPanel::GenPalette() ! 118: { ! 119: if (apply_palette) { ! 120: // パレットを適用する場合 ! 121: const ColorXBGR *vmpal; ! 122: // 雑に X680x0/LUNA 対応 ! 123: if (gVideoCtlr) { ! 124: vmpal = gVideoCtlr->GetHostPalette(); ! 125: } else { ! 126: vmpal = gBT454->GetHostPalette(); ! 127: } ! 128: const Color bg = vmpal[0].ToColor(); ! 129: for (int i = 0; i < pal.size(); i++) { ! 130: if ((i & planemask)) { ! 131: int n = i % 16; ! 132: pal[i] = vmpal[n].ToColor(); ! 133: } else { ! 134: pal[i] = bg; ! 135: } ! 136: } ! 137: } else { ! 138: // パレットを適用しない場合 ! 139: for (int i = 0; i < pal.size(); i++) { ! 140: if ((i & planemask)) { ! 141: pal[i] = Color(255, 255, 255); ! 142: } else { ! 143: pal[i] = Color(0, 0, 0); ! 144: } ! 145: } ! 146: } ! 147: } ! 148: ! 149: // 倍率を設定 ! 150: void ! 151: WXPlaneVRAMBitmapPanel::SetScale(int scale_) ! 152: { ! 153: int before = scale; ! 154: ! 155: scale = scale_; ! 156: ! 157: // 仮想画面の大きさを計算 ! 158: virtual_width = plane_width * scale; ! 159: virtual_height = plane_height * scale; ! 160: ! 161: // ビューのスケール変換は前後のスケールがいるのでここでやる ! 162: view.x = view.x * scale / before; ! 163: view.y = view.y * scale / before; ! 164: view.w = view.w * scale / before; ! 165: view.h = view.h * scale / before; ! 166: ! 167: SetMaxClientSize(wxSize(virtual_width, virtual_height)); ! 168: } ! 169: ! 170: // スクロール位置変更通知 ! 171: void ! 172: WXPlaneVRAMBitmapPanel::OnScroll(wxScrollEvent& event) ! 173: { ! 174: int orient = event.GetOrientation(); ! 175: int pos = event.GetPosition(); ! 176: ! 177: if (orient == wxHORIZONTAL) { ! 178: view.x = pos; ! 179: } else { ! 180: view.y = pos; ! 181: } ! 182: } ! 183: ! 184: ! 185: // ! 186: // プレーン VRAM パネル ! 187: // ! 188: ! 189: // イベントテーブル ! 190: wxBEGIN_EVENT_TABLE(WXPlaneVRAMPanel, inherited) ! 191: EVT_SIZE(WXPlaneVRAMPanel::OnSize) ! 192: EVT_TIMER(wxID_ANY, WXPlaneVRAMPanel::OnTimer) ! 193: wxEND_EVENT_TABLE() ! 194: ! 195: // コンストラクタ ! 196: WXPlaneVRAMPanel::WXPlaneVRAMPanel(wxWindow *parent) ! 197: : inherited(parent) ! 198: { ! 199: // 表示パネル ! 200: viewctl = new WXPlaneVRAMBitmapPanel(this); ! 201: ! 202: // スクロールバーを自分で持つ (配置は Layout() で行う) ! 203: vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL); ! 204: hscroll = new WXScrollBar(this, wxID_ANY, wxSB_HORIZONTAL); ! 205: ! 206: // 右下の空き地 ! 207: corner = new WXBitmapPanel(this); ! 208: ! 209: // Sizer 使わず自前でレイアウトする。 ! 210: SetAutoLayout(true); ! 211: ! 212: // 最小値は適当 ! 213: int vscr_width = vscroll->GetClientSize().x; ! 214: int hscr_height = hscroll->GetClientSize().y; ! 215: SetMinClientSize(wxSize(16 + vscr_width, 16 + hscr_height)); ! 216: SetMaxClientSize(wxSize(viewctl->virtual_width + vscr_width, ! 217: viewctl->virtual_height + hscr_height)); ! 218: ! 219: // スクロールバーからの通知イベントは表示パネルへ回す ! 220: vscroll->Connect(NONO_EVT_SCROLL, ! 221: wxScrollEventHandler(WXPlaneVRAMBitmapPanel::OnScroll), NULL, viewctl); ! 222: hscroll->Connect(NONO_EVT_SCROLL, ! 223: wxScrollEventHandler(WXPlaneVRAMBitmapPanel::OnScroll), NULL, viewctl); ! 224: ! 225: // 更新タイマーはモニターパネル同様の 30Hz にしておく。 ! 226: timer.SetOwner(this); ! 227: timer.Start(33); ! 228: } ! 229: ! 230: // デストラクタ ! 231: WXPlaneVRAMPanel::~WXPlaneVRAMPanel() ! 232: { ! 233: } ! 234: ! 235: bool ! 236: WXPlaneVRAMPanel::Layout() ! 237: { ! 238: if (inherited::Layout() == false) { ! 239: return false; ! 240: } ! 241: ! 242: // コントロールを配置 ! 243: const wxSize size = GetClientSize(); ! 244: int vscr_width = vscroll->GetClientSize().x; ! 245: int hscr_height = hscroll->GetClientSize().y; ! 246: int view_width = size.x - vscr_width; ! 247: int view_height = size.y - hscr_height; ! 248: viewctl->SetSize(0, 0, view_width, view_height); ! 249: vscroll->SetSize(view_width, 0, vscr_width, view_height); ! 250: hscroll->SetSize(0, view_height, view_width, hscr_height); ! 251: corner->SetSize(view_width, view_height, vscr_width, hscr_height); ! 252: ! 253: // XXX 内部のコントロールのサイズが確定してからでないと DoSize() できない ! 254: DoSize(size); ! 255: ! 256: return true; ! 257: } ! 258: ! 259: // サイズ変更イベント ! 260: void ! 261: WXPlaneVRAMPanel::OnSize(wxSizeEvent& event) ! 262: { ! 263: // Mac ではウィンドウ作成時に 0 以下の値が来ることがある。 ! 264: // GTK では 1 で来ることがある。 ! 265: wxSize size = event.GetSize(); ! 266: if (size.x <= 1 || size.y <= 1) { ! 267: return; ! 268: } ! 269: ! 270: // Layout() を呼ぶために必要 ! 271: event.Skip(); ! 272: ! 273: // XXX レイアウトが終わった後でないと DoSize() できない ! 274: // DoSize(size); ! 275: } ! 276: ! 277: // サイズ変更処理。パネルサイズと倍率が変わったら呼ぶこと。 ! 278: // 倍率が変わった場合もスクロールバーの再設定とかがあるため。 ! 279: void ! 280: WXPlaneVRAMPanel::DoSize(wxSize size) ! 281: { ! 282: wxSize viewsize = viewctl->GetClientSize(); ! 283: int virtual_width = viewctl->virtual_width; ! 284: int virtual_height = viewctl->virtual_height; ! 285: Rect& view = viewctl->view; ! 286: ! 287: // スクロールバーが右端まで行っている場合は右を固定したように見せる。 ! 288: // ただし全体が見えている場合は除く。 ! 289: ! 290: if (view.x > 0 && ! 291: (view.x + view.w == virtual_width || ! 292: view.x + viewsize.x >= virtual_width)) ! 293: { ! 294: view.x = virtual_width - viewsize.x; ! 295: if (view.x < 0) { ! 296: view.x = 0; ! 297: } ! 298: } ! 299: view.w = viewsize.x; ! 300: ! 301: // 下端も同様 ! 302: if (view.y > 0 && ! 303: (view.y + view.h >= virtual_height || ! 304: view.y + size.y >= virtual_height)) ! 305: { ! 306: view.y = virtual_height - viewsize.y; ! 307: if (view.y < 0) { ! 308: view.y = 0; ! 309: } ! 310: } ! 311: view.h = viewsize.y; ! 312: ! 313: // スクロールバー(横)を再設定 ! 314: assert(hscroll); ! 315: int hpos = view.x; ! 316: int hthumbsize = view.w; ! 317: int hrange = virtual_width; ! 318: int hpagesize = view.w; ! 319: hscroll->SetScrollParam(hpos, hthumbsize, hrange, hpagesize); ! 320: ! 321: // スクロールバー(縦)を再設定 ! 322: assert(vscroll); ! 323: int vpos = view.y; ! 324: int vthumbsize = view.h; ! 325: int vrange = virtual_height; ! 326: int vpagesize = view.h; ! 327: vscroll->SetScrollParam(vpos, vthumbsize, vrange, vpagesize); ! 328: } ! 329: ! 330: // タイマーイベント ! 331: void ! 332: WXPlaneVRAMPanel::OnTimer(wxTimerEvent& event) ! 333: { ! 334: Refresh(); ! 335: } ! 336: ! 337: // プレーン選択変更 ! 338: void ! 339: WXPlaneVRAMPanel::EnablePlane(int plane, bool value) ! 340: { ! 341: viewctl->EnablePlane(plane, value); ! 342: } ! 343: ! 344: // パレット適用変更 ! 345: void ! 346: WXPlaneVRAMPanel::EnablePalette(bool value) ! 347: { ! 348: viewctl->EnablePalette(value); ! 349: } ! 350: ! 351: // 倍率を設定 ! 352: void ! 353: WXPlaneVRAMPanel::SetScale(int scale_) ! 354: { ! 355: viewctl->SetScale(scale_); ! 356: ! 357: int vscr_width = vscroll->GetClientSize().x; ! 358: int hscr_height = hscroll->GetClientSize().y; ! 359: SetMaxClientSize(wxSize(viewctl->virtual_width + vscr_width, ! 360: viewctl->virtual_height + hscr_height)); ! 361: ! 362: DoSize(GetSize()); ! 363: } ! 364: ! 365: ! 366: // ! 367: // プレーン VRAM ウィンドウ ! 368: // ! 369: ! 370: // イベントテーブル ! 371: wxBEGIN_EVENT_TABLE(WXPlaneVRAMWindow, inherited) ! 372: EVT_COMMAND_RANGE(ID_PLANE0, ID_PLANE7, wxEVT_CHECKBOX, ! 373: WXPlaneVRAMWindow::OnPlane) ! 374: EVT_CHECKBOX(ID_PALETTE, WXPlaneVRAMWindow::OnApplyPalette) ! 375: EVT_CHOICE(ID_SCALE, WXPlaneVRAMWindow::OnScale) ! 376: wxEND_EVENT_TABLE() ! 377: ! 378: // コンストラクタ ! 379: WXPlaneVRAMWindow::WXPlaneVRAMWindow(wxWindow *parent, const wxString& name) ! 380: : inherited(parent, wxID_ANY, name, ! 381: inherited::DEFAULT_STYLE | wxRESIZE_BORDER) ! 382: { ! 383: auto *topsizer = new wxBoxSizer(wxVERTICAL); ! 384: ! 385: // 上にコントロールパネル(のまず下敷き) ! 386: ctrlpanel = new WXBitmapPanel(this); ! 387: topsizer->Add(ctrlpanel, 0, wxEXPAND); ! 388: ! 389: // コントロールパネル用の横 Sizer ! 390: auto *ctrlbox = new wxBoxSizer(wxHORIZONTAL); ! 391: ! 392: // プレーン選択チェックボックス (#3, #2, #1, #0 の順に並べる) ! 393: for (int i = planesw.size() - 1; i >= 0; i--) { ! 394: planesw[i] = new wxCheckBox(ctrlpanel, ID_PLANE(i), ! 395: string_format("#%d", i)); ! 396: ctrlbox->Add(planesw[i], 0, wxALIGN_CENTER); ! 397: } ! 398: ! 399: // パレット合成チェックボックス ! 400: applysw = new wxCheckBox(ctrlpanel, ID_PALETTE, _("Apply palette")); ! 401: ctrlbox->Add(applysw, 0, wxALIGN_CENTER); ! 402: ! 403: // セパレータを出したいのだが… ! 404: ctrlbox->Add(new wxStaticText(ctrlpanel, wxID_ANY, "|"), 0, wxALIGN_CENTER); ! 405: ! 406: // 倍率 ! 407: wxString scale_choice[] = { ! 408: "x1", ! 409: "x2", ! 410: "x4", ! 411: }; ! 412: scalesw = new wxChoice(ctrlpanel, ID_SCALE, ! 413: wxDefaultPosition, wxDefaultSize, ! 414: countof(scale_choice), scale_choice); ! 415: ctrlbox->Add(scalesw, 0, wxALIGN_CENTER); ! 416: ! 417: // sizer と下敷きパネルを紐付ける ! 418: ctrlpanel->SetSizer(ctrlbox); ! 419: ctrlbox->SetSizeHints(ctrlpanel); ! 420: ! 421: viewpanel = new WXPlaneVRAMPanel(this); ! 422: topsizer->Add(viewpanel, 1, wxEXPAND); ! 423: ! 424: SetSizer(topsizer); ! 425: ! 426: // 最小サイズは上コントロール部の横幅が最小基準 ! 427: wxSize minsize = ctrlpanel->GetMinClientSize(); ! 428: minsize.y += viewpanel->GetMinClientSize().y; ! 429: SetMinClientSize(minsize); ! 430: // 最大サイズは DoScale() 内で設定している ! 431: ! 432: // 1bpp ならプレーン選択はすべて無効、4bpp ならすべて有効。 ! 433: if (gPlaneVRAM->GetPlaneCount() == 1) { ! 434: for (int i = 0; i < planesw.size(); i++) { ! 435: planesw[i]->Enable(false); ! 436: } ! 437: } ! 438: ! 439: // 初期値をコントロールにセットする ! 440: if (sticky_used) { ! 441: // 前回の値があればそれを使う。 ! 442: for (int i = 0; i < planesw.size(); i++) { ! 443: planesw[i]->SetValue(sticky_plane[i]); ! 444: } ! 445: applysw->SetValue(sticky_apply); ! 446: scalesw->SetSelection(sticky_scale); ! 447: } else { ! 448: if (gPlaneVRAM->GetPlaneCount() == 1) { ! 449: // 初回 1bpp なら #0 プレーンのみオン。 ! 450: for (int i = 0; i < planesw.size(); i++) { ! 451: planesw[i]->SetValue((i == 0)); ! 452: } ! 453: applysw->SetValue(true); ! 454: } else { ! 455: // 初回 4bpp なら全プレーンオン。 ! 456: for (int i = 0; i < planesw.size(); i++) { ! 457: planesw[i]->SetValue(true); ! 458: } ! 459: applysw->SetValue(true); ! 460: } ! 461: scalesw->SetSelection(0); ! 462: } ! 463: ! 464: // SetValue() ではイベントが飛ばないので、 ! 465: // 直接呼び出してイベントが来たことにする。うーん…。 ! 466: for (int i = 0; i < planesw.size(); i++) { ! 467: DoPlane(i, planesw[i]->IsChecked()); ! 468: } ! 469: DoApplyPalette(applysw->IsChecked()); ! 470: DoScale(scalesw->GetSelection()); ! 471: } ! 472: ! 473: // デストラクタ ! 474: WXPlaneVRAMWindow::~WXPlaneVRAMWindow() ! 475: { ! 476: } ! 477: ! 478: void ! 479: WXPlaneVRAMWindow::FontChanged() ! 480: { ! 481: // 親 (wxSubWindow) の FontChanged() を実行しないようにするための ! 482: // 空のオーバーライド。親の FontChanged() が呼ぶ DoSize() が ! 483: // ウィンドウサイズを変更しようとするが、ここはテキストフォントを ! 484: // 持っていないのでその操作は不要。うーん。 ! 485: } ! 486: ! 487: // プレーン選択のチェックボックスイベント ! 488: void ! 489: WXPlaneVRAMWindow::OnPlane(wxCommandEvent& event) ! 490: { ! 491: int plane = event.GetId() - ID_PLANE0; ! 492: bool value = event.IsChecked(); ! 493: ! 494: DoPlane(plane, value); ! 495: } ! 496: ! 497: // プレーン選択 ON/OFF 処理 ! 498: void ! 499: WXPlaneVRAMWindow::DoPlane(int plane, bool value) ! 500: { ! 501: // コントロールに指示 ! 502: viewpanel->EnablePlane(plane, value); ! 503: ! 504: // 値を保存 ! 505: sticky_plane[plane] = value; ! 506: sticky_used = true; ! 507: } ! 508: ! 509: // パレット合成のチェックボックスイベント ! 510: void ! 511: WXPlaneVRAMWindow::OnApplyPalette(wxCommandEvent& event) ! 512: { ! 513: bool value = event.IsChecked(); ! 514: ! 515: DoApplyPalette(value); ! 516: } ! 517: ! 518: // パレット合成 ON/OFF 処理 ! 519: void ! 520: WXPlaneVRAMWindow::DoApplyPalette(bool value) ! 521: { ! 522: // コントロールに指示 ! 523: viewpanel->EnablePalette(value); ! 524: ! 525: // 値を保存 ! 526: sticky_apply = value; ! 527: sticky_used = true; ! 528: } ! 529: ! 530: // 倍率変更イベント ! 531: void ! 532: WXPlaneVRAMWindow::OnScale(wxCommandEvent& event) ! 533: { ! 534: int scale_index = event.GetSelection(); ! 535: ! 536: DoScale(scale_index); ! 537: } ! 538: ! 539: // 倍率変更処理 ! 540: void ! 541: WXPlaneVRAMWindow::DoScale(int scale_index) ! 542: { ! 543: viewpanel->SetScale(1 << scale_index); ! 544: ! 545: // 最大サイズは表示部の最大サイズから ! 546: wxSize maxsize = viewpanel->GetMaxClientSize(); ! 547: maxsize.y += ctrlpanel->GetMinClientSize().y; ! 548: SetMaxClientSize(maxsize); ! 549: ! 550: // 保存しておくのはインデックスのほう ! 551: sticky_scale = scale_index; ! 552: } ! 553: ! 554: // static 変数 ! 555: std::array<bool, WXPlaneVRAMWindow::NPLANES> WXPlaneVRAMWindow::sticky_plane; ! 556: bool WXPlaneVRAMWindow::sticky_apply; ! 557: int WXPlaneVRAMWindow::sticky_scale; ! 558: bool WXPlaneVRAMWindow::sticky_used;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.