|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.6 ! root 7: //
! 8: // ビデオ系モニターウィンドウ
! 9: //
! 10:
1.1 root 11: #include "wxvideomonitor.h"
1.1.1.6 ! root 12: #include "wxuimessage.h"
! 13: #include "bt454.h"
1.1.1.5 root 14: #include "lunafb.h"
1.1.1.6 ! root 15: #include "renderer.h"
! 16:
! 17: enum {
! 18: ID_PLANE0 = IDGROUP_VIDEO,
! 19: ID_PLANE1,
! 20: ID_PLANE2,
! 21: ID_PLANE3,
! 22: ID_PLANE4,
! 23: ID_PLANE5,
! 24: ID_PLANE6,
! 25: ID_PLANE7,
! 26: ID_PALETTE,
! 27:
! 28: ID_local_end, // 最後に置く (チェック用)
! 29: };
! 30: static_assert(ID_local_end <= (int)IDGROUP_VIDEO_END, "ID exceeded");
! 31:
! 32: #define ID_PLANE(id) (ID_PLANE0 + (id))
1.1 root 33:
34: //
35: // LUNA ビットマップパネル
36: //
37:
38: // イベントテーブル
39: wxBEGIN_EVENT_TABLE(WXLunaBitmapPanel, inherited)
40: EVT_SIZE(WXLunaBitmapPanel::OnSize)
1.1.1.6 ! root 41: EVT_TIMER(wxID_ANY, WXLunaBitmapPanel::OnTimer)
1.1 root 42: wxEND_EVENT_TABLE()
43:
44: // コンストラクタ
45: WXLunaBitmapPanel::WXLunaBitmapPanel(wxWindow *parent)
1.1.1.6 ! root 46: : inherited(parent, wxDefaultSize)
1.1 root 47: {
1.1.1.6 ! root 48: // スクロールバーを自分で持つ (配置は Layout() で行う)
! 49: vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL);
! 50: hscroll = new WXScrollBar(this, wxID_ANY, wxSB_HORIZONTAL);
! 51:
! 52: // Sizer 使わず自前でレイアウトする。
! 53: SetAutoLayout(true);
! 54:
! 55: // 最小値は適当
! 56: int vscr_width = vscroll->GetClientSize().x;
! 57: int hscr_height = hscroll->GetClientSize().y;
! 58: SetMinClientSize(wxSize(16 + vscr_width, 16 + hscr_height));
! 59: SetMaxClientSize(wxSize(virtual_width + vscr_width,
! 60: virtual_height + hscr_height));
! 61:
! 62: // スクロールバーからの通知イベントを受け取る
! 63: vscroll->Connect(NONO_EVT_SCROLL,
! 64: wxScrollEventHandler(WXLunaBitmapPanel::OnScroll), NULL, this);
! 65: hscroll->Connect(NONO_EVT_SCROLL,
! 66: wxScrollEventHandler(WXLunaBitmapPanel::OnScroll), NULL, this);
! 67:
! 68: // VM からの通知を受け取る
! 69: WXUIMessage::Connect(UIMessage::PALETTE, this,
! 70: wxCommandEventHandler(WXLunaBitmapPanel::OnPaletteChanged));
! 71:
! 72: renderer = dynamic_cast<LunaRenderer*>(gRenderer);
1.1 root 73:
1.1.1.6 ! root 74: // 更新タイマーはモニターパネル同様の 30Hz にしておく。
! 75: timer.SetOwner(this);
! 76: timer.Start(33);
1.1 root 77: }
78:
79: // デストラクタ
80: WXLunaBitmapPanel::~WXLunaBitmapPanel()
81: {
1.1.1.6 ! root 82: WXUIMessage::Disconnect(UIMessage::PALETTE,
! 83: wxCommandEventHandler(WXLunaBitmapPanel::OnPaletteChanged));
! 84: }
! 85:
! 86: bool
! 87: WXLunaBitmapPanel::Layout()
! 88: {
! 89: if (inherited::Layout() == false) {
! 90: return false;
! 91: }
! 92:
! 93: // クライアント領域内にスクロールバーを置く
! 94: // (その分のスペースは加味してある)
! 95: const wxSize size = GetClientSize();
! 96: int vscr_width = vscroll->GetClientSize().x;
! 97: int hscr_height = hscroll->GetClientSize().y;
! 98: int view_width = size.x - vscr_width;
! 99: int view_height = size.y - hscr_height;
! 100: vscroll->SetSize(view_width, 0, vscr_width, view_height);
! 101: hscroll->SetSize(0, view_height, view_width, hscr_height);
! 102:
! 103: // 右下の空き地は誰も描画がはみ出さなければ最初の背景色のままのはず
! 104:
! 105: return true;
1.1 root 106: }
107:
108: // サイズ変更イベント
109: void
110: WXLunaBitmapPanel::OnSize(wxSizeEvent& event)
111: {
112: // Mac ではウィンドウ作成時に 0 以下の値が来ることがある
113: // GTK では 1 で来ることがある
1.1.1.6 ! root 114: wxSize size = event.GetSize();
1.1 root 115: if (size.x <= 1 || size.y <= 1) {
116: return;
117: }
118:
1.1.1.6 ! root 119: inherited::OnSize(event);
1.1 root 120:
1.1.1.6 ! root 121: // スクロールバー分を除いたところが描画領域
! 122: size.x -= vscroll->GetClientSize().x;
! 123: size.y -= hscroll->GetClientSize().y;
! 124:
! 125: // スクロールバーが右端まで行っている場合は右を固定したように見せる
! 126: // ただし全体が見えている場合は除く。
! 127:
! 128: if (view.x > 0 &&
! 129: (view.x + view.w == virtual_width ||
! 130: view.x + size.x >= virtual_width))
! 131: {
! 132: view.x = virtual_width - size.x;
! 133: }
! 134: view.w = size.x;
! 135:
! 136: // 下端も同様
! 137: if (view.y > 0 &&
! 138: (view.y + view.h >= virtual_height ||
! 139: view.y + size.y >= virtual_height))
! 140: {
! 141: view.y = virtual_height - size.y;
! 142: }
! 143: view.h = size.y;
! 144:
! 145: // スクロールバー(横)を再設定
! 146: assert(hscroll);
! 147: int hpos = view.x;
! 148: int hthumbsize = view.w;
! 149: int hrange = virtual_width;
! 150: int hpagesize = view.w;
! 151: hscroll->SetScrollParam(hpos, hthumbsize, hrange, hpagesize);
! 152:
! 153: // スクロールバー(縦)を再設定
! 154: assert(vscroll);
! 155: int vpos = view.y;
! 156: int vthumbsize = view.h;
! 157: int vrange = virtual_height;
! 158: int vpagesize = view.h;
! 159: vscroll->SetScrollParam(vpos, vthumbsize, vrange, vpagesize);
1.1 root 160: }
161:
1.1.1.6 ! root 162: // スクロール位置変更通知
1.1 root 163: void
1.1.1.6 ! root 164: WXLunaBitmapPanel::OnScroll(wxScrollEvent& event)
1.1 root 165: {
166: int orient = event.GetOrientation();
167: int pos = event.GetPosition();
168:
169: if (orient == wxHORIZONTAL) {
1.1.1.6 ! root 170: view.x = pos;
1.1 root 171: } else {
1.1.1.6 ! root 172: view.y = pos;
1.1 root 173: }
174: }
175:
1.1.1.6 ! root 176: // タイマーイベント
! 177: void
! 178: WXLunaBitmapPanel::OnTimer(wxTimerEvent& event)
! 179: {
! 180: Refresh();
! 181: }
! 182:
1.1 root 183: // XXX 実際にはこの辺かどこかで更新チェックをしないといけない。
1.1.1.6 ! root 184: // 今は表示領域を毎回描画しているので無駄。
1.1 root 185:
1.1.1.6 ! root 186: // ビットマッププレーンの内容を描画する
1.1 root 187: void
1.1.1.6 ! root 188: WXLunaBitmapPanel::Draw()
1.1 root 189: {
1.1.1.6 ! root 190: assert(view.GetRight() < virtual_width);
! 191: assert(view.GetBottom() < virtual_height);
! 192:
! 193: const BitmapI8& src = renderer->GetComposite();
1.1 root 194:
1.1.1.6 ! root 195: bitmap.DrawBitmap(0, 0, src, &pal[0], view);
1.1 root 196: }
197:
1.1.1.6 ! root 198: // プレーン選択変更
1.1 root 199: void
1.1.1.6 ! root 200: WXLunaBitmapPanel::EnablePlane(int plane, bool value)
1.1 root 201: {
1.1.1.6 ! root 202: if (value) {
! 203: planemask |= 1U << plane;
! 204: } else {
! 205: planemask &= ~(1U << plane);
! 206: }
! 207:
! 208: // パレット生成
! 209: GenPalette();
! 210: }
! 211:
! 212: // パレット適用変更
! 213: void
! 214: WXLunaBitmapPanel::EnablePalette(bool value)
! 215: {
! 216: apply_palette = value;
! 217:
! 218: // パレット生成
! 219: GenPalette();
! 220: }
! 221:
! 222: // VM からのパレット変更通知
! 223: void
! 224: WXLunaBitmapPanel::OnPaletteChanged(wxCommandEvent& event)
! 225: {
! 226: // パレット生成
! 227: GenPalette();
! 228: }
! 229:
! 230: // パレット生成
! 231: void
! 232: WXLunaBitmapPanel::GenPalette()
! 233: {
! 234: if (apply_palette) {
! 235: // パレットを適用する場合
! 236: // (今のところ BT454 (4bpp) のみ対応)
! 237: const ColorXBGR *vmpal = gBT454->GetHostPalette();
! 238: const Color bg = vmpal[0].ToColor();
! 239: for (int i = 0; i < pal.size(); i++) {
! 240: if ((i & planemask)) {
! 241: int n = i % 16;
! 242: pal[i] = vmpal[n].ToColor();
! 243: } else {
! 244: pal[i] = bg;
! 245: }
! 246: }
! 247: } else {
! 248: // パレットを適用しない場合
! 249: for (int i = 0; i < pal.size(); i++) {
! 250: if ((i & planemask)) {
! 251: pal[i] = Color(255, 255, 255);
! 252: } else {
! 253: pal[i] = Color(0, 0, 0);
1.1 root 254: }
255: }
256: }
257: }
258:
1.1.1.6 ! root 259:
1.1 root 260: //
261: // LUNA ビットマップウィンドウ
262: //
263:
264: wxBEGIN_EVENT_TABLE(WXLunaBitmapWindow, inherited)
1.1.1.6 ! root 265: EVT_COMMAND_RANGE(ID_PLANE0, ID_PLANE7, wxEVT_CHECKBOX,
! 266: WXLunaBitmapWindow::OnPlane)
! 267: EVT_CHECKBOX(ID_PALETTE, WXLunaBitmapWindow::OnApplyPalette)
1.1 root 268: wxEND_EVENT_TABLE()
269:
270: // コンストラクタ
1.1.1.5 root 271: WXLunaBitmapWindow::WXLunaBitmapWindow(wxWindow *parent, const wxString& name)
272: : inherited(parent, wxID_ANY, name,
1.1 root 273: inherited::DEFAULT_STYLE | wxRESIZE_BORDER)
274: {
1.1.1.6 ! root 275: auto *topsizer = new wxBoxSizer(wxVERTICAL);
1.1 root 276:
1.1.1.6 ! root 277: // 上にコントロールパネル(のまず下敷き)
! 278: auto ctrlpanel = new WXBitmapPanel(this);
! 279: topsizer->Add(ctrlpanel, 0, wxEXPAND);
! 280:
! 281: // コントロールパネル用の横 Sizer
! 282: auto *ctrlbox = new wxBoxSizer(wxHORIZONTAL);
! 283:
! 284: // プレーン選択チェックボックス (#3, #2, #1, #0 の順に並べる)
! 285: for (int i = planesw.size() - 1; i >= 0; i--) {
! 286: planesw[i] = new wxCheckBox(ctrlpanel, ID_PLANE(i),
! 287: string_format("#%d", i));
! 288: ctrlbox->Add(planesw[i]);
! 289: }
1.1 root 290:
1.1.1.6 ! root 291: // パレット合成チェックボックス
! 292: applysw = new wxCheckBox(ctrlpanel, ID_PALETTE, _("Apply palette"));
! 293: ctrlbox->Add(applysw);
! 294:
! 295: // sizer と下敷きパネルを紐付ける
! 296: ctrlpanel->SetSizer(ctrlbox);
! 297: ctrlbox->SetSizeHints(ctrlpanel);
! 298:
! 299: viewpanel = new WXLunaBitmapPanel(this);
! 300: topsizer->Add(viewpanel, 1, wxEXPAND);
! 301:
! 302: SetSizer(topsizer);
! 303:
! 304: // 最小サイズ
! 305: wxSize minsize = ctrlpanel->GetMinClientSize();
! 306: minsize.y += viewpanel->GetMinClientSize().y;
! 307: SetMinClientSize(minsize);
! 308:
! 309: // 1bpp ならプレーン選択はすべて無効、4bpp ならすべて有効。
! 310: if (gPlaneVRAM->GetPlaneCount() == 1) {
! 311: for (int i = 0; i < planesw.size(); i++) {
! 312: planesw[i]->Enable(false);
! 313: }
! 314: }
! 315:
! 316: // 初期値をコントロールにセットする
! 317: if (sticky_used) {
! 318: // 前回の値があればそれを使う。
! 319: for (int i = 0; i < planesw.size(); i++) {
! 320: planesw[i]->SetValue(sticky_plane[i]);
! 321: }
! 322: applysw->SetValue(sticky_apply);
! 323: } else if (gPlaneVRAM->GetPlaneCount() == 1) {
! 324: // 初回 1bpp なら #0 プレーンのみオン。
! 325: for (int i = 0; i < planesw.size(); i++) {
! 326: planesw[i]->SetValue((i == 0));
! 327: }
! 328: applysw->SetValue(true);
! 329: } else {
! 330: // 初回 4bpp なら全プレーンオン。
! 331: for (int i = 0; i < planesw.size(); i++) {
! 332: planesw[i]->SetValue(true);
! 333: }
! 334: applysw->SetValue(true);
! 335: }
! 336:
! 337: // SetValue() ではイベントが飛ばないので、
! 338: // 直接呼び出してイベントが来たことにする。うーん…。
! 339: for (int i = 0; i < planesw.size(); i++) {
! 340: DoPlane(i, planesw[i]->IsChecked());
! 341: }
! 342: DoApplyPalette(applysw->IsChecked());
1.1 root 343: }
344:
345: // デストラクタ
346: WXLunaBitmapWindow::~WXLunaBitmapWindow()
347: {
348: }
349:
350: void
1.1.1.6 ! root 351: WXLunaBitmapWindow::FontChanged()
1.1 root 352: {
1.1.1.6 ! root 353: // 親 (wxSubWindow) の FontChanged() を実行しないようにするための
! 354: // 空のオーバーライド。親の FontChanged() が呼ぶ DoSize() が
! 355: // ウィンドウサイズを変更しようとするが、ここはテキストフォントを
! 356: // 持っていないのでその操作は不要。うーん。
1.1 root 357: }
1.1.1.6 ! root 358:
! 359: // プレーン選択のチェックボックスイベント
! 360: void
! 361: WXLunaBitmapWindow::OnPlane(wxCommandEvent& event)
! 362: {
! 363: int plane = event.GetId() - ID_PLANE0;
! 364: bool value = event.IsChecked();
! 365:
! 366: DoPlane(plane, value);
! 367: }
! 368:
! 369: // プレーン選択 ON/OFF 処理
! 370: void
! 371: WXLunaBitmapWindow::DoPlane(int plane, bool value)
! 372: {
! 373: // コントロールに指示
! 374: viewpanel->EnablePlane(plane, value);
! 375:
! 376: // 値を保存
! 377: sticky_plane[plane] = value;
! 378: sticky_used = true;
! 379: }
! 380:
! 381: // パレット合成のチェックボックスイベント
! 382: void
! 383: WXLunaBitmapWindow::OnApplyPalette(wxCommandEvent& event)
! 384: {
! 385: bool value = event.IsChecked();
! 386:
! 387: DoApplyPalette(value);
! 388: }
! 389:
! 390: // パレット合成 ON/OFF 処理
! 391: void
! 392: WXLunaBitmapWindow::DoApplyPalette(bool value)
! 393: {
! 394: // コントロールに指示
! 395: viewpanel->EnablePalette(value);
! 396:
! 397: // 値を保存
! 398: sticky_apply = value;
! 399: sticky_used = true;
! 400: }
! 401:
! 402: // static 変数
! 403: std::array<bool, WXLunaBitmapWindow::NPLANES> WXLunaBitmapWindow::sticky_plane;
! 404: bool WXLunaBitmapWindow::sticky_apply;
! 405: bool WXLunaBitmapWindow::sticky_used;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.