YSTest: ShlReader.cpp 源文件

YSTest PreAlpha_b400_20130424 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

全部 类 命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义 组 页
ShlReader.cpp
浏览该文件的文档.
1 ﻿/*
2 Copyright by FrankHB 2011 - 2013.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "ShlReader.h"
29 #include "ShlExplorer.h"
30 #include <NPL/Lexical.h>
31
32 YSL_BEGIN_NAMESPACE(YReader)
33
34 namespace
35 {
36 // ResourceMap GlobalResourceMap;
37
38 using namespace Text;
39
40 /*
41 \brief 文本阅读器菜单项。
42 \since build 303
43 */
44 enum MNU_READER : Menu::IndexType
45 {
46 MR_Return = 0,
47 MR_Setting,
48 MR_FileInfo,
50 MR_Bookmark,
51 MR_LineUp,
52 MR_LineDown,
53 MR_ScreenUp,
54 MR_ScreenDown
55 };
56
57 } // unnamed namespace;
58
59
60 ReaderBox::ReaderBox(const Rect& r)
61 : Control(r),
62 btnMenu({4, 12, 16, 16}), btnSetting({24, 12, 16, 16}),
63 btnInfo({44, 12, 16, 16}), btnBookmark({64, 12, 16, 16}),
64 btnReturn({84, 12, 16, 16}),
65 btnPrev({104, 12, 16, 16}), btnNext({124, 12, 16, 16}),
66 pbReader({4, 0, 248, 8}), lblProgress({216, 12, 40, 16})
67 {
68 Background = nullptr,
69 SetRenderer(make_unique<BufferedRenderer>()),
70 unseq_apply(ContainerSetter(*this), btnMenu, btnSetting, btnInfo,
71 btnBookmark, btnReturn, btnPrev, btnNext, pbReader, lblProgress);
72 SetBufferRendererAndText(btnMenu, u"M"),
73 SetBufferRendererAndText(btnSetting, u"S"),
74 SetBufferRendererAndText(btnInfo, u"I"),
75 SetBufferRendererAndText(btnBookmark, u"B"),
76 SetBufferRendererAndText(btnReturn, u"R"),
77 SetBufferRendererAndText(btnPrev, u"←"),
78 SetBufferRendererAndText(btnNext, u"→");
79 pbReader.ForeColor = Color(192, 192, 64),
80 lblProgress.SetRenderer(make_unique<BufferedRenderer>()),
81 lblProgress.Background = nullptr,
82 lblProgress.Font.SetSize(12),
83 InitializeProgress();
84 }
85
86 void
87 ReaderBox::InitializeProgress()
88 {
89 yunseq(lblProgress.Text = u"--%", lblProgress.ForeColor = ColorSpace::Blue);
90 }
91
92 void
93 ReaderBox::UpdateData(DualScreenReader& reader)
94 {
95 if(YB_LIKELY(reader.IsBufferReady()))
96 {
97 const auto ts(reader.GetTextSize());
98
99 if(YB_LIKELY(ts != 0))
100 {
101 const auto tp(reader.GetTopPosition());
102 char str[5];
103
104 std::sprintf(str, "%2u%%", tp * 100 / ts);
105 yunseq(lblProgress.Text = str,
106 lblProgress.ForeColor = reader.GetBottomPosition() == ts
107 ? ColorSpace::Green : ColorSpace::Fuchsia);
108 pbReader.SetMaxValue(ts),
109 pbReader.SetValue(tp);
110 }
111 else
112 InitializeProgress();
113 }
114 else
115 InitializeProgress();
116 Invalidate(pbReader),
117 Invalidate(lblProgress);
118 }
119
120
121 TextInfoBox::TextInfoBox()
122 : DialogBox({32, 32, 200, 108}),
123 lblEncoding({4, 20, 192, 18}),
124 lblSize({4, 40, 192, 18}),
125 lblTop({4, 60, 192, 18}),
126 lblBottom({4, 80, 192, 18})
127 {
128 unseq_apply(ContainerSetter(*this), lblEncoding, lblSize);
129 FetchEvent<TouchMove>(*this) += OnTouchMove_Dragging;
130 }
131
132 void
133 TextInfoBox::Refresh(PaintEventArgs&& e)
134 {
135 DialogBox::Refresh(std::move(e));
136
137 unseq_apply(ChildPainter(e), lblEncoding, lblSize, lblTop, lblBottom);
138 e.ClipArea = Rect(e.Location, GetSizeOf(*this));
139 }
140
141 void
142 TextInfoBox::UpdateData(DualScreenReader& reader)
143 {
144 yunseq(lblEncoding.Text = "Encoding: " + to_string(reader.GetEncoding())
145 + ';',
146 lblSize.Text = "Size: " + to_string(reader.GetTextSize()) + " B;",
147 lblTop.Text = "Top: " + to_string(reader.GetTopPosition()) + " B;",
148 lblBottom.Text = "Bottom: " + to_string(reader.GetBottomPosition())
149 + " B;");
150 Invalidate(lblEncoding),
151 Invalidate(lblSize);
152 }
153
154
155 FileInfoPanel::FileInfoPanel()
156 : Panel(Size(MainScreenWidth, MainScreenHeight)),
157 lblPath({8, 20, 240, 16}),
158 lblSize({8, 40, 240, 16}),
159 lblAccessTime({8, 60, 240, 16}),
160 lblModifiedTime({8, 80, 240, 16}),
161 lblOperations({8, 120, 240, 16})
162 {
163 Background = SolidBrush(ColorSpace::Silver);
164 #if YCL_DS
165 lblOperations.Text = "<↑↓> 滚动一行 <LR> 滚动一屏 <B>退出";
166 #else
167 lblOperations.Text = "<↑↓> 滚动一行 <LR> 滚动一屏 <Esc>退出";
168 #endif
169 AddWidgets(*this, lblPath, lblSize, lblAccessTime, lblModifiedTime,
170 lblOperations);
171 }
172
173
174 ShlReader::ShlReader(const IO::Path& pth,
175 const shared_ptr<Desktop>& h_dsk_up, const shared_ptr<Desktop>& h_dsk_dn)
176 : ShlDS(h_dsk_up, h_dsk_dn),
177 CurrentPath(pth), fBackgroundTask(), bExit()
178 {}
179
180 void
181 ShlReader::Exit()
182 {
183 if(bExit)
184 return;
185 bExit = true;
186 fBackgroundTask = nullptr;
187 // TODO: Use template %SetShellToNew.
188 // SetShellToNew<ShlExplorer>();
189 const auto h_up(GetDesktopUpHandle());
190 const auto h_dn(GetDesktopDownHandle());
191
192 PostMessage<SM_TASK>(0xF8, [=]{
193 ResetDSDesktops(*h_up, *h_dn);
194 NowShellTo(ystdex::make_shared<ShlExplorer>(CurrentPath / u"..",
195 h_up, h_dn));
196 });
197 }
198
199 BookmarkList
200 ShlReader::LoadBookmarks(const string& group)
201 {
202 BookmarkList bookmarks;
203
204 try
205 {
206 // TODO: Complete unexpected input handling.
207 ystdex::split(Access<string>(FetchGlobalInstance().Root
208 .GetNode("YReader")["Bookmarks"].GetNode('"' + NPL::MakeEscape(
209 group) + '"')), static_cast<int(&)(int)>(std::isspace),
210 [&](string::iterator b, string::iterator e){
211 bookmarks.push_back(std::stoi(ystdex::ltrim(string(b, e))));
212 });
213 }
214 catch(std::exception& e) // TODO: Logging.
215 {}
216 return std::move(bookmarks);
217 }
218
219 ReaderSetting
220 ShlReader::LoadGlobalConfiguration()
221 {
222 try
223 {
224 return ReaderSetting((FetchGlobalInstance().Root %= LoadConfiguration()
225 .GetNode("YReader")).GetNode("ReaderSetting").GetContainer());
226 }
227 catch(std::exception& e) // TODO: Logging.
228 {}
229 return {};
230 }
231
232 void
233 ShlReader::OnInput()
234 {
235 PostMessage<SM_PAINT>(0xE0, nullptr);
236 if(fBackgroundTask)
237 PostMessage<SM_TASK>(0x20, fBackgroundTask);
238 }
239
240 void
241 ShlReader::SaveBookmarks(const string& group, const BookmarkList& bookmarks)
242 {
243 try
244 {
245 FetchGlobalInstance().Root.GetNode("YReader")["Bookmarks"]
246 ['"' + NPL::MakeEscape(group) + '"'].Value = [&]{
247 string str;
248
249 for(const auto& pos : bookmarks)
250 {
251 str += to_string(pos);
252 str += ' ';
253 }
254 return std::move(str);
255 }();
256 }
257 catch(std::exception& e) // TODO: Logging.
258 {}
259 }
260
261 void
262 ShlReader::SaveGlobalConfiguration(const ReaderSetting& rs)
263 {
264 try
265 {
266 auto& root(FetchGlobalInstance().Root);
267
268 root["YReader"]["ReaderSetting"].Value = ValueNode::Container(rs);
269 SaveConfiguration(root);
270 }
271 catch(std::exception& e) // TODO: Logging.
272 {}
273 }
274
275
276 ShlTextReader::BaseSession::BaseSession(ShlTextReader& shl)
277 : GShellSession<ShlTextReader>(shl)
278 {
279 shl.StopAutoScroll(),
280 Hide(shl.boxReader),
281 Hide(shl.boxTextInfo);
282 }
283 ShlTextReader::BaseSession::~BaseSession()
284 {
285 auto& shl(GetShell());
286
287 shl.reader.SetVisible(true),
288 shl.boxReader.UpdateData(shl.reader),
289 shl.boxTextInfo.UpdateData(shl.reader),
290 Show(shl.boxReader);
291 }
292
293
294 ShlTextReader::SettingSession::SettingSession(ShlTextReader& shl)
295 : BaseSession(shl)
296 {
297 auto& dsk_up(shl.GetDesktopUp());
298 auto& dsk_dn(shl.GetDesktopDown());
299 auto& reader(shl.reader);
300 auto& CurrentSetting(shl.CurrentSetting);
301 auto& pnlSetting(shl.pnlSetting);
302
303 shl.reader.SetVisible(false),
304 yunseq(CurrentSetting.UpColor = dsk_up.Background
305 .target<SolidBrush>()->Color, CurrentSetting.DownColor
306 = dsk_dn.Background.target<SolidBrush>()->Color,
307 CurrentSetting.FontColor = reader.GetColor(),
308 CurrentSetting.Font = reader.GetFont());
309 AddWidgets(dsk_up, pnlSetting.lblAreaUp, pnlSetting.lblAreaDown);
310 {
311 using ystdex::get_key;
312
313 size_t i(std::find(Encodings | get_key,
314 (Encodings + arrlen(Encodings)) | get_key,
315 reader.GetEncoding()) - Encodings);
316
317 if(i == arrlen(Encodings))
318 i = 0;
319 yunseq(pnlSetting.lblAreaDown.Text = FetchEncodingString(i),
320 pnlSetting.ddlEncoding.Text = Encodings[i].second);
321 }
322 Show(pnlSetting << CurrentSetting);
323 }
324 ShlTextReader::SettingSession::~SettingSession()
325 {
326 auto& shl(GetShell());
327
328 RemoveWidgets(shl.GetDesktopUp(),
329 shl.pnlSetting.lblAreaUp, shl.pnlSetting.lblAreaDown);
330 }
331
332
333 ShlTextReader::BookmarkSession::BookmarkSession(ShlTextReader& shl)
334 : BaseSession(shl)
335 {
336 shl.pnlBookmark.LoadBookmarks();
337 Show(shl.pnlBookmark);
338 }
339
340
341 ShlTextReader::ShlTextReader(const IO::Path& pth,
342 const shared_ptr<Desktop>& h_dsk_up, const shared_ptr<Desktop>& h_dsk_dn)
343 : ShlReader(pth, h_dsk_up, h_dsk_dn),
344 LastRead(ystdex::parameterize_static_object<ReadingList>()),
345 CurrentSetting(LoadGlobalConfiguration()), tmrScroll(
346 CurrentSetting.GetTimerSetting()), tmrInput(), reader(),
347 boxReader({0, 160, 256, 32}), boxTextInfo(), pnlSetting(),
348 pTextFile(), mhMain(GetDesktopDown()),
349 pnlBookmark(LoadBookmarks(pth.GetNativeString()), *this), session_ptr()
350 {
351 using ystdex::get_key;
352
353 const auto exit_session([this](TouchEventArgs&&){
354 session_ptr.reset();
355 });
356
357 SetVisibleOf(boxReader, false),
358 SetVisibleOf(boxTextInfo, false),
359 SetVisibleOf(pnlSetting, false),
360 SetVisibleOf(pnlBookmark, false);
361 yunseq(
362 reader.ViewChanged = [this]{
363 if(IsVisible(boxReader))
364 boxReader.UpdateData(reader);
365 if(IsVisible(boxTextInfo))
366 boxTextInfo.UpdateData(reader);
367 },
368 mhMain.Roots[&boxReader.btnMenu] = 1U,
369 FetchEvent<Click>(boxReader.btnMenu) += [this](TouchEventArgs&&){
370 if(mhMain.IsShowing(1U))
371 mhMain.Hide(1U);
372 else
373 {
374 const auto& pt(LocateForWidget(GetDesktopDown(),
375 boxReader.btnMenu));
376
377 ShowMenu(1U, Point(pt.X, pt.Y - mhMain[1U].GetHeight()));
378 }
379 },
380 FetchEvent<Click>(boxReader.btnSetting) += [this](TouchEventArgs&&){
381 Execute(MR_Setting);
382 },
383 FetchEvent<Click>(boxReader.btnInfo) += [this](TouchEventArgs&&){
384 Execute(MR_FileInfo);
385 },
386 FetchEvent<Click>(boxReader.btnBookmark) += [this](TouchEventArgs&&){
387 Execute(MR_Bookmark);
388 },
389 FetchEvent<Click>(boxReader.btnReturn) += [this](TouchEventArgs&&){
390 Execute(MR_Return);
391 },
392 FetchEvent<Click>(boxReader.btnPrev) += [this](TouchEventArgs&&){
393 UpdateReadingList(true);
394 },
395 FetchEvent<Click>(boxReader.btnNext) += [this](TouchEventArgs&&){
396 UpdateReadingList(false);
397 },
398 FetchEvent<TouchDown>(boxReader.pbReader) += [this](TouchEventArgs&& e){
399 const auto s(reader.GetTextSize());
400
401 if(YB_LIKELY(s != 0))
402 Locate(e.X * s / boxReader.pbReader.GetWidth());
403 },
404 FetchEvent<Paint>(boxReader.pbReader) += [this](PaintEventArgs&& e){
405 auto& pb(boxReader.pbReader);
406 const auto mval(pb.GetMaxValue());
407 const auto w(pb.GetWidth() - 2);
408 auto& pt(e.Location);
409
410 FillRect(e.Target, Point(pt.X + 1 + round(pb.GetValue() * w / mval),
411 pt.Y + 1), Size(round((reader.GetBottomPosition()
412 - GetReaderPosition()) * w / mval), pb.GetHeight() - 2),
413 ColorSpace::Yellow);
414 },
415 FetchEvent<Click>(pnlSetting.btnClose) += exit_session,
416 FetchEvent<Click>(pnlSetting.btnOK) += [&, this](TouchEventArgs&&){
417 pnlSetting >> CurrentSetting;
418 tmrScroll.SetInterval(CurrentSetting.GetTimerSetting());
419 Switch(pnlSetting.current_encoding),
420 reader.SetColor(CurrentSetting.FontColor),
421 reader.SetFont(CurrentSetting.Font);
422 reader.UpdateView();
423 yunseq(GetDesktopUp().Background = pnlSetting.lblAreaUp.Background,
424 GetDesktopDown().Background = pnlSetting.lblAreaDown.Background
425 );
426 if(IsVisible(boxReader))
427 for(auto pr(boxReader.GetChildren()); pr.first != pr.second;
428 ++pr.first)
429 if(dynamic_cast<BufferedRenderer*>(
430 &pr.first->GetRenderer()))
431 Invalidate(*pr.first);
432 },
433 FetchEvent<Click>(pnlSetting.btnOK) += exit_session,
434 FetchEvent<Click>(pnlBookmark.btnClose) += exit_session,
435 FetchEvent<Click>(pnlBookmark.btnOK) += [this](TouchEventArgs&&){
436 if(pnlBookmark.lbPosition.IsSelected() && Locate(pnlBookmark
437 .bookmarks[pnlBookmark.lbPosition.GetSelectedIndex()]))
438 boxReader.UpdateData(reader);
439 },
440 FetchEvent<Click>(pnlBookmark.btnOK) += exit_session
441 );
442 {
443 Menu& mnu(*(ynew Menu({}, shared_ptr<Menu::ListType>(new
444 Menu::ListType{"返回", "设置...", "文件信息...", "书签...",
445 "向上一行", "向下一行", "向上一屏", "向下一屏"}), 1u)));
446
447 mnu.GetConfirmed() += [this](IndexEventArgs&& e){
448 Execute(e.Value);
449 };
450 mhMain += mnu;
451 }
452 ResizeForContent(mhMain[1u]);
453
454 auto& dsk_up(GetDesktopUp());
455 auto& dsk_dn(GetDesktopDown());
456
457 reader.SetColor(CurrentSetting.FontColor),
458 reader.SetFont(CurrentSetting.Font),
459 yunseq(
460 dsk_up.Background = SolidBrush(CurrentSetting.UpColor),
461 dsk_dn.Background = SolidBrush(CurrentSetting.DownColor),
462 FetchEvent<Click>(dsk_dn).Add(*this, &ShlTextReader::OnClick),
463 FetchEvent<KeyDown>(dsk_dn).Add(*this, &ShlTextReader::OnKeyDown),
464 FetchEvent<KeyHeld>(dsk_dn) += OnEvent_Call<KeyDown>
465 );
466 reader.Attach(dsk_up, dsk_dn),
467 AddWidgets(dsk_dn, boxReader, boxTextInfo, pnlSetting, pnlBookmark);
468 LoadFile(pth);
469 LastRead.DropSubsequent();
470 UpdateButtons();
471 //置默认视图。
472 // TODO: Associate view setting state for user selection.
473 OnClick(TouchEventArgs(dsk_dn, 0));
474 RequestFocusCascade(dsk_dn);
475 }
476
477 ShlTextReader::~ShlTextReader()
478 {
479 SaveBookmarks(CurrentPath.GetNativeString(), pnlBookmark.bookmarks),
480 SaveGlobalConfiguration(CurrentSetting);
481 LastRead.Insert(CurrentPath, GetReaderPosition());
482 }
483
484 string
485 ShlTextReader::GetSlice(Bookmark::PositionType pos, string::size_type len)
486 {
487 return CopySliceFrom(reader.GetTextBufferRef(), pos, len);
488 }
489
490 void
491 ShlTextReader::Execute(IndexEventArgs::ValueType idx)
492 {
493 switch(idx)
494 {
495 case MR_Return:
496 Exit();
497 break;
498 case MR_Setting:
499 session_ptr.reset(new SettingSession(*this));
500 break;
501 case MR_Bookmark:
502 session_ptr.reset(new BookmarkSession(*this));
503 break;
504 case MR_FileInfo:
505 boxTextInfo.UpdateData(reader);
506 Show(boxTextInfo);
507 break;
508 case MR_LineUp:
509 reader.Execute(DualScreenReader::LineUpScroll);
510 break;
511 case MR_LineDown:
512 reader.Execute(DualScreenReader::LineDownScroll);
513 break;
514 case MR_ScreenUp:
515 reader.Execute(DualScreenReader::ScreenUpScroll);
516 break;
517 case MR_ScreenDown:
518 reader.Execute(DualScreenReader::ScreenDownScroll);
519 break;
520 }
521 }
522
523 void
524 ShlTextReader::LoadFile(const IO::Path& pth)
525 {
526 CurrentPath = pth;
527 pTextFile = make_unique<TextFile>(pth.GetNativeString().c_str(),
528 std::ios_base::in | std::ios_base::binary, CharSet::Null);
529 reader.LoadText(*pTextFile);
530
531 const auto text_size(reader.GetTextSize());
532
533 ystdex::erase_all_if(pnlBookmark.bookmarks, [&](Bookmark::PositionType pos){
534 return pos >= text_size;
535 });
536 }
537
538 bool
539 ShlTextReader::Locate(Bookmark::PositionType pos)
540 {
541 const auto s(reader.GetTextSize());
542
543 if(YB_LIKELY(s != 0))
544 {
545 const auto old_pos(GetReaderPosition());
546
547 reader.Locate(pos);
548 if(YB_LIKELY(old_pos != GetReaderPosition()))
549 {
550 LastRead.Insert(CurrentPath, old_pos);
551 LastRead.DropSubsequent();
552 UpdateButtons();
553 return true;
554 }
555 }
556 return false;
557 }
558
559 void
560 ShlTextReader::Scroll()
561 {
562 if(tmrScroll.IsActive())
563 if(YB_UNLIKELY(tmrScroll.Refresh()))
564 {
565 if(CurrentSetting.SmoothScroll)
566 reader.ScrollByPixel(1U);
567 else
568 reader.Execute(DualScreenReader::LineDownScroll);
569 }
570 }
571
572 void
573 ShlTextReader::ShowMenu(Menu::ID id, const Point& pt)
574 {
575 if(!mhMain.IsShowing(id))
576 {
577 auto& mnu(mhMain[id]);
578
579 mnu.ClearSelected();
580 switch(id)
581 {
582 case 1u:
583 mnu.SetItemEnabled(MR_LineUp, !reader.IsTextTop());
584 mnu.SetItemEnabled(MR_LineDown, !reader.IsTextBottom());
585 mnu.SetItemEnabled(MR_ScreenUp, !reader.IsTextTop());
586 mnu.SetItemEnabled(MR_ScreenDown, !reader.IsTextBottom());
587 }
588 SetLocationOf(mnu, pt);
589 mhMain.Show(id);
590 }
591 }
592
593 void
594 ShlTextReader::StopAutoScroll()
595 {
596 reader.AdjustScrollOffset(),
597 fBackgroundTask = nullptr,
598 Deactivate(tmrScroll);
599 }
600
601 void
602 ShlTextReader::Switch(Encoding enc)
603 {
604 if(enc != Encoding() && pTextFile && bool(*pTextFile)
605 && pTextFile->Encoding != enc)
606 {
607 pTextFile->Encoding = enc;
608 reader.LoadText(*pTextFile);
609 }
610 }
611
612 void
613 ShlTextReader::UpdateReadingList(bool is_prev)
614 {
615 LastRead.Insert(CurrentPath, GetReaderPosition());
616
617 const auto& bm(LastRead.Switch(is_prev));
618
619 if(bm.Path != CurrentPath)
620 LoadFile(bm.Path);
621 if(reader.IsBufferReady())
622 reader.Locate(bm.Position);
623 UpdateButtons();
624 }
625
626 void
627 ShlTextReader::UpdateButtons()
628 {
629 const auto pr(LastRead.CheckBoundary());
630
631 yunseq(Enable(boxReader.btnPrev, pr.first),
632 Enable(boxReader.btnNext, pr.second));
633 }
634
635 void
636 #if YCL_MINGW32
637 ShlTextReader::OnClick(TouchEventArgs&& e)
638 #else
639 ShlTextReader::OnClick(TouchEventArgs&&)
640 #endif
641 {
642 #if YCL_MINGW32
643 if(e.Keys[VK_RBUTTON])
644 {
645 ShowMenu(1U, e);
646 return;
647 }
648 #endif
649 if(tmrScroll.IsActive())
650 {
651 StopAutoScroll();
652 Deactivate(tmrScroll);
653 return;
654 }
655 if(IsVisible(boxReader))
656 {
657 Close(boxReader);
658 reader.Stretch(0);
659 }
660 else
661 {
662 Show(boxReader);
663 reader.Stretch(boxReader.GetHeight());
664 }
665 }
666
667 void
668 ShlTextReader::OnKeyDown(KeyEventArgs&& e)
669 {
670 using namespace Timers;
671 using namespace KeyCodes;
672
673 if(e.Strategy != RoutedEventArgs::Tunnel && !mhMain.IsShowing(1u)
674 && RepeatHeld(tmrInput, FetchGUIState().KeyHeldState,
675 TimeSpan(240), TimeSpan(60)))
676 {
677 const auto ntick(HighResolutionClock::now());
678
679 //这里可以考虑提供暂停，不调整视图。
680 if(tmrScroll.IsActive())
681 {
682 StopAutoScroll();
683 return;
684 }
685
686 const auto& k(e.GetKeys());
687
688 if(k.count() != 1)
689 return;
690 if(k[YCL_KEY_Start])
691 {
692 fBackgroundTask = std::bind(&ShlTextReader::Scroll, this);
693 tmrScroll.Reset();
694 Activate(tmrScroll);
695 return;
696 }
697 if(k[KeyCodes::Enter])
698 reader.UpdateView();
699 else if(k[Esc])
700 Exit();
701 else if(k[Up])
702 reader.Execute(DualScreenReader::LineUpScroll);
703 else if(k[Down])
704 reader.Execute(DualScreenReader::LineDownScroll);
705 else if(k[YCL_KEY(X)] || k[YCL_KEY(Y)])
706 {
707 auto size(reader.GetFont().GetSize());
708
709 e.Handled = true;
710 if(k[YCL_KEY(X)])
711 {
712 if(YB_LIKELY(size > Font::MinimalSize))
713 --size;
714 else
715 return;
716 }
717 else if(YB_LIKELY(size < Font::MaximalSize))
718 ++size;
719 else
720 return;
721 reader.SetFontSize(size);
722 reader.UpdateView();
723 }
724 else if(k[YCL_KEY(L)])
725 {
726 if(YB_LIKELY(reader.GetLineGap() != 0))
727 reader.SetLineGap(reader.GetLineGap() - 1);
728 }
729 else if(k[YCL_KEY(R)])
730 {
731 if(YB_LIKELY(reader.GetLineGap() != 12))
732 reader.SetLineGap(reader.GetLineGap() + 1);
733 }
734 else if(k[Left])
735 // else if(k[PgUp])
736 reader.Execute(DualScreenReader::ScreenUpScroll);
737 else if(k[Right])
738 // else if(k[PgDn])
739 reader.Execute(DualScreenReader::ScreenDownScroll);
740 else
741 return;
742 tmrInput.Delay(HighResolutionClock::now() - ntick);
743 e.Handled = true;
744 }
745 }
746
747
748 ShlHexBrowser::ShlHexBrowser(const IO::Path& pth,
749 const shared_ptr<Desktop>& h_dsk_up, const shared_ptr<Desktop>& h_dsk_dn)
750 : ShlReader(pth, h_dsk_up, h_dsk_dn),
751 HexArea(Rect({}, MainScreenWidth, MainScreenHeight)), pnlFileInfo()
752 {
753 HexArea.SetRenderer(make_unique<BufferedRenderer>(true));
754 yunseq(
755 FetchEvent<KeyDown>(HexArea) += [this](KeyEventArgs&& e){
756 if(e.GetKeys() == 1 << KeyCodes::Esc)
757 Exit();
758 },
759 HexArea.ViewChanged += [this](HexViewArea::ViewArgs&&){
760 pnlFileInfo.lblSize.Text = u"当前位置： "
761 + String(to_string(HexArea.GetModel().GetPosition())
762 + " / " + to_string(HexArea.GetModel().GetSize()));
763 Invalidate(pnlFileInfo.lblSize);
764 }
765 );
766
767 auto& dsk_up(GetDesktopUp());
768 auto& dsk_dn(GetDesktopDown());
769 const auto& path_str(pth.GetNativeString());
770
771 pnlFileInfo.lblPath.Text = u"文件路径：" + pth;
772
773 struct ::stat file_stat;
774
775 //在 DeSmuME 上无效； iDSL + DSTT 上访问时间精确不到日，修改时间正常。
776 ::stat(path_str.c_str(), &file_stat);
777 yunseq(pnlFileInfo.lblAccessTime.Text = u"访问时间："
778 + String(TranslateTime(file_stat.st_atime)),
779 pnlFileInfo.lblModifiedTime.Text = u"修改时间："
780 + String(TranslateTime(file_stat.st_mtime)));
781 dsk_up += pnlFileInfo;
782 HexArea.Load(path_str.c_str());
783 HexArea.UpdateData(0);
784 HexArea.ViewChanged(HexViewArea::ViewArgs(HexArea, true));
785 dsk_dn += HexArea;
786 RequestFocusCascade(HexArea);
787 }
788
789 YSL_END_NAMESPACE(YReader)
790