Annotation of nono/wx/wxvideomonitor.cpp, revision 1.1.1.6

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;

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.