_tOut transform_when(_tIn first, _tOut result, _fPred pred, _fOp op) { yunseq((yconstraint(!is_undereferenceable(first)), 0), (yconstraint(!is_undereferenceable(result)), 0)); for(; pred(*first); yunseq((++first, 0), (++result, 0))) *result = op(*first); return result; }
void SaveInput(const ::AInputEvent& e) { const auto update_key([](std::int32_t action, const std::uint8_t keycode){ lock_guard<mutex> lck(KeyMutex); // TODO: Track Alt/Shift/Sym key states. // const auto meta(::AKeyEvent_getMetaState(&e)); switch(action) { case ::AKEY_EVENT_ACTION_DOWN: case ::AKEY_EVENT_ACTION_UP: KeyStateBuffer.set(keycode, action == ::AKEY_EVENT_ACTION_DOWN); break; case ::AKEY_EVENT_ACTION_MULTIPLE: // TODO: Record. break; } }); const auto update_motion_key([](bool down){ lock_guard<mutex> lck(KeyMutex); KeyStateBuffer.set(platform::KeyCodes::Primary, down); }); switch(::AInputEvent_getType(&e)) { case AINPUT_EVENT_TYPE_KEY: if(~::AKeyEvent_getFlags(&e) & ::AKEY_EVENT_FLAG_CANCELED) update_key(::AKeyEvent_getAction(&e), ::AKeyEvent_getKeyCode(&e) & 0xFF); break; case AINPUT_EVENT_TYPE_MOTION: // TODO: Detect multiple pointers using 'AMotionEvent_getPointerCount'. // TODO: Support multiple pointers handlers. // TODO: Detect edges using 'AMotionEvent_getEdgeFlags'. // TODO: Record pressure using 'AMotionEvent_getPressure'. // TODO: Record touch area size using 'AMotionEvent_getSize'. // TODO: Track historical motion using 'AMotionEvent_getHistorical*'. if(::AMotionEvent_getFlags(&e) != AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) switch(::AKeyEvent_getAction(&e) & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_CANCEL: break; case AMOTION_EVENT_ACTION_UP: update_motion_key({}); break; case AMOTION_EVENT_ACTION_DOWN: update_motion_key(true); case AMOTION_EVENT_ACTION_MOVE: default: { lock_guard<mutex> lck(CursorMutex); yunseq(LastCursorPosX = ::AMotionEvent_getRawX(&e, 0), LastCursorPosY = ::AMotionEvent_getRawY(&e, 0)); } } } }
void ClearKeyStates() { lock_guard<mutex> comp_lck(CompKeyMutex); lock_guard<mutex> lck(KeyMutex); yunseq(Deref(pKeyState).reset(), Deref(pOldKeyState).reset()); }
bool BlitBounds(const Point& dp, const Point& sp, const Size& ds, const Size& ss, const Size& sc, SDst& min_x, SDst& min_y, SDst& delta_x, SDst& delta_y) { SPos max_x, max_y; yunseq(min_x = blit_min(sp.X, dp.X), min_y = blit_min(sp.Y, dp.Y), max_x = blit_max(sp.X, dp.X, ss.Width, ds.Width, sc.Width), max_y = blit_max(sp.Y, dp.Y, ss.Height, ds.Height, sc.Height)); if(min_x < max_x && min_y < max_y) { yunseq(delta_x = max_x - min_x, delta_y = max_y - min_y); return true; } return false; }
void AMUnitList::ResetView() { bool b(vwList.IsSelected()); vwList.Reset(); if(b) vwList.SetSelectedIndex(0, GetTotal()); yunseq(uTopOffset = 0, idxShared = size_t(-1)); }
ProgressBar::ProgressBar(const Rect& r, ValueType m) : Control(r, NoBackgroundTag()), GMRange<float>(m == 0 ? 1 : m, 0) { auto& pal(FetchGUIState().Colors); BorderStyle style; style.ActiveColor = pal[Styles::InactiveBorder]; yunseq( Background = SolidBrush(pal[Styles::Track]), ForeColor = pal[Styles::HotTracking], FetchEvent<Paint>(*this).Add(BorderBrush(style), BoundaryPriority) ); }
HoverUpdater::HoverUpdater(IWidget& wgt) : Widget(wgt) { yunseq( FetchEvent<Enter>(wgt) += [this](UIEventArgs&&){ entered = true, Invalidate(Widget); }, FetchEvent<Leave>(wgt) += [this](UIEventArgs&&){ entered = false, Invalidate(Widget); } ); }
ProgressBar::ProgressBar(const Rect& r, ValueType m) : Control(r), GMRange<float>(m == 0 ? 1 : m, 0) { const auto invalidator([this]{ Invalidate(*this); }); auto& pal(FetchGUIState().Colors); BorderStyle style; style.ActiveColor = pal[Styles::InactiveBorder]; yunseq( Background = SolidBrush(pal[Styles::Track]), ForeColor = pal[Styles::HotTracking], FetchEvent<Paint>(*this).Add(BorderBrush(style), BoundaryPriority), FetchEvent<GotFocus>(*this) += invalidator, FetchEvent<LostFocus>(*this) += invalidator ); }
Control::Control(const Rect& r, NoBackgroundTag) : Widget(new View(r), new Renderer(), new Controller(true, FetchPrototype<ControlEventMap>())), BoundControlPtr(std::bind(&Control::GetBoundControlPtr, this, std::placeholders::_1)) { const auto h([this](UIEventArgs&&) { Invalidate(*this); }); FetchGUIState().Wrap(*this), yunseq( FetchEvent<Move>(*this) += [this](UIEventArgs&&) { InvalidateParent(*this); }, FetchEvent<Resize>(*this) += h, FetchEvent<GotFocus>(*this) += h, FetchEvent<LostFocus>(*this) += h ); }
SettingPanel& SettingPanel::operator<<(const ReaderSetting& s) { auto& node(dynWgts.WidgetNode); DeclDynWidgetNode(DropDownList, ddlFont) DeclDynWidgetNode(CheckButton, cbSmoothScroll) yunseq( lblAreaUp.ForeColor = s.FontColor, lblAreaUp.Background = SolidBrush(s.UpColor), lblAreaUp.Font = s.Font, lblAreaDown.ForeColor = s.FontColor, lblAreaDown.Background = SolidBrush(s.DownColor), lblAreaDown.Font = s.Font, ddlFont.Text = s.Font.GetFamilyName(), scroll_duration = s.ScrollDuration, smooth_scroll_duration = s.SmoothScrollDuration ), cbSmoothScroll.Tick(s.SmoothScroll); UpdateInfo(); return *this; }
DSWindow::DSWindow(NativeWindowHandle h_wnd, DSScreen& s_up, DSScreen& s_dn, GUIHost& h) : Window(h_wnd, h), scr_up(s_up), scr_dn(s_dn) { # if YCL_Win32 yunseq( MessageMap[WM_DESTROY] += []{ YSLib::PostQuitMessage(0); // NOTE: Try to make sure all shells are released before destructing the // instance of %DSApplication. }, MessageMap[WM_PAINT] += [this]{ GSurface<WindowRegionDeviceContext> sf(Nonnull(GetNativeHandle())); const auto& r(sf.GetInvalidatedArea()); UpdateScreen(sf, scr_up, r); UpdateScreen(sf, scr_dn, r); } ); Show(); # endif }
void ProgressBar::Refresh(PaintEventArgs&& e) { const auto& g(e.Target); auto pt(e.Location); auto& r(e.ClipArea); Size s(GetSizeOf(*this)); if(YB_LIKELY(s.Width > 2 && s.Height > 2)) { yunseq(s.Width -= 2, s.Height -= 2, pt.X += 1, pt.Y += 1); const SDst w_bar(round(value * s.Width / max_value)); FillRect(g, r, {pt, w_bar, s.Height}, ForeColor); pt.X += w_bar; if(s.Width > w_bar) // TODO: Finish drawing with non-solid brushes. if(const auto p = Background.target<SolidBrush>()) FillRect(g, r, Rect(pt, s.Width - w_bar, s.Height), p->Color); } }
ValueNode TransformNPLA1(const ValueNode& node, std::function<NodeMapper> mapper) { auto s(node.GetSize()); if(s == 0) return {0, "", node ? Deliteralize(Access<string>(node)) : string()}; auto i(node.begin()); if(s == 1) return TransformNPLA1(*i, mapper); const auto& name(ParseNPLANodeString(*i)); if(!name.empty()) yunseq(++i, --s); if(s == 1) { auto&& n(TransformNPLA1(*i, mapper)); if(n.GetName().empty()) return {0, name, std::move(n.Value)}; return {ValueNode::Container{std::move(n)}, name}; } auto p_node_con(make_unique<ValueNode::Container>()); std::for_each(i, node.end(), [&](const ValueNode& nd){ auto&& n(mapper ? mapper(nd) : TransformNPLA1(nd, mapper)); p_node_con->insert(n.GetName().empty() ? ValueNode(0, '$' + std::to_string(p_node_con->size()), std::move(n.Value)) : std::move(n)); }); return {std::move(p_node_con), name}; }
void BorderResizer::Wrap() { auto& controller(widget.get().GetController()); yunseq( FetchEvent<TouchDown>(controller).Add([this](CursorEventArgs&& e){ yunseq(orig_loc = FetchGUIState().CursorLocation, locked_bounds = GetBoundsOf(widget), focused = CheckArea(e)); }, 0xE0), FetchEvent<TouchHeld>(controller).Add([this](CursorEventArgs&& e){ if(e.Strategy == RoutedEventArgs::Direct && focused != Area(BorderArea::Center, BorderArea::Center)) { auto& st(FetchGUIState()); if(st.CheckDraggingOffset()) { const auto offset(st.CursorLocation - orig_loc); auto bounds(locked_bounds); switch(focused.first) { case BorderArea::Left: bounds.Width = max<SPos>(MinSize.Width, locked_bounds.Width - offset.X); bounds.X += locked_bounds.Width - bounds.Width; break; case BorderArea::Right: bounds.Width = max<SPos>(MinSize.Width, locked_bounds.Width + offset.X); break; default: ; } switch(focused.second) { case BorderArea::Up: bounds.Height = max<SPos>(MinSize.Height, locked_bounds.Height - offset.Y); bounds.Y += locked_bounds.Height - bounds.Height; break; case BorderArea::Down: bounds.Height = max<SPos>(MinSize.Height, locked_bounds.Height + offset.Y); break; default: ; } YTraceDe(Notice, "BorderResizer: new bounds = %s.\n", to_string(bounds).c_str()); InvalidateParent(widget); if(HostMode) { const auto& off( bounds.GetPoint() - locked_bounds.GetPoint()); SetBoundsOf(widget, bounds); const auto& nloc(FetchGUIState().CursorLocation - off); if(bounds.Width != MinSize.Width) orig_loc.X = nloc.X; if(bounds.Height != MinSize.Height) orig_loc.Y = nloc.Y; locked_bounds = GetBoundsOf(widget); locked_bounds.GetPointRef() -= off; } else SetBoundsOf(widget, bounds); } e.Handled = true; // XXX: Paint context target invalidated. } }, 0xE0), FetchEvent<Click>(controller).Add([this](CursorEventArgs&& e){ CallEvent<ClickAcross>(widget, e); }, 0xE0), FetchEvent<ClickAcross>(controller).Add([this](CursorEventArgs&&){ yunseq(orig_loc = Point::Invalid, locked_bounds = Rect(), focused = {BorderArea::Center, BorderArea::Center}); }, 0xE0) ); }
DropDownList::DropDownList(const Rect& r, const shared_ptr<ListType>& h) : Button(r), lbContent( {}, h) { const auto detacher([this](UIEventArgs&& e) { if(!dynamic_cast<RoutedEventArgs*>(&e)) DetachTopWidget(); }); yunseq( Margin.Left = 4, Margin.Right = 18, HorizontalAlignment = TextAlignment::Left, lbContent.GetView().DependencyPtr = this, FetchEvent<TouchDown>(*this) += [this](CursorEventArgs&& e) { if(!FetchContainerPtr(lbContent)) { Point pt; if(const auto p = dynamic_cast<Panel*>(&FetchTopLevel(e.GetSender(), pt))) { // NOTE: Get height of top widget, top and bottom spaces. const SDst h0(GetSizeOf(*p).Height); // XXX: Conversion to 'SPos' might be implementation-defined. const SDst h1(SDst(max<SPos>(0, pt.Y))), h2(SDst(max<SPos>(0, SPos(h0) - pt.Y - SPos(GetHeight())))); if(IsInOpenInterval(h1, h0) || IsInOpenInterval(h2, h0)) { lbContent.ResizeForPreferred(Size(0, max(h1, h2)), Size(GetWidth(), 0)); const SDst h3(lbContent.GetHeight()); // NOTE: Bottom space is preferred. // XXX: Conversion to 'SPos' might be // implementation-defined. pt.Y += SPos(h2 < h3 ? -h3 : GetHeight()); SetLocationOf(lbContent, pt); lbContent.AdjustViewLength(); { const auto& lst(lbContent.GetList()); const auto i(std::find(lst.cbegin(), lst.cend(), Text)); if(i != lst.cend()) lbContent.SetSelected(size_t(i - lst.cbegin())); else lbContent.ClearSelected(); } p->Add(lbContent, 224U); // TODO: Use non-magic number. RequestFocusCascade(lbContent); e.Handled = true; } } } }, FetchEvent<LostFocus>(*this) += detacher, FetchEvent<LostFocus>(lbContent) += detacher, lbContent.GetConfirmed() += [this](IndexEventArgs&& e) { YAssert(e.Value < lbContent.GetList().size(), "Invalid index found."); Text = lbContent.GetList()[e.Value]; // XXX: This seems to be redundant if the detached top widget would be // always invalidated, however there is no such guarantee. Invalidate(e.GetSender()), Invalidate(*this); DetachTopWidget(); } ); }