Annotation of nono/wx/wxmonitor.cpp, revision 1.1.1.10

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: 
                      7: //
1.1.1.7   root        8: // モニター
1.1       root        9: //
                     10: 
1.1.1.6   root       11: #include "wxmonitor.h"
1.1.1.7   root       12: #include "wxmainframe.h"
1.1.1.9   root       13: #include "monitor.h"
1.1.1.7   root       14: 
1.1.1.10! root       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: 
1.1.1.7   root       23: //
                     24: // モニターパネル
                     25: //
                     26: 
                     27: // イベントテーブル
                     28: wxBEGIN_EVENT_TABLE(WXMonitorPanel, inherited)
                     29:        EVT_TIMER(wxID_ANY, WXMonitorPanel::OnTimer)
                     30: wxEND_EVENT_TABLE()
                     31: 
                     32: // コンストラクタ
1.1.1.9   root       33: WXMonitorPanel::WXMonitorPanel(wxWindow *parent, Monitor *monitor_)
                     34:        : inherited(parent, monitor_->GetSize())
1.1.1.7   root       35:        , monitor(monitor_)
                     36: {
                     37:        timer.SetOwner(this);
                     38: 
                     39:        // 現在の設定値を適用
1.1.1.8   root       40:        auto mainframe = dynamic_cast<WXMainFrame*>(GetParent()->GetParent());
                     41:        SetRate(mainframe->GetMonitorRate());
1.1.1.7   root       42: 
                     43:        // 最初に一回描画を起こす
                     44:        wxTimerEvent dummy(timer);
                     45:        AddPendingEvent(dummy);
                     46: }
                     47: 
                     48: // デストラクタ
                     49: WXMonitorPanel::~WXMonitorPanel()
                     50: {
                     51: }
                     52: 
                     53: // タイマーイベント
                     54: void
                     55: WXMonitorPanel::OnTimer(wxTimerEvent& event)
                     56: {
                     57:        DoRefresh();
                     58: }
                     59: 
                     60: // 画面を更新して再描画する。
                     61: //
                     62: // 通常はタイマーイベントにより更新間隔ごとに呼ばれるが、
                     63: // ユーザ操作により画面の更新が必要ならその都度直接これを呼ぶ。
                     64: void
                     65: WXMonitorPanel::DoRefresh()
                     66: {
                     67:        // モニタースクリーンを更新して
                     68:        MONITOR_UPDATE(monitor, screen);
                     69: 
                     70:        // 必要なら再描画
                     71:        if (screen.GetBuf() != prevbuf) {
                     72:                Refresh();
                     73:        }
                     74: }
                     75: 
                     76: // 画面更新頻度を Hz で設定する。
                     77: void
                     78: WXMonitorPanel::SetRate(int hz)
                     79: {
                     80:        timer.Start(1000 / hz);
                     81: }
                     82: 
                     83: 
                     84: //
                     85: // モニターウィンドウ
                     86: //
1.1.1.6   root       87: 
1.1       root       88: // コンストラクタ
1.1.1.5   root       89: WXMonitorWindow::WXMonitorWindow(wxWindow *parent, const wxString& name,
1.1.1.9   root       90:        Monitor *monitor_)
1.1.1.5   root       91:        : inherited(parent, wxID_ANY, name)
1.1       root       92: {
1.1.1.7   root       93:        // モニタパネル
                     94:        monpanel = new WXMonitorPanel(this, monitor_);
1.1.1.10! root       95:        Fit();
1.1       root       96: }
                     97: 
                     98: // デストラクタ
                     99: WXMonitorWindow::~WXMonitorWindow()
                    100: {
                    101: }
1.1.1.7   root      102: 
                    103: 
                    104: //
                    105: // 縦スクロールバー付きモニタウィンドウ
                    106: //
                    107: 
                    108: // コンストラクタ
                    109: WXScrollMonitorWindow::WXScrollMonitorWindow(wxWindow *parent,
1.1.1.9   root      110:        const wxString& name, Monitor *monitor_)
1.1.1.7   root      111:        : inherited(parent, wxID_ANY, name, DEFAULT_STYLE | wxRESIZE_BORDER)
                    112: {
1.1.1.10! root      113:        DPRINTF("%s begin\n", __method__);
        !           114: 
1.1.1.7   root      115:        // +--------------+---------+
                    116:        // | MonitorPanel | VScroll |
                    117:        // +--------------+---------+
                    118: 
                    119:        // モニタパネル
                    120:        monpanel = new WXMonitorPanel(this, monitor_);
                    121: 
                    122:        // スクロールバー
                    123:        vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL);
                    124: 
1.1.1.10! root      125:        // Sizer 使わず自前でレイアウトする。
        !           126:        SetAutoLayout(true);
1.1.1.7   root      127: 
                    128:        // ウィンドウサイズを確定させる
