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

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:        // スクロールバーからの通知イベントは表示パネルへ回す。
        !           208:        vscroll->Connect(NONO_EVT_SCROLL,
        !           209:                wxScrollEventHandler(WXScreenPanel::OnScroll), NULL, viewpanel);
        !           210:        hscroll->Connect(NONO_EVT_SCROLL,
        !           211:                wxScrollEventHandler(WXScreenPanel::OnScroll), NULL, viewpanel);
        !           212: }
        !           213: 
        !           214: // デストラクタ
        !           215: WXScreenWindow::~WXScreenWindow()
        !           216: {
        !           217: }
        !           218: 
        !           219: bool
        !           220: WXScreenWindow::GetMySizeHints(wxSize *newp, wxSize *minp, wxSize *maxp,
        !           221:        wxSize *incp)
        !           222: {
        !           223:        DPRINTF("Window.%s\n", __func__);
        !           224: 
        !           225:        // viewpanel の最小サイズは縦横スクロールバーの大きさで決まる。
        !           226:        const wxSize& ctrlsize = ctrlpanel->GetSize();
        !           227:        const wxSize& ctrlmin  = ctrlpanel->GetMinSize();
        !           228:        const wxSize& statsize = statuspanel->GetSize();
        !           229:        const wxSize& statmin  = statuspanel->GetMinSize();
        !           230:        const wxSize& viewsize = viewpanel->GetSize();
        !           231:        const wxSize& vscrsize = vscroll->GetSize();
        !           232:        const wxSize& vscrmin  = vscroll->GetMinSize();
        !           233:        const wxSize& hscrsize = hscroll->GetSize();
        !           234: 
        !           235:        // コントロールからウィンドウサイズを計算。
        !           236:        int size_x = std::max(ctrlmin.x, statmin.x);
        !           237:        size_x = std::max(size_x, viewsize.x + vscrsize.x);
        !           238:        int size_y = ctrlsize.y + statsize.y + viewsize.y + hscrsize.y;
        !           239:        wxSize newsize(size_x, size_y);
        !           240: 
        !           241:        // 最小サイズを計算。
        !           242:        int min_x = std::max(ctrlmin.x, statmin.x);
        !           243:        // statmin.x は viewpanel の最小幅より必ず大きいのでこれは不要。
        !           244:        //min_x = std::max(min_x, hscrmin.x + vscrsize.x);
        !           245:        int min_y = ctrlmin.y + statmin.y + vscrmin.y + hscrsize.y;
        !           246:        wxSize minsize(min_x, min_y);
        !           247: 
        !           248:        // 最大サイズは viewsize に依存しそうだから手抜き。
        !           249:        const wxSize& viewmax = viewpanel->GetMaxSize();
        !           250:        int max_x = viewmax.x;
        !           251:        if (max_x > 0) {
        !           252:                max_x += vscrsize.x;
        !           253:        }
        !           254:        int max_y = viewmax.y;
        !           255:        if (max_y > 0) {
        !           256:                max_y += ctrlmin.y + statmin.y + hscrsize.y;
        !           257:        }
        !           258:        wxSize maxsize(max_x, max_y);
        !           259: 
        !           260:        if (newp) *newp = newsize;
        !           261:        if (minp) *minp = minsize;
        !           262:        if (maxp) *maxp = maxsize;
        !           263:        if (incp) *incp = wxDefaultSize;
        !           264:        return true;
        !           265: }
        !           266: 
        !           267: bool
        !           268: WXScreenWindow::Layout()
        !           269: {
        !           270:        if (MyLayout() == false) {
        !           271:                DPRINTF("%s.Layout false\n", __func__);
        !           272:                // sizer があるので呼ばないといけない。
        !           273:                BaseLayout();
        !           274: 
        !           275:                // コントロールを再配置。
        !           276:                const wxSize client = GetClientSize();
        !           277:                const wxSize& ctrlsize = ctrlpanel->GetSize();
        !           278:                const wxSize& statsize = statuspanel->GetSize();
        !           279:                const wxSize& vscrsize = vscroll->GetSize();
        !           280:                const wxSize& hscrsize = hscroll->GetSize();
        !           281:                DPRINTF("%s.Layout client=(%d,%d)\n", __func__, client.x, client.y);
        !           282:                DPRINTF("%s.Layout vscrsize=(%d,%d) hscrsize=(%d,%d)\n", __func__,
        !           283:                        vscrsize.x, vscrsize.y, hscrsize.x, hscrsize.y);
        !           284:                ctrlpanel->SetSize(0, 0, client.x, ctrlsize.y);
        !           285:                statuspanel->SetSize(0, ctrlsize.y, statsize.x, statsize.y);
        !           286:                int view_y = ctrlsize.y + statsize.y;
        !           287:                int view_w = client.x - vscrsize.x;
        !           288:                int view_h = client.y - ctrlsize.y - statsize.y - hscrsize.y;
        !           289:                viewpanel->SetSize(0, view_y, view_w, view_h);
        !           290:                vscroll->SetSize(view_w, view_y, vscrsize.x, view_h);
        !           291:                hscroll->SetSize(0, view_y + view_h, view_w, hscrsize.y);
        !           292:                corner->SetSize(view_w, view_y + view_h, hscrsize.x, vscrsize.y);
        !           293:                DPRINTF("%s.Layout view=(%d,%d,%d,%d)\n", __func__,
        !           294:                        viewpanel->GetPosition().x,
        !           295:                        viewpanel->GetPosition().y,
        !           296:                        viewpanel->GetSize().x,
        !           297:                        viewpanel->GetSize().y);
        !           298: 
        !           299:                // ステータスパネル右に空き地が出来るなら埋める。
        !           300:                if (statsize.x < client.x) {
        !           301:                        spacer->SetSize(statsize.x, ctrlsize.y,
        !           302:                                client.x - statsize.x, statsize.y);
        !           303:                        spacer->Show();
        !           304:                } else {
        !           305:                        spacer->Hide();
        !           306:                }
        !           307: 
        !           308:                SetScroll();
        !           309: 
        !           310:                DPRINTF("%s.Layout false done\n", __func__);
        !           311:        }
        !           312: 
        !           313:        return true;
        !           314: }
        !           315: 
        !           316: // 倍率変更イベント
        !           317: void
        !           318: WXScreenWindow::OnScale(wxCommandEvent& event)
        !           319: {
        !           320:        int scale_index = event.GetSelection();
        !           321: 
        !           322:        DoScale(scale_index);
        !           323: }
        !           324: 
        !           325: // 倍率変更処理
        !           326: void
        !           327: WXScreenWindow::DoScale(int scale_index)
        !           328: {
        !           329:        DPRINTF("%s index=%d\n", __method__, scale_index);
        !           330:        int scale_ = 1 << scale_index;
        !           331:        viewpanel->SetScale(scale_);
        !           332: 
        !           333:        SetScroll();
        !           334: 
        !           335:        wxSize maxsize;
        !           336:        GetMySizeHints(NULL, NULL, &maxsize, NULL);
        !           337:        SetMaxClientSize(maxsize);
        !           338: }
        !           339: 
        !           340: // タイマーイベント
        !           341: void
        !           342: WXScreenWindow::OnTimer(wxTimerEvent& event)
        !           343: {
        !           344:        viewpanel->Refresh();
        !           345: 
        !           346:        // この位置の情報で screen を更新
        !           347:        TextScreen& screen = statuspanel->GetScreen();
        !           348:        const wxPoint& cursor = viewpanel->GetCursor();
        !           349: 
        !           350:        // UpdateInfo() は cursor が範囲外の時の描画も行っている。
        !           351:        UpdateInfo(screen, cursor.x, cursor.y);
        !           352:        statuspanel->Refresh();
        !           353: }
        !           354: 
        !           355: // 縦スクロールバーの位置を設置する。
        !           356: // (パネルからマウスホイールイベントで呼ばれる)
        !           357: void
        !           358: WXScreenWindow::SetVScrollPosition(int pos)
        !           359: {
        !           360:        vscroll->SetThumbPosition(pos);
        !           361: }
        !           362: 
        !           363: // サイズ変更処理。パネルサイズと倍率が変わったら呼ぶこと。
        !           364: // 倍率が変わった場合もスクロールバーの再設定とかがあるため。
        !           365: void
        !           366: WXScreenWindow::SetScroll()
        !           367: {
        !           368:        wxSize viewsize = viewpanel->GetSize();
        !           369:        int virtual_width  = viewpanel->GetVirtualWidth();
        !           370:        int virtual_height = viewpanel->GetVirtualHeight();
        !           371:        Rect& view = viewpanel->view;
        !           372: 
        !           373:        DPRINTF("%s: viewsize=(%d,%d)\n", __method__, viewsize.x, viewsize.y);
        !           374: 
        !           375:        // スクロールバーが右端まで行っている場合は右を固定したように見せる。
        !           376:        // ただし全体が見えている場合は除く。
        !           377: 
        !           378:        if (view.x > 0 &&
        !           379:            (view.x + view.w == virtual_width ||
        !           380:             view.x + viewsize.x >= virtual_width))
        !           381:        {
        !           382:                view.x = virtual_width - viewsize.x;
        !           383:                if (view.x < 0) {
        !           384:                        view.x = 0;
        !           385:                }
        !           386:        }
        !           387:        view.w = viewsize.x;
        !           388: 
        !           389:        // 下端も同様
        !           390:        if (view.y > 0 &&
        !           391:            (view.y + view.h >= virtual_height ||
        !           392:             view.y + viewsize.y >= virtual_height))
        !           393:        {
        !           394:                view.y = virtual_height - viewsize.y;
        !           395:                if (view.y < 0) {
        !           396:                        view.y = 0;
        !           397:                }
        !           398:        }
        !           399:        view.h = viewsize.y;
        !           400: 
        !           401:        // スクロールバー(横)を再設定
        !           402:        assert(hscroll);
        !           403:        int hpos = view.x;
        !           404:        int hthumbsize = view.w;
        !           405:        int hrange = virtual_width;
        !           406:        int hpagesize = view.w;
        !           407:        hscroll->SetScrollParam(hpos, hthumbsize, hrange, hpagesize);
        !           408: 
        !           409:        // スクロールバー(縦)を再設定
        !           410:        assert(vscroll);
        !           411:        int vpos = view.y;
        !           412:        int vthumbsize = view.h;
        !           413:        int vrange = virtual_height;
        !           414:        int vpagesize = view.h;
        !           415:        vscroll->SetScrollParam(vpos, vthumbsize, vrange, vpagesize);
        !           416: }

unix.superglobalmegacorp.com

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