YSTest: ImageControl.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

ImageControl.cpp
浏览该文件的文档.
1 /*
2 © 2013-2015, 2017, 2019 FrankHB.
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 "ImageControl.h" // for ystdex::max;
29 #include YFM_YSLib_Service_YPixel
30
31 namespace ImageBrowser
32 {
33
35 enum MenuItem : size_t
36 {
37 Exit = 0,
38 OrigSize,
39 Flip,
40 RotateCW,
41 RotateCCW,
42 CopyImage
43 };
44
45 ImagePanel::ImagePanel(const Rect& r_, const Size& min_size,
46 const Size& max_size)
47 : Panel(r_),
48 min_panel_size(min_size), max_panel_size(max_size), btnClose({{}, 24, 24}),
49 lblCenter(Size(96, 32), Font(FetchDefaultTypeface().GetFontFamily(), 16,
50 FontStyle::Bold), SolidCompositeBrush({0x00, 0x00, 0x00, 0xA0}),
51 ColorSpace::White), hover_state(std::bind(TimedHoverState::LocateForOffset,
52 std::placeholders::_1, Point(0, 24))), border(*this, 8, min_size),
53 mnuContext({}, make_shared<Menu::ListType, String>(
54 {u"退出", u"查看原始大小", u"翻转", u"顺时针旋转", u"逆时针旋转", u"复制"}))
55 {
56 AddWidgets(*this, btnClose, lblCenter),
57 SetVisibleOf(lblCenter, {}),
58 Host::SetupTopLevelTimedTips(btnClose, hover_state, lblCloseTips, u"关闭"),
59 yunseq(
60 lblCenter.HorizontalAlignment = TextAlignment::Center,
61 Background = SolidBrush({0x00, 0x00, 0x00, 0xC0}),
62 btnClose.Background = [this](PaintEventArgs&& e){
63 const auto& g(e.Target);
64 const auto& pt(e.Location);
65 auto& r(e.ClipArea);
66
67 if(hover_updater.IsEntered())
68 FillCircle(g, r, pt + Vec(12, 12), 10, {225, 96, 76});
69 DrawCross(g, e.ClipArea, {pt + Vec(4, 4), {16, 16}}, ColorSpace::White);
70 r = Rect(pt, GetSizeOf(e.GetSender()));
71 },
72 mnuContext.Confirmed += [this](IndexEventArgs&& e){
73 switch(e.Value)
74 {
75 case MenuItem::Exit:
76 YSLib::PostQuitMessage(0);
77 break;
78 case MenuItem::OrigSize:
79 if(session_ptr)
80 ResetSize();
81 break;
82 case MenuItem::Flip:
83 Flip();
84 break;
85 case MenuItem::RotateCW:
86 RotateCW();
87 break;
88 case MenuItem::RotateCCW:
89 RotateCCW();
90 break;
91 case MenuItem::CopyImage:
92 CopyToClipboard();
93 default:
94 break;
95 }
96 },
97 FetchEvent<Resize>(*this) += [this]{
98 SetLocationOf(btnClose, CalcCloseButtonLocation());
99 if(session_ptr)
100 {
101 MoveToCenter(lblCenter),
102 GetPagesRef().Resize(GetSizeOf(*this)),
103 // TODO: Invalidate smaller area?
104 Invalidate(*this);
105 }
106 },
107 FetchEvent<KeyDown>(*this) += [this](KeyEventArgs&& e){
108 if(e.Strategy == RoutedEventArgs::Direct)
109 {
110 auto& st(FetchGUIState());
111
112 st.CheckHeldState(e.Keys);
113
114 const auto& k(st.GetCheckedHeldKeys());
115
116 if(k[KeyCodes::Ctrl] && e.Keys['C'])
117 CopyToClipboard();
118 }
119 },
120 FetchEvent<KeyHeld>(*this) += OnKeyHeld,
121 FetchEvent<Click>(*this) += [this](CursorEventArgs&& e){
122 if(session_ptr && e.Keys[KeyCodes::Tertiary])
123 ResetSize();
124 },
125 FetchEvent<CursorWheel>(*this) += [this](CursorWheelEventArgs&& e){
126 if(session_ptr)
127 {
128 static yconstexpr float def_scale(1.201F),
129 def_rscale(1 / def_scale);
130 auto& pages(GetPagesRef());
131
132 if(pages.ZoomByRatio(e.GetDelta() > 0 ? def_scale : def_rscale, e))
133 {
134 lblCenter.Text = ystdex::sfmt("%2u%%",
135 unsigned(round(pages.GetScale() * 100.F)));
136 if(!IsVisible(lblCenter))
137 {
138 MoveToCenter(lblCenter),
139 DisplayFor(lblCenter, TimeSpan(1000));
140 }
141 // TODO: Invalidate smaller area?
142 Invalidate(*this),
143 UpdateMenuItem();
144 }
145 }
146 },
147 FetchEvent<Paint>(*this).Add([this](PaintEventArgs&& e){
148 if(session_ptr)
149 GetPagesRef().Brush(std::move(e));
150 }, BackgroundPriority),
151 FetchEvent<Click>(btnClose) += []{
152 YSLib::PostQuitMessage(0);
153 },
154 FetchEvent<Paint>(lblCenter) += BorderBrush(BorderStyle(ColorSpace::Gray))
155 );
156 SetLocationOf(btnClose, CalcCloseButtonLocation());
157 }
158
159 bool
160 ImagePanel::CopyToClipboard() ynothrow
161 {
162 return TryInvoke([this]() -> bool{
163 if(const auto p = Host::GetWindowPtrOf(*this))
164 {
165 const auto& g(GetPagesRef().Brush.ImagePtr->GetContext());
166
167 YTraceDe(Debug, "Size of image to be copied to clipboard: %s.",
168 to_string(g.GetSize()).c_str());
169 // TODO: Port to other hosted platforms.
170 #if YCL_Win32
171 platform_ex::Clipboard(p->GetNativeHandle()).Send(g);
172 #endif
173 return true;
174 }
175 return {};
176 });
177 }
178
179 void
180 ImagePanel::Load(ImagePages&& src)
181 {
182 session_ptr.reset(new Session(forward_as_tuple(std::move(src),
183 GAnimationSession<InvalidationUpdater>(), Timers::Timer(),
184 vector<std::chrono::milliseconds>())));
185 auto& pages(GetPagesRef());
186
187 SetSizeOf(*this, pages.GetViewSize());
188 Invalidate(*this);
189
190 // TODO: Check "Loop" metadata.
191 const auto& bmps(pages.GetBitmaps());
192 const auto n(bmps.size());
193 auto& frame_delays(get<3>(*session_ptr));
194
195 YTraceDe(Notice, "Loaded page count = %u.", unsigned(n));
196 if(n > 1)
197 {
198 frame_delays.reserve(n);
199 for(const auto& bmp : bmps)
200 {
201 // TODO: Allow user set minimal frame time.
202 TimeSpan d(20);
203
204 TryExpr(d = ystdex::max(GetFrameTimeOf(bmp), d))
205 CatchExpr(LoggedEvent& e,
206 YTraceDe(e.GetLevel(), "Invalid frame time found."))
207 YTraceDe(Informative, "Loaded frame time = %s milliseconds.",
208 to_string(d.count()).c_str());
209 frame_delays.push_back(d);
210 }
211
212 const auto refresh_frame([this]{
213 const auto d(get<3>(*session_ptr).at(GetPagesRef().GetIndex()));
214
215 YTraceDe(Informative, "Set frame time = %s ms.",
216 to_string(d.count()).c_str());
217 get<2>(*session_ptr).Interval = d;
218 });
219
220 refresh_frame();
221 UI::SetupByTimer(get<1>(*session_ptr), *this, get<2>(*session_ptr),
222 [this, refresh_frame]{
223 if(GetPagesRef().SwitchPageDiff(1))
224 {
225 refresh_frame();
226 Invalidate(*this);
227 }
228 });
229 }
230 UpdateMenuItem();
231 }
232
233 bool
234 ImagePanel::ResetSize()
235 {
236 YAssertNonnull(session_ptr);
237
238 const auto& s(GetSizeOf(*this));
239
240 if(GetPagesRef().ZoomTo(1.F, Point(s.Width / 2, s.Height / 2)))
241 {
242 Invalidate(*this);
243 UpdateMenuItem({});
244 return true;
245 }
246 return {};
247 }
248
249 void
250 ImagePanel::SetupContextMenu()
251 {
252 ResizeForContent(mnuContext);
253 Host::SetupTopLevelContextMenu(*this, mhMain, mnuContext);
254 }
255
256 void
257 ImagePanel::Unload()
258 {
259 session_ptr.reset();
260 }
261
262 void
263 ImagePanel::UpdateBrush()
264 {
265 GetPagesRef().Brush.Update = DispatchRotatedBrush(rot);
266 Invalidate(*this);
267 }
268
269 void
270 ImagePanel::UpdateMenuItem()
271 {
272 UpdateMenuItem(!(std::fabs(GetPagesRef().GetScale() - 1.F)
273 < std::numeric_limits<ImageScale>::epsilon()));
274 }
275 void
276 ImagePanel::UpdateMenuItem(bool b)
277 {
278 mnuContext.SetItemEnabled(MenuItem::OrigSize, b);
279 }
280
281 } // namespace ImageBrowser;
282
YSLib::UI::SetLocationOf
YF_API void SetLocationOf(IWidget &, const Point &)
设置部件左上角所在位置（相对容器的偏移坐标）。
Definition: YWidget.cpp:76
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:112
YSLib::TryInvoke
ystdex::nonvoid_result_t< ystdex::invoke_result_t< _fCallable, _tParams... > > TryInvoke(_fCallable &&f, _tParams &&... args) ynothrow
调用函数并尝试返回。
Definition: YException.h:206
YSLib::Drawing::Size
屏幕区域大小。
Definition: YGDIBase.h:536
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:1072
YSLib::PostQuitMessage
YF_API void PostQuitMessage(int=0, Messaging::Priority p=DefaultQuitPriority)
以指定错误码和优先级发起 Shell 终止请求。
Definition: YApplication.cpp:87
YSLib::UI::Panel
面板。
Definition: YPanel.h:46
ImageBrowser::RotateCW
@ RotateCW
Definition: ImageControl.cpp:40
ImageBrowser::MenuItem
MenuItem
Definition: ImageControl.cpp:36
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
YSLib::Consoles::Gray
@ Gray
Definition: YConsole.h:60
YSLib::Drawing::ImageTag::to_string
YB_ATTR_nodiscard YF_API YB_PURE string to_string(const ImageTag &, ImageMetadataModel)
取按指定图像元数据模型解释的标签值字符串表示。
Definition: Image.cpp:707
YSLib::Consoles::White
@ White
Definition: YConsole.h:68
ImageBrowser::ImagePanel::ImagePanel
ImagePanel(const Rect &, const Size &=DefaultMinPanelSize, const Size &=DefaultMaxPanelSize)
Definition: ImageControl.cpp:45
ImageBrowser
Definition: ImageControl.cpp:32
platform::KeyCodes::DS::Ctrl
@ Ctrl
Definition: Keys.h:255
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:142
YSLib::UI::GetSizeOf
YB_ATTR_nodiscard YB_PURE pt pt Y YB_ATTR_nodiscard YB_PURE const IWidget &wgt const IWidget &wgt GetSizeOf
无效化：使相对部件的子部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: YWidget.h:165
ystdex::cpp2014::max
const _type & max(const _type &a, const _type &b, _fComp comp=less< _type >())
取较大的元素。
Definition: algorithm.hpp:635
ImageBrowser::RotateCCW
@ RotateCCW
Definition: ImageControl.cpp:41
YSLib::Drawing::DrawCross
YF_API void DrawCross(const Graphics &, const Rect &, const Rect &, Color)
在指定图形接口上下文中使用指定颜色描画交叉直线段（“×”）。
Definition: YStyle.cpp:244
YSLib::Drawing::g
The boundary is out of the const Graphics & g
Definition: YDraw.h:161
YSLib::UI::SetupByTimer
void SetupByTimer(_tAnimation &ani, IWidget &wgt, _tTimer &&timer, _func f)
安装以计时器控制的动画效果。
Definition: Animation.h:218
YSLib::UI::BackgroundPriority
yconstexpr const EventPriority BackgroundPriority(0xC0)
用户界面绘制优先级。
YSLib::UI::Invalidate
YF_API void Invalidate(IWidget &, const Rect &)
无效化：使相对部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: YWidget.cpp:108
ImageBrowser::Exit
@ Exit
Definition: ImageControl.cpp:37
YSLib::Drawing::SolidCompositeBrush
单色 Alpha 组合画刷。
Definition: YBrush.h:98
YSLib::UI::AddWidgets
void AddWidgets(_tCon &con, _tWidgets &... wgts)
向部件容器添加子部件。
Definition: YUIContainer.h:446
ImageBrowser::Flip
@ Flip
Definition: ImageControl.cpp:39
YSLib::Drawing::Point
GBinaryGroup< SPos > Point
屏幕二维点（直角坐标表示）。
Definition: YGDIBase.h:520
ImageBrowser::CopyImage
@ CopyImage
Definition: ImageControl.cpp:42
YSLib::Drawing::src
src
Definition: YGDI.h:442
platform::Descriptions::Notice
@ Notice
Definition: YCommon.h:184
YSLib::UI::IndexEventArgs
GValueEventArgs< size_t > IndexEventArgs
索引事件。
Definition: ListControl.h:47
platform::Descriptions::Informative
@ Informative
Definition: YCommon.h:185
YSLib::Drawing::HBitmap::GetFrameTimeOf
YB_ATTR_nodiscard YF_API YB_PURE Timers::TimeSpan GetFrameTimeOf(const HBitmap &)
取图像延时。
Definition: Image.cpp:446
ystdex::sfmt
_tString sfmt(const typename string_traits< _tString >::value_type *fmt,...)
以 C 标准输出格式的输出 basic_string 实例的对象。
Definition: string.hpp:2028
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:165
YSLib::Drawing::DispatchRotatedBrush
GBrushUpdater< const _tImage &, const Point &, const Point & > DispatchRotatedBrush(Rotation rot)
按指定的源图像旋转方向构造画刷。
Definition: YBrush.h:272
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:407
ImageControl.h
图像显示控件。
ImageBrowser::OrigSize
@ OrigSize
Definition: ImageControl.cpp:38
YSLib::UI::OnKeyHeld
YF_API void OnKeyHeld(KeyEventArgs &&)
处理键接触保持事件。
Definition: YControl.cpp:109
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
YSLib::UI::MoveToCenter
YF_API void MoveToCenter(IWidget &)
移动部件至容器中心。
Definition: YUIContainer.cpp:135
YSLib::Drawing::Rect
屏幕标准矩形：表示屏幕矩形区域。
Definition: YGDIBase.h:788
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:143
YSLib::UI::SetSizeOf
YF_API void SetSizeOf(IWidget &, const Size &)
设置部件大小。
Definition: YWidget.cpp:83
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:140
YSLib::UI::TextList::ResizeForContent
YF_API void ResizeForContent(TextList &)
根据文本内容调整文本列表大小。
Definition: ListControl.cpp:414
YSLib::Drawing::Font
字体：字模，包含字型、样式和大小。
Definition: Font.h:589
platform::p
return p p
Definition: YCLib/FileSystem.h:209
const
const Decapsulate const Decapsulate &y ynothrow ContextNode &ctx const
Definition: NPLA1Forms.cpp:1629
YSLib::Timers::TimeSpan
std::chrono::duration< Duration::rep, std::milli > TimeSpan
低精度时间间隔。
Definition: YClock.h:81
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
YSLib::UI::IsVisible
IsVisible
Definition: YWidget.h:101
YSLib::UI::FetchGUIState
GUIState & FetchGUIState() ynothrow
Definition: YGUI.cpp:506
platform::KeyCodes::DS::Tertiary
@ Tertiary
Definition: Keys.h:266
platform::Descriptions::Debug
@ Debug
Definition: YCommon.h:186
YSLib::Drawing::FetchDefaultTypeface
YB_ATTR_nodiscard YF_API const Typeface & FetchDefaultTypeface()
取默认字型引用。
Definition: Font.cpp:391