1.1.1.10! root      129:        FontChanged();
1.1.1.7   root      130: 
                    131:        // スクロールのために (パネル領域での) MouseWheel イベントもここで
                    132:        // 受け取りたい。スクロールバー上のマウスホイール操作はスクロールバーが
                    133:        // 処理しているので問題ないが、パネル領域でのマウスホイール操作はここ
                    134:        // (wxFrame)ではなくパネルに対して飛んでくる。
                    135:        // ここで一緒に処理したほうが楽なので、こちらに回す。
                    136:        monpanel->Connect(wxEVT_MOUSEWHEEL,
                    137:                wxMouseEventHandler(WXScrollMonitorWindow::OnMouseWheel), NULL, this);
                    138: 
                    139:        // スクロールバーからの位置変更通知
                    140:        vscroll->Connect(NONO_EVT_SCROLL,
                    141:                wxScrollEventHandler(WXScrollMonitorWindow::OnScroll), NULL, this);
1.1.1.10! root      142:        DPRINTF("%s done\n", __method__);
1.1.1.7   root      143: }
                    144: 
                    145: // デストラクタ
                    146: WXScrollMonitorWindow::~WXScrollMonitorWindow()
                    147: {
                    148: }
                    149: 
1.1.1.10! root      150: void
        !           151: WXScrollMonitorWindow::FontChanged()
1.1.1.7   root      152: {
1.1.1.10! root      153:        monpanel->FontChanged();
        !           154:        vscroll->FontChanged();
        !           155:        DPRINTF("%s %d\n", __method__, monpanel->GetFontHeight());
        !           156: 
        !           157:        Fit();
1.1.1.7   root      158: }
                    159: 
                    160: void
1.1.1.10! root      161: WXScrollMonitorWindow::Fit()
1.1.1.7   root      162: {
1.1.1.10! root      163:        // inherited::Fit() は呼ばずに自力で行う。
1.1.1.7   root      164: 
1.1.1.10! root      165:        wxSize newsize = DoSizeHints();
        !           166: #if defined(WINDOW_DEBUG)
        !           167:        wxSize newwin = ClientToWindowSize(newsize);
        !           168:        printf("%s (%d,%d) client=(%d,%d)\n", __method__,
        !           169:                newwin.x, newwin.y, newsize.x, newsize.y);
        !           170: #endif
        !           171:        SetClientSize(newsize);
        !           172: }
1.1.1.7   root      173: 
1.1.1.10! root      174: bool
        !           175: WXScrollMonitorWindow::Layout()
        !           176: {
        !           177:        // inherited::Layout() は(実質何もしないので)、呼ばずに自力で行う。
        !           178: 
        !           179:        wxSize client = GetClientSize();
        !           180:        const wxSize win = GetSize();
        !           181:        const wxSize margin = win - client;
        !           182:        const wxSize vsize = vscroll->GetSize();
        !           183:        const wxSize monsize = monpanel->GetSize();
        !           184: #if defined(WINDOW_DEBUG)
        !           185:        const wxSize min = GetMinClientSize();
        !           186:        int py = client.y
        !           187:                - monpanel->GetPaddingTop() - monpanel->GetPaddingBottom();
        !           188:        int height = monpanel->GetFontHeight();
        !           189:        int row = (height != 0) ? (py / height) : 0;
        !           190:        int res = (height != 0) ? (py % height) : 0;
        !           191:        wxSize minwin = GetMinSize();
        !           192:        printf("%s begin: margin=(%d,%d) shown=%d\n", __method__,
        !           193:                margin.x, margin.y, IsShown());
        !           194:        printf("%s  WinSize   =(%d,%d) MinWin   =(%d,%d)\n", __method__,
        !           195:                win.x, win.y, minwin.x, minwin.y);
        !           196:        printf("%s  ClientSize=(%d,%d) MinClient=(%d,%d)\n", __method__,
        !           197:                client.x, client.y, min.x, min.y);
        !           198:        printf("%s  mon=(%d,%d) vscroll=(%d,%d), row=%d%s\n", __method__,
        !           199:                monsize.x, monsize.y, vsize.x, vsize.y,
        !           200:                row, (res == 0 ? "" : "+"));
        !           201: #endif
        !           202: 
        !           203:        if (oldmargin != margin) {
        !           204:                // ウィンドウマネージャ管轄のサイズが変わったので最小サイズを再設定。
        !           205:                // ここでは出来ないのでこの関数を抜けた後 CallAfter 内で設定する。
        !           206:                layout_pass2 = true;
        !           207:                oldmargin = margin;
        !           208:                CallAfter([this]() {
        !           209:                        DoSizeHints();
        !           210:                });
        !           211:                DPRINTF("%s done(pass1)\n", __method__);
        !           212:                return true;
        !           213:        } else if (layout_pass2) {
        !           214:                // SetSizeHints() 後に呼ばれるところ。
        !           215:                // なぜか設定したサイズと変わっている(ことがある?)ので、その場合は
        !           216:                // 仕方ないのでここで元の要求サイズに再設定する。
        !           217:                // ウィンドウマネージャによっては表示サイズが変わらない(?)ので
        !           218:                // Hide()/Show() で叩き起こすと直るようだ??。
        !           219:                layout_pass2 = false;
        !           220:                client.y = monsize.y;
        !           221:                DPRINTF("%s SetClientSize (%d,%d)\n", __method__, client.x, client.y);
        !           222:                SetClientSize(client);
        !           223:                Hide();
        !           224:                Show();
        !           225:                DPRINTF("%s done(pass2)\n", __method__);
        !           226:                return true;
        !           227:        }
        !           228: 
        !           229:        // コントロールを配置。
        !           230:        int mon_width  = client.x - vsize.x;
        !           231:        int mon_height = client.y;
        !           232:        // 最低でも 1px ないと GTK とかに怒られる。
        !           233:        if (mon_width < 1) {
        !           234:                mon_width = 1;
        !           235:        }
        !           236:        if (mon_height < 1) {
        !           237:                mon_height = 1;
        !           238:        }
        !           239: 
        !           240:        monpanel->SetSize(0, 0, mon_width, mon_height);
        !           241:        vscroll->SetSize(mon_width, 0, vsize.x, mon_height);
        !           242: 
        !           243:        // スクロールバーを再設定。
        !           244:        // 今の所ヘッダが常に1行ある。
        !           245:        static int HEADLINES = 1;
1.1.1.7   root      246:        int pos = (int)monpanel->GetUserData();
                    247:        int thumbsize = monpanel->GetRow() - HEADLINES;
1.1.1.9   root      248:        int range = monpanel->GetMonitor()->GetMaxHeight() - HEADLINES;
1.1.1.7   root      249:        int pagesize = thumbsize - 1;
                    250:        if (pos > range - thumbsize) {
                    251:                pos = range - thumbsize;
                    252:                DoScroll(pos);
                    253:        }
                    254:        vscroll->SetScrollParam(pos, thumbsize, range, pagesize);
1.1.1.10! root      255: 
        !           256:        DPRINTF("%s done\n", __method__);
        !           257: 
        !           258:        return true;
        !           259: }
        !           260: 
        !           261: // クライアントサイズと最大/最小サイズを計算する。
        !           262: // SetSizeHints() を実行し、設定すべきクライアントサイズを返す。
        !           263: wxSize
        !           264: WXScrollMonitorWindow::DoSizeHints()
        !           265: {
        !           266:        auto psize = monpanel->GetSize();
        !           267:        auto vsize = vscroll->GetSize();
        !           268: 
        !           269:        // 幅は monpanel 幅 + スクロールバーの幅、高さは monpanel の高さで決まる。
        !           270:        // monpanel には四辺に Padding があることに注意。
        !           271:        int x = psize.x + vsize.x;
        !           272:        int min_y = std::max(vscroll->GetMinSize().y,
        !           273:                monpanel->GetScreenHeight(1));
        !           274:        int new_y = std::max(psize.y, min_y);
        !           275:        wxSize minsize(x, min_y);
        !           276:        wxSize maxsize(x, GetMaxClientSize().y);
        !           277:        wxSize incsize(0, monpanel->GetFontHeight());
        !           278:        wxSize minwin = ClientToWindowSize(minsize);
        !           279:        wxSize maxwin = ClientToWindowSize(maxsize);
        !           280:        wxSize newsize(x, new_y);
        !           281:        DPRINTF("%s MinWin=(%d,%d) RecommendClient=(%d,%d)\n", __method__,
        !           282:                minwin.x, minwin.y, newsize.x, newsize.y);
        !           283:        SetSizeHints(minwin, maxwin, incsize);
        !           284: 
        !           285:        return newsize;
1.1.1.7   root      286: }
                    287: 
                    288: // マウスホイールイベント (WXTextScreen 上で起きたやつをこっちに回してある)
                    289: void
                    290: WXScrollMonitorWindow::OnMouseWheel(wxMouseEvent& event)
                    291: {
                    292:        // GetWheelRotation() は上(奥)向きに回すと +120、下(手前)に回すと -120。
                    293:        // どこの決まりか知らんけど、スクロールバーのほうはホイール1段階で3行
                    294:        // スクロールするのでそれに合わせる。
                    295:        int pos = (int)monpanel->GetUserData();
                    296:        pos = pos - event.GetWheelRotation() / 40;
                    297: 
                    298:        int maxpos = vscroll->GetRange() - vscroll->GetThumbSize();
                    299:        if (pos < 0)
                    300:                pos = 0;
                    301:        if (pos > maxpos)
                    302:                pos = maxpos;
                    303: 
                    304:        DoScroll(pos);
                    305:        // スクロールバーの位置を追従
                    306:        vscroll->SetThumbPosition(pos);
                    307: }
                    308: 
                    309: // スクロールバーからの通知イベント
                    310: void
                    311: WXScrollMonitorWindow::OnScroll(wxScrollEvent& event)
                    312: {
                    313:        DoScroll(event.GetPosition());
                    314: }
                    315: 
                    316: // スクロール処理 (OnScroll() と OnMouseWheel() から呼ばれる)
                    317: void
                    318: WXScrollMonitorWindow::DoScroll(int pos)
                    319: {
                    320:        // userdata が表示開始位置になっている
                    321:        monpanel->SetUserData(pos);
                    322:        monpanel->DoRefresh();
                    323: }

unix.superglobalmegacorp.com

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