|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.