Annotation of nono/wx/wxplanemonitor.cpp, revision 1.1.1.1

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;

unix.superglobalmegacorp.com

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