Annotation of nono/wx/wxscreenmonitor.cpp, revision 1.1.1.2

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // スクリーンモニタ
                      9: //
                     10: 
                     11: #include "wxscreenmonitor.h"
                     12: #include "wxscrollbar.h"
                     13: #include "wxtextscreen.h"
                     14: 
                     15: //#define WINDOW_DEBUG 1
                     16: 
                     17: #if defined(WINDOW_DEBUG)
                     18: #define DPRINTF(fmt...) printf(fmt)
                     19: #else
                     20: #define DPRINTF(fmt...) /**/
                     21: #endif
                     22: 
                     23: //
                     24: // スクリーンパネル (共通部)
                     25: //
                     26: 
                     27: // イベントテーブル
                     28: wxBEGIN_EVENT_TABLE(WXScreenPanel, inherited)
                     29:        EVT_MOTION(WXScreenPanel::OnMouseMove)
                     30:        EVT_LEAVE_WINDOW(WXScreenPanel::OnMouseMove)
                     31:        EVT_MOUSEWHEEL(WXScreenPanel::OnMouseWheel)
                     32: wxEND_EVENT_TABLE()
                     33: 
                     34: // コンストラクタ
                     35: WXScreenPanel::WXScreenPanel(wxWindow *parent)
                     36:        : inherited(parent)
                     37: {
                     38:        cursor = wxDefaultPosition;
                     39: }
                     40: 
                     41: // 継承側でサイズが確定したところで呼ぶ、コンストラクタの残り。
                     42: void
                     43: WXScreenPanel::Ctor(int plane_width_, int plane_height_)
                     44: {
                     45:        // 画面のネイティブの大きさ。
                     46:        plane_width  = plane_width_;
                     47:        plane_height = plane_height_;
                     48: 
                     49:        // まず等倍でセット。
                     50:        scale = 1;
                     51:        SetScale(1);
                     52: }
                     53: 
                     54: // デストラクタ
                     55: WXScreenPanel::~WXScreenPanel()
                     56: {
                     57: }
                     58: 
                     59: // 倍率を設定
                     60: void
                     61: WXScreenPanel::SetScale(int new_scale)
                     62: {
                     63:        int before = scale;
                     64: 
                     65:        scale = new_scale;
                     66: 
                     67:        // 仮想画面の大きさを計算。
                     68:        virtual_width  = plane_width  * scale;
                     69:        virtual_height = plane_height * scale;
                     70: 
                     71:        // ビューのスケール変換は前後のスケールがいるのでここでやる。
                     72:        view.x = view.x * scale / before;
                     73:        view.y = view.y * scale / before;
                     74:        view.w = view.w * scale / before;
                     75:        view.h = view.h * scale / before;
                     76: 
                     77:        SetMaxSize(wxSize(virtual_width, virtual_height));
                     78: }
                     79: 
                     80: // スクロール位置変更通知
                     81: void
                     82: WXScreenPanel::OnScroll(wxScrollEvent& event)
                     83: {
                     84:        int orient = event.GetOrientation();
                     85:        int pos = event.GetPosition();
                     86: 
                     87:        if (orient == wxHORIZONTAL) {
                     88:                view.x = pos;
                     89:        } else {
                     90:                view.y = pos;
                     91:        }
                     92: }
                     93: 
                     94: // マウス移動イベント
                     95: void
                     96: WXScreenPanel::OnMouseMove(wxMouseEvent& event)
                     97: {
                     98:        // pt はこのパネル左上からの位置
                     99:        const wxPoint& pt = event.GetPosition();
                    100: 
                    101:        // pt がパネル内の座標なのに Leaving() になることがある。
                    102:        // pt がパネル外の座標なのに Leaving() にならないことがある。
                    103:        if (event.Leaving() == false && GetClientRect().Contains(pt)) {
                    104:                // cursor は(拡大前の)仮想画面上の座標
                    105:                cursor.x = (view.x + pt.x) / scale;
                    106:                cursor.y = (view.y + pt.y) / scale;
                    107:                assertmsg(cursor.x < plane_width,  "%d < %d", cursor.x, plane_width);
                    108:                assertmsg(cursor.y < plane_height, "%d < %d", cursor.y, plane_height);
                    109:        } else {
                    110:                cursor = wxDefaultPosition;
                    111:        }
                    112: }
                    113: 
                    114: // マウスホイールイベント
                    115: void
                    116: WXScreenPanel::OnMouseWheel(wxMouseEvent& event)
                    117: {
                    118:        // ホイールは1回で ±120 が飛んでくる。
                    119:        // ここでは 64 ドットずつ移動させてみる。
                    120:        int delta = event.GetWheelRotation() / 30 * 16;
                    121:        int y = view.y - delta;
                    122:        if (y < 0) {
                    123:                y = 0;
                    124:        } else {
                    125:                int max_y = virtual_height - view.h;
                    126:                if (y >= max_y) {
                    127:                        y = max_y;
                    128:                }
                    129:        }
                    130:        view.y = y;
                    131: 
                    132:        // マウスカーソルは移動してないが view が動いたので cursor 再計算。
                    133:        OnMouseMove(event);
                    134: 
                    135:        // 縦スクロールバーの位置を追従。
                    136:        auto window = dynamic_cast<WXScreenWindow *>(GetParent());
                    137:        window->SetVScrollPosition(view.y);
                    138: }
                    139: 
                    140: 
                    141: //
                    142: // スクリーンモニタウィンドウ (共通部)
                    143: //
                    144: 
                    145: // +----------------------------------------------------+
                    146: // | wxPanel *ctrlpanel                                 |
                    147: // | (wx製のコントロールパネル、横目一杯まで伸びる)     |
                    148: // +---------------------------+------------------------+
                    149: // | WXTextScreen *statuspanel | spacer                 |
                    150: // | (固定幅のテキスト情報)    | (必要なら空き地をおく) |
                    151: // +---------------------------+-+----------------------+
                    152: // | WXScreenPanel *viewpanel    | WXScrollBar *vscroll |
                    153: // | (VRAM 表示パネル)           | (縦スクロールバー)   |
                    154: // +-----------------------------+----------------------+
                    155: // | WXScrollBar *hscroll        | corner               |
                    156: // | (横スクロールバー)          | (空き地)             |
                    157: // +-----------------------------+----------------------+
                    158: 
                    159: // イベントテーブル
                    160: wxBEGIN_EVENT_TABLE(WXScreenWindow, inherited)
                    161:        EVT_TIMER(wxID_ANY, WXScreenWindow::OnTimer)
                    162: wxEND_EVENT_TABLE()
                    163: 
                    164: // コンストラクタ
                    165: WXScreenWindow::WXScreenWindow(wxWindow *parent, const wxString& name)
                    166:        : inherited(parent, wxID_ANY, name, DEFAULT_STYLE | wxRESIZE_BORDER)
                    167: {
                    168:        SetName(name + ".Window");
                    169: 
                    170:        // 上段、コントロールパネル(のまず下敷き)
                    171:        ctrlpanel = new wxPanel(this);
                    172:        ctrlpanel->SetName(name + ".CtrlPanel");
                    173: 
                    174:        // 中段、情報パネルと右側の空き地用。
                    175:        // 情報パネルは継承クラスで。
                    176:        spacer = new WXBitmapPanel(this);
                    177: 
                    178:        // 下段、表示パネルは継承クラスで。
                    179: 
                    180:        // スクロールバー。
                    181:        vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL);
                    182:        hscroll = new WXScrollBar(this, wxID_ANY, wxSB_HORIZONTAL);
                    183: 
                    184:        // 右下の空き地。
                    185:        corner = new WXBitmapPanel(this);
                    186: 
                    187:        // 更新タイマーはモニターパネル同様の 30Hz にしておく。
                    188:        timer.SetOwner(this);
                    189:        timer.Start(33);
                    190: 
                    191:        DPRINTF("%s.ctor end\n", __func__);
                    192: }
                    193: 
                    194: // コンストラクタの残り。
                    195: // statuspanel、viewpanel を作成したあとで呼ぶ。
                    196: void
                    197: WXScreenWindow::Ctor()
                    198: {
                    199:        assert(statuspanel);
                    200:        assert(viewpanel);
                    201: 
                    202:        // 自前レイアウト。
                    203:        SetMyLayout();
                    204: 
                    205:        FontChanged();
                    206: 
                    207:        // スクロールバーからの通知イベントは表示パネルへ回す。
1.1.1.2 ! root      208:        vscroll->Bind(NONO_EVT_SCROLL, &WXScreenPanel::OnScroll, viewpanel);
        !           209:        hscroll->Bind(NONO_EVT_SCROLL, &WXScreenPanel::OnScroll, viewpanel);
1.1       root      210: }
                    211: 
                    212: // デストラクタ
                    213: WXScreenWindow::~WXScreenWindow()
                    214: {
                    215: }
                    216: 
                    217: bool
                    218: WXScreenWindow::GetMySizeHints(wxSize *newp, wxSize *minp, wxSize *maxp,
                    219:        wxSize *incp)
                    220: {
                    221:        DPRINTF("Window.%s\n", __func__);
                    222: 
                    223:        // viewpanel の最小サイズは縦横スクロールバーの大きさで決まる。
                    224:        const wxSize& ctrlsize = ctrlpanel->GetSize();
                    225:        const wxSize& ctrlmin  = ctrlpanel->GetMinSize();
                    226:        const wxSize& statsize = statuspanel->GetSize();
                    227:        const wxSize& statmin  = statuspanel->GetMinSize();
                    228:        const wxSize& viewsize = viewpanel->GetSize();
                    229:        const wxSize& vscrsize = vscroll->GetSize();
                    230:        const wxSize& vscrmin  = vscroll->GetMinSize();
                    231:        const wxSize& hscrsize = hscroll->GetSize();
                    232: 
                    233:        // コントロールからウィンドウサイズを計算。
                    234:        int size_x = std::max(ctrlmin.x, statmin.x);
                    235:        size_x = std::max(size_x, viewsize.x + vscrsize.x);
                    236:        int size_y = ctrlsize.y + statsize.y + viewsize.y + hscrsize.y;
                    237:        wxSize newsize(size_x, size_y);
                    238: 
                    239:        // 最小サイズを計算。
                    240:        int min_x = std::max(ctrlmin.x, statmin.x);
                    241:        // statmin.x は viewpanel の最小幅より必ず大きいのでこれは不要。
                    242:        //min_x = std::max(min_x, hscrmin.x + vscrsize.x);
                    243:        int min_y = ctrlmin.y + statmin.y + vscrmin.y + hscrsize.y;
                    244:        wxSize minsize(min_x, min_y);
                    245: 
                    246:        // 最大サイズは viewsize に依存しそうだから手抜き。
                    247:        const wxSize& viewmax = viewpanel->GetMaxSize();
                    248:        int max_x = viewmax.x;
                    249:        if (max_x > 0) {
                    250:                max_x += vscrsize.x;
                    251:        }
                    252:        int max_y = viewmax.y;
                    253:        if (max_y > 0) {
                    254:                max_y += ctrlmin.y + statmin.y + hscrsize.y;
                    255:        }
                    256:        wxSize maxsize(max_x, max_y);
                    257: 
                    258:        if (newp) *newp = newsize;
                    259:        if (minp) *minp = minsize;
                    260:        if (maxp) *maxp = maxsize;
                    261:        if (incp) *incp = wxDefaultSize;
                    262:        return true;
                    263: }
                    264: 
                    265: bool
                    266: WXScreenWindow::Layout()
                    267: {
                    268:        if (MyLayout() == false) {
                    269:                DPRINTF("%s.Layout false\n", __func__);
                    270:                // sizer があるので呼ばないといけない。
                    271:                BaseLayout();
                    272: 
                    273:                // コントロールを再配置。
                    274:                const wxSize client = GetClientSize();
                    275:                const wxSize& ctrlsize = ctrlpanel->GetSize();
                    276:                const wxSize& statsize = statuspanel->GetSize();
                    277:                const wxSize& vscrsize = vscroll->GetSize();
                    278:                const wxSize& hscrsize = hscroll->GetSize();
                    279:                DPRINTF("%s.Layout client=(%d,%d)\n", __func__, client.x, client.y);
                    280:                DPRINTF("%s.Layout vscrsize=(%d,%d) hscrsize=(%d,%d)\n", __func__,
                    281:                        vscrsize.x, vscrsize.y, hscrsize.x, hscrsize.y);
                    282:                ctrlpanel->SetSize(0, 0, client.x, ctrlsize.y);
                    283:                statuspanel->SetSize(0, ctrlsize.y, statsize.x, statsize.y);
                    284:                int view_y = ctrlsize.y + statsize.y;
                    285:                int view_w = client.x - vscrsize.x;
                    286:                int view_h = client.y - ctrlsize.y - statsize.y - hscrsize.y;
                    287:                viewpanel->SetSize(0, view_y, view_w, view_h);
                    288:                vscroll->SetSize(view_w, view_y, vscrsize.x, view_h);
                    289:                hscroll->SetSize(0, view_y + view_h, view_w, hscrsize.y);
                    290:                corner->SetSize(view_w, view_y + view_h, hscrsize.x, vscrsize.y);
                    291:                DPRINTF("%s.Layout view=(%d,%d,%d,%d)\n", __func__,
                    292:                        viewpanel->GetPosition().x,
                    293:                        viewpanel->GetPosition().y,
                    294:                        viewpanel->GetSize().x,
                    295:                        viewpanel->GetSize().y);
                    296: 
                    297:                // ステータスパネル右に空き地が出来るなら埋める。
                    298:                if (statsize.x < client.x) {
                    299:                        spacer->SetSize(statsize.x, ctrlsize.y,
                    300:                                client.x - statsize.x, statsize.y);
                    301:                        spacer->Show();
                    302:                } else {
                    303:                        spacer->Hide();
                    304:                }
                    305: 
                    306:                SetScroll();
                    307: 
                    308:                DPRINTF("%s.Layout false done\n", __func__);
                    309:        }
                    310: 
                    311:        return true;
                    312: }
                    313: 
                    314: // 倍率変更イベント
                    315: void
                    316: WXScreenWindow::OnScale(wxCommandEvent& event)
                    317: {
                    318:        int scale_index = event.GetSelection();
                    319: 
                    320:        DoScale(scale_index);
                    321: }
                    322: 
                    323: // 倍率変更処理
                    324: void
                    325: WXScreenWindow::DoScale(int scale_index)
                    326: {
                    327:        DPRINTF("%s index=%d\n", __method__, scale_index);
                    328:        int scale_ = 1 << scale_index;
                    329:        viewpanel->SetScale(scale_);
                    330: 
                    331:        SetScroll();
                    332: 
                    333:        wxSize maxsize;
                    334:        GetMySizeHints(NULL, NULL, &maxsize, NULL);
                    335:        SetMaxClientSize(maxsize);
                    336: }
                    337: 
                    338: // タイマーイベント
                    339: void
                    340: WXScreenWindow::OnTimer(wxTimerEvent& event)
                    341: {
                    342:        viewpanel->Refresh();
                    343: 
                    344:        // この位置の情報で screen を更新
                    345:        TextScreen& screen = statuspanel->GetScreen();
                    346:        const wxPoint& cursor = viewpanel->GetCursor();
                    347: 
                    348:        // UpdateInfo() は cursor が範囲外の時の描画も行っている。
                    349:        UpdateInfo(screen, cursor.x, cursor.y);
                    350:        statuspanel->Refresh();
                    351: }
                    352: 
                    353: // 縦スクロールバーの位置を設置する。
                    354: // (パネルからマウスホイールイベントで呼ばれる)
                    355: void
                    356: WXScreenWindow::SetVScrollPosition(int pos)
                    357: {
                    358:        vscroll->SetThumbPosition(pos);
                    359: }
                    360: 
                    361: // サイズ変更処理。パネルサイズと倍率が変わったら呼ぶこと。
                    362: // 倍率が変わった場合もスクロールバーの再設定とかがあるため。
                    363: void
                    364: WXScreenWindow::SetScroll()
                    365: {
                    366:        wxSize viewsize = viewpanel->GetSize();
                    367:        int virtual_width  = viewpanel->GetVirtualWidth();
                    368:        int virtual_height = viewpanel->GetVirtualHeight();
                    369:        Rect& view = viewpanel->view;
                    370: 
                    371:        DPRINTF("%s: viewsize=(%d,%d)\n", __method__, viewsize.x, viewsize.y);
                    372: 
                    373:        // スクロールバーが右端まで行っている場合は右を固定したように見せる。
                    374:        // ただし全体が見えている場合は除く。
                    375: 
                    376:        if (view.x > 0 &&
                    377:            (view.x + view.w == virtual_width ||
                    378:             view.x + viewsize.x >= virtual_width))
                    379:        {
                    380:                view.x = virtual_width - viewsize.x;
                    381:                if (view.x < 0) {
                    382:                        view.x = 0;
                    383:                }
                    384:        }
                    385:        view.w = viewsize.x;
                    386: 
                    387:        // 下端も同様
                    388:        if (view.y > 0 &&
                    389:            (view.y + view.h >= virtual_height ||
                    390:             view.y + viewsize.y >= virtual_height))
                    391:        {
                    392:                view.y = virtual_height - viewsize.y;
                    393:                if (view.y < 0) {
                    394:                        view.y = 0;
                    395:                }
                    396:        }
                    397:        view.h = viewsize.y;
                    398: 
                    399:        // スクロールバー(横)を再設定
                    400:        assert(hscroll);
                    401:        int hpos = view.x;
                    402:        int hthumbsize = view.w;
                    403:        int hrange = virtual_width;
                    404:        int hpagesize = view.w;
                    405:        hscroll->SetScrollParam(hpos, hthumbsize, hrange, hpagesize);
                    406: 
                    407:        // スクロールバー(縦)を再設定
                    408:        assert(vscroll);
                    409:        int vpos = view.y;
                    410:        int vthumbsize = view.h;
                    411:        int vrange = virtual_height;
                    412:        int vpagesize = view.h;
                    413:        vscroll->SetScrollParam(vpos, vthumbsize, vrange, vpagesize);
                    414: }

unix.superglobalmegacorp.com

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