YSTest: ImageControl.cpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

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

- 文件列表
- 文件成员

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