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