#include "drape_frontend/gui/ruler.hpp" #include "drape_frontend/animation/show_hide_animation.hpp" #include "drape_frontend/gui/drape_gui.hpp" #include "drape_frontend/gui/gui_text.hpp" #include "drape_frontend/gui/ruler_helper.hpp" #include "drape_frontend/shader_def.hpp" #include "drape/glsl_func.hpp" #include "drape/glsl_types.hpp" #include "std/bind.hpp" namespace gui { namespace { struct RulerVertex { RulerVertex() = default; RulerVertex(glsl::vec2 const & pos, glsl::vec2 const & normal, glsl::vec2 const & texCoord) : m_position(pos) , m_normal(normal) , m_texCoord(texCoord) { } glsl::vec2 m_position; glsl::vec2 m_normal; glsl::vec2 m_texCoord; }; dp::BindingInfo GetBindingInfo() { dp::BindingInfo info(3); uint8_t offset = 0; offset += dp::FillDecl(0, "a_position", info, offset); offset += dp::FillDecl(1, "a_normal", info, offset); offset += dp::FillDecl(2, "a_colorTexCoords", info, offset); return info; } template class BaseRulerHandle : public TBase { public: BaseRulerHandle(uint32_t id, dp::Anchor anchor, m2::PointF const & pivot, bool isAppearing) : TBase(id, anchor, pivot) , m_isAppearing(isAppearing) , m_isVisibleAtEnd(true) , m_animation(false, 0.4) { } bool Update(ScreenBase const & screen) { RulerHelper & helper = DrapeGui::GetRulerHelper(); TBase::SetIsVisible(true); bool isVisible = helper.IsVisible(screen); if (!isVisible) { m_animation.HideAnimated(); m_isVisibleAtEnd = false; } else { if (helper.IsTextDirty()) { m_isAppearing = !m_isAppearing; if (m_isAppearing) { m_animation.ShowAnimated(); m_isVisibleAtEnd = true; } else { m_animation.HideAnimated(); m_isVisibleAtEnd = false; } } } bool const result = TBase::Update(screen); UpdateImpl(screen, helper); if (m_animation.IsFinished()) TBase::SetIsVisible(m_isVisibleAtEnd); return result; } protected: virtual void UpdateImpl(ScreenBase const & /*screen*/, RulerHelper const & /*helper*/) {} bool IsAppearing() const { return m_isAppearing; } float GetOpacity() const { return m_animation.GetT(); } private: bool m_isAppearing; bool m_isVisibleAtEnd; df::ShowHideAnimation m_animation; }; class RulerHandle : public BaseRulerHandle { using TBase = BaseRulerHandle; public: RulerHandle(uint32_t id, dp::Anchor anchor, m2::PointF const & pivot, bool appearing) : TBase(id, anchor, pivot, appearing) {} private: void UpdateImpl(ScreenBase const & screen, RulerHelper const & helper) override { if (IsVisible()) { m_size = m2::PointF(helper.GetRulerPixelLength(), 2 * helper.GetRulerHalfHeight()); if (IsAppearing()) m_uniforms.SetFloatValue("u_length", helper.GetRulerPixelLength()); m_uniforms.SetFloatValue("u_position", m_pivot.x, m_pivot.y); m_uniforms.SetFloatValue("u_opacity", GetOpacity()); } } }; class RulerTextHandle : public BaseRulerHandle { using TBase = BaseRulerHandle; public: RulerTextHandle(uint32_t id, dp::Anchor anchor, m2::PointF const & pivot, bool isAppearing, ref_ptr textures) : TBase(id, anchor, pivot, isAppearing) , m_firstUpdate(true) { SetTextureManager(textures); } bool Update(ScreenBase const & screen) override { SetIsVisible(DrapeGui::GetRulerHelper().IsVisible(screen)); if (IsVisible() && (DrapeGui::GetRulerHelper().IsTextDirty() || m_firstUpdate)) { SetContent(DrapeGui::GetRulerHelper().GetRulerText()); m_firstUpdate = false; } return TBase::Update(screen); } void SetPivot(glsl::vec2 const & pivot) override { RulerHelper & helper = DrapeGui::GetRulerHelper(); TBase::SetPivot(pivot + glsl::vec2(0.0, helper.GetVerticalTextOffset() - helper.GetRulerHalfHeight())); } protected: void UpdateImpl(ScreenBase const & /*screen*/, RulerHelper const & /*helper*/) override { if (IsVisible()) m_uniforms.SetFloatValue("u_opacity", GetOpacity()); } private: bool m_firstUpdate; }; } drape_ptr Ruler::Draw(m2::PointF & size, ref_ptr tex) const { ShapeControl control; size = m2::PointF::Zero(); DrawRuler(size, control, tex, true); DrawRuler(size, control, tex, false); DrawText(size, control, tex, true); DrawText(size, control, tex, false); drape_ptr renderer = make_unique_dp(); renderer->AddShapeControl(move(control)); return renderer; } void Ruler::DrawRuler(m2::PointF & size, ShapeControl & control, ref_ptr tex, bool isAppearing) const { buffer_vector data; dp::TextureManager::ColorRegion reg; tex->GetColorRegion(DrapeGui::GetGuiTextFont().m_color, reg); glsl::vec2 texCoord = glsl::ToVec2(reg.GetTexRect().Center()); float h = DrapeGui::GetRulerHelper().GetRulerHalfHeight(); size += m2::PointF(DrapeGui::GetRulerHelper().GetMaxRulerPixelLength(), 2.0 * h); glsl::vec2 normals[] = { glsl::vec2(-1.0, 0.0), glsl::vec2(1.0, 0.0), }; dp::Anchor anchor = m_position.m_anchor; if (anchor & dp::Left) normals[0] = glsl::vec2(0.0, 0.0); else if (anchor & dp::Right) normals[1] = glsl::vec2(0.0, 0.0); data.push_back(RulerVertex(glsl::vec2(0.0, h), normals[0], texCoord)); data.push_back(RulerVertex(glsl::vec2(0.0, -h), normals[0], texCoord)); data.push_back(RulerVertex(glsl::vec2(0.0, h), normals[1], texCoord)); data.push_back(RulerVertex(glsl::vec2(0.0, -h), normals[1], texCoord)); auto state = df::CreateGLState(gpu::RULER_PROGRAM, df::RenderState::GuiLayer); state.SetColorTexture(reg.GetTexture()); dp::AttributeProvider provider(1, 4); provider.InitStream(0, GetBindingInfo(), make_ref(data.data())); { dp::Batcher batcher(dp::Batcher::IndexPerQuad, dp::Batcher::VertexPerQuad); dp::SessionGuard guard(batcher, bind(&ShapeControl::AddShape, &control, _1, _2)); batcher.InsertTriangleStrip(state, make_ref(&provider), make_unique_dp(EGuiHandle::GuiHandleRuler, m_position.m_anchor, m_position.m_pixelPivot, isAppearing)); } } void Ruler::DrawText(m2::PointF & size, ShapeControl & control, ref_ptr tex, bool isAppearing) const { string alphabet; uint32_t maxTextLength; RulerHelper & helper = DrapeGui::GetRulerHelper(); helper.GetTextInitInfo(alphabet, maxTextLength); MutableLabelDrawer::Params params; params.m_anchor = static_cast((m_position.m_anchor & (dp::Right | dp::Left)) | dp::Bottom); params.m_alphabet = alphabet; params.m_maxLength = maxTextLength; params.m_font = DrapeGui::GetGuiTextFont(); params.m_pivot = m_position.m_pixelPivot + m2::PointF(0.0, helper.GetVerticalTextOffset()); params.m_handleCreator = [isAppearing, tex](dp::Anchor anchor, m2::PointF const & pivot) { return make_unique_dp(EGuiHandle::GuiHandleRulerLabel, anchor, pivot, isAppearing, tex); }; m2::PointF textSize = MutableLabelDrawer::Draw(params, tex, bind(&ShapeControl::AddShape, &control, _1, _2)); size.y += (textSize.y + abs(helper.GetVerticalTextOffset())); } }