added CompassArrow GUI element.

This commit is contained in:
rachytski 2012-08-20 12:42:03 +03:00 committed by Alex Zolotarev
parent 378ba050ee
commit 9ca2c102b9
12 changed files with 380 additions and 12 deletions

162
map/compass_arrow.cpp Normal file
View file

@ -0,0 +1,162 @@
#include "compass_arrow.hpp"
#include "framework.hpp"
#include "rotate_screen_task.hpp"
#include "../anim/controller.hpp"
#include "../gui/controller.hpp"
#include "../geometry/any_rect2d.hpp"
#include "../geometry/transformations.hpp"
#include "../yg/display_list.hpp"
#include "../yg/screen.hpp"
#include "../yg/skin.hpp"
CompassArrow::CompassArrow(Params const & p)
: base_t(p),
m_boundRects(1)
{
m_arrowWidth = p.m_arrowWidth;
m_arrowHeight = p.m_arrowHeight;
m_northColor = p.m_northColor;
m_southColor = p.m_southColor;
m_framework = p.m_framework;
m_angle = 0;
}
void CompassArrow::setAngle(double angle)
{
m_angle = angle;
m_drawM = math::Shift(math::Rotate(math::Identity<double, 3>(), m_angle), pivot() * visualScale());
setIsDirtyRect(true);
}
vector<m2::AnyRectD> const & CompassArrow::boundRects() const
{
if (isDirtyRect())
{
double k = visualScale();
m2::PointD pv = pivot() * k;
double halfW = m_arrowWidth / 2.0 * k;
double halfH = m_arrowHeight / 2.0 * k;
m_boundRects[0] = m2::AnyRectD(pv,
-math::pi / 2 + m_angle,
m2::RectD(-halfW, -halfH, halfW, halfH));
setIsDirtyRect(false);
}
return m_boundRects;
}
void CompassArrow::draw(yg::gl::OverlayRenderer * r,
math::Matrix<double, 3, 3> const & m) const
{
if (isVisible())
{
checkDirtyDrawing();
m_displayList->draw(m_drawM * m);
}
}
void CompassArrow::cache()
{
yg::gl::Screen * cacheScreen = m_controller->GetCacheScreen();
m_displayList.reset();
m_displayList.reset(cacheScreen->createDisplayList());
cacheScreen->beginFrame();
cacheScreen->setDisplayList(m_displayList.get());
double k = visualScale();
double halfW = m_arrowWidth / 2.0 * k;
double halfH = m_arrowHeight / 2.0 * k;
m2::PointF northPts[3] = {
m2::PointF(-halfW, 0),
m2::PointF(0, -halfH),
m2::PointF(halfW, 0)
};
cacheScreen->drawConvexPolygon(northPts, 3, m_northColor, depth());
m2::PointF southPts[3] = {
m2::PointF(-halfW, 0),
m2::PointF(halfW, 0),
m2::PointF(0, halfH),
};
cacheScreen->drawConvexPolygon(southPts, 3, m_southColor, depth());
m2::PointD outlinePts[6] = {
m2::PointD(-halfW, 0),
m2::PointD(0, -halfH),
m2::PointD(halfW, 0),
m2::PointD(0, halfH),
m2::PointD(-halfW, 0),
m2::PointD(halfW, 0)
};
yg::PenInfo outlinePenInfo(yg::Color(32, 32, 32, 255), 1, 0, 0, 0);
cacheScreen->drawPath(outlinePts, sizeof(outlinePts) / sizeof(m2::PointD), 0, cacheScreen->skin()->mapPenInfo(outlinePenInfo), depth());
m_drawM = math::Shift(math::Rotate(math::Identity<double, 3>(), m_angle), pivot() * k);
cacheScreen->setDisplayList(0);
cacheScreen->endFrame();
// we should not call cacheScreen->completeCommands
// as the gui::Element::cache is called on the GUI thread.
}
void CompassArrow::purge()
{
m_displayList.reset();
}
bool CompassArrow::onTapEnded(m2::PointD const & pt)
{
shared_ptr<anim::Controller> animController = m_framework->GetRenderPolicy()->GetAnimController();
animController->Lock();
if (m_rotateScreenTask
&& !m_rotateScreenTask->IsEnded()
&& !m_rotateScreenTask->IsCancelled())
m_rotateScreenTask->Cancel();
m_rotateScreenTask.reset();
double startAngle = m_framework->GetNavigator().Screen().GetAngle();
double endAngle = 0;
double period = 2 * math::pi;
startAngle -= floor(startAngle / period) * period;
endAngle -= floor(endAngle / period) * period;
if (fabs(startAngle - endAngle) > math::pi)
startAngle -= 2 * math::pi;
m_rotateScreenTask.reset(new RotateScreenTask(m_framework,
startAngle,
endAngle,
1));
animController->AddTask(m_rotateScreenTask);
animController->Unlock();
m_framework->Invalidate();
return true;
}
bool CompassArrow::hitTest(m2::PointD const & pt) const
{
return pt.Length(pivot() * visualScale()) < max(m_arrowWidth / 2, m_arrowHeight / 2);
}

69
map/compass_arrow.hpp Normal file
View file

@ -0,0 +1,69 @@
#pragma once
#include "../gui/element.hpp"
#include "../yg/color.hpp"
#include "../geometry/any_rect2d.hpp"
#include "../std/shared_ptr.hpp"
namespace yg
{
namespace gl
{
class DisplayList;
}
}
class RotateScreenTask;
class Framework;
/// Compass Arrow, which shows up when the screen is rotated,
/// and rotates screen back to straight orientation when beeing pressed
class CompassArrow : public gui::Element
{
private:
typedef gui::Element base_t;
unsigned m_arrowWidth;
unsigned m_arrowHeight;
yg::Color m_northColor;
yg::Color m_southColor;
double m_angle;
shared_ptr<yg::gl::DisplayList> m_displayList;
shared_ptr<RotateScreenTask> m_rotateScreenTask;
mutable vector<m2::AnyRectD> m_boundRects;
math::Matrix<double, 3, 3> m_drawM;
Framework * m_framework;
void cache();
void purge();
public:
struct Params : public base_t::Params
{
unsigned m_arrowWidth;
unsigned m_arrowHeight;
yg::Color m_northColor;
yg::Color m_southColor;
Framework * m_framework;
};
CompassArrow(Params const & p);
void setAngle(double angle);
vector<m2::AnyRectD> const & boundRects() const;
void draw(yg::gl::OverlayRenderer * r, math::Matrix<double, 3, 3> const & m) const;
bool onTapEnded(m2::PointD const & pt);
bool hitTest(m2::PointD const & pt) const;
};

View file

@ -571,6 +571,8 @@ void Framework::DrawAdditionalInfo(shared_ptr<PaintEvent> const & e)
m_informationDisplay.setEmptyCountryName(m_renderPolicy->GetCountryName());
m_informationDisplay.enableCountryStatusDisplay(isEmptyModel);
m_informationDisplay.enableCompassArrow(m_navigator.Screen().GetAngle() != 0);
m_informationDisplay.setCompassArrowAngle(m_navigator.Screen().GetAngle());
m_informationDisplay.setScreen(m_navigator.Screen());

View file

@ -1,6 +1,7 @@
#include "information_display.hpp"
#include "drawer_yg.hpp"
#include "country_status_display.hpp"
#include "compass_arrow.hpp"
#include "framework.hpp"
#include "../indexer/mercator.hpp"
@ -37,6 +38,19 @@ InformationDisplay::InformationDisplay(Framework * framework)
m_countryStatusDisplay.reset(new CountryStatusDisplay(p));
CompassArrow::Params cap;
cap.m_position = yg::EPosCenter;
cap.m_depth = yg::maxDepth;
cap.m_arrowHeight = 60;
cap.m_arrowWidth = 20;
cap.m_pivot = m2::PointD(10 + cap.m_arrowHeight / 2, 10 + cap.m_arrowHeight / 2);
cap.m_northColor = yg::Color(255, 0, 0, 255);
cap.m_southColor = yg::Color(255, 255, 255, 255);
cap.m_framework = framework;
m_compassArrow.reset(new CompassArrow(cap));
location::State::Params lsp;
lsp.m_position = yg::EPosCenter;
@ -57,6 +71,7 @@ InformationDisplay::InformationDisplay(Framework * framework)
enableMemoryWarning(false);
enableBenchmarkInfo(false);
enableCountryStatusDisplay(false);
enableCompassArrow(false);
for (int i = 0; i < sizeof(m_DebugPts) / sizeof(m2::PointD); ++i)
m_DebugPts[i] = m2::PointD(0, 0);
@ -68,6 +83,7 @@ void InformationDisplay::setController(gui::Controller *controller)
{
m_controller = controller;
m_controller->AddElement(m_countryStatusDisplay);
m_controller->AddElement(m_compassArrow);
m_controller->AddElement(m_locationState);
}
@ -368,6 +384,16 @@ void InformationDisplay::drawLog(DrawerYG * drawer)
}
*/
void InformationDisplay::enableCompassArrow(bool doEnable)
{
m_compassArrow->setIsVisible(doEnable);
}
void InformationDisplay::setCompassArrowAngle(double angle)
{
m_compassArrow->setAngle(angle);
}
void InformationDisplay::enableCountryStatusDisplay(bool doEnable)
{
m_countryStatusDisplay->setIsVisible(doEnable);

View file

@ -24,6 +24,7 @@ namespace gui
class Framework;
class CountryStatusDisplay;
class CompassArrow;
/// Class, which displays additional information on the primary layer.
/// like rules, coordinates, GPS position and heading
@ -80,6 +81,7 @@ private:
static WindowHandle * s_windowHandle;
*/
shared_ptr<CountryStatusDisplay> m_countryStatusDisplay;
shared_ptr<CompassArrow> m_compassArrow;
shared_ptr<location::State> m_locationState;
public:
@ -126,6 +128,9 @@ public:
void setLogSize(size_t logSize);
void drawLog(DrawerYG * pDrawer);
void enableCompassArrow(bool doEnable);
void setCompassArrowAngle(double angle);
shared_ptr<location::State> const & locationState() const;
void enableCountryStatusDisplay(bool doEnable);

View file

@ -48,7 +48,8 @@ HEADERS += \
tile_set.hpp \
geourl_process.hpp \
country_status_display.hpp \
rotate_screen_task.hpp
rotate_screen_task.hpp \
compass_arrow.hpp
SOURCES += \
feature_vec_model.cpp \
@ -88,7 +89,8 @@ SOURCES += \
geourl_process.cpp \
bookmark.cpp \
country_status_display.cpp \
rotate_screen_task.cpp
rotate_screen_task.cpp \
compass_arrow.cpp
!iphone*:!bada*:!android* {
HEADERS += qgl_render_context.hpp
@ -105,3 +107,5 @@ SOURCES += \

View file

@ -36,10 +36,55 @@ namespace yg
base_t::endFrame();
}
void AreaRenderer::drawTrianglesFan(m2::PointF const * points,
size_t pointsCount,
uint32_t styleID,
double depth)
{
++m_areasCount;
m_trianglesCount += (pointsCount - 2);
if (!m_drawAreas)
return;
ResourceStyle const * style = skin()->fromID(styleID);
if (style == 0)
{
LOG(LINFO, ("drawTrianglesFan: styleID=", styleID, " wasn't found on current skin."));
return;
}
ASSERT_GREATER_OR_EQUAL(pointsCount, 2, ());
float texX = style->m_texRect.minX() + 1.0f;
float texY = style->m_texRect.minY() + 1.0f;
shared_ptr<BaseTexture> texture = skin()->getPage(style->m_pipelineID)->texture();
if (!texture)
{
LOG(LDEBUG, ("returning as no texture is reserved"));
return;
}
texture->mapPixel(texX, texY);
m2::PointF texCoord(texX, texY);
m2::PointF normal(0, 0);
addTexturedFanStrided(points, sizeof(m2::PointF),
&normal, 0,
&texCoord, 0,
pointsCount,
depth,
style->m_pipelineID);
}
void AreaRenderer::drawTrianglesList(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth)
{
++m_areasCount;
m_trianglesCount += pointsCount;
m_trianglesCount += pointsCount / 3;
if (!m_drawAreas)
return;

View file

@ -32,6 +32,11 @@ namespace yg
uint32_t styleID,
double depth);
void drawTrianglesFan(m2::PointF const * points,
size_t pointsCount,
uint32_t styleID,
double depth);
void beginFrame();
void endFrame();
};

View file

@ -19,6 +19,7 @@ namespace yg
m_isVisible(true),
m_isValid(true),
m_isDirtyRect(true),
m_isDirtyDrawing(true),
m_isDirtyRoughRect(true)
{}

View file

@ -82,8 +82,8 @@ namespace yg
bool isValid() const;
void setIsValid(bool flag);
bool hitTest(m2::PointD const & pt) const;
bool roughHitTest(m2::PointD const & pt) const;
virtual bool hitTest(m2::PointD const & pt) const;
virtual bool roughHitTest(m2::PointD const & pt) const;
m2::RectD const & roughBoundRect() const;
};

View file

@ -17,6 +17,19 @@ namespace yg
{
}
void ShapeRenderer::drawConvexPolygon(m2::PointF const * pts, size_t ptsCount, yg::Color const & color, double depth)
{
uint32_t styleID = skin()->mapColor(color);
if (styleID == skin()->invalidHandle())
{
LOG(LINFO, ("cannot map color"));
return;
}
drawTrianglesFan(pts, ptsCount, styleID, depth);
}
void ShapeRenderer::drawArc(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth)
{
vector<m2::PointD> pts;

View file

@ -16,14 +16,50 @@ namespace yg
ShapeRenderer(base_t::Params const & params);
static void approximateArc(m2::PointD const & center, double startA, double endA, double r, vector<m2::PointD> & pts);
void drawArc(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth);
void drawSector(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth);
void fillSector(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth);
void drawConvexPolygon(m2::PointF const * points,
size_t pointsCount,
yg::Color const & color,
double depth);
void drawRectangle(m2::AnyRectD const & r, yg::Color const & c, double depth);
void drawRectangle(m2::RectD const & r, yg::Color const & c, double depth);
void drawRoundedRectangle(m2::RectD const & r, double rad, yg::Color const & c, double depth);
static void approximateArc(m2::PointD const & center,
double startA,
double endA,
double r,
vector<m2::PointD> & pts);
void drawArc(m2::PointD const & center,
double startA,
double endA,
double r,
yg::Color const & c,
double depth);
void drawSector(m2::PointD const & center,
double startA,
double endA,
double r,
yg::Color const & c,
double depth);
void fillSector(m2::PointD const & center,
double startA,
double endA,
double r,
yg::Color const & c,
double depth);
void drawRectangle(m2::AnyRectD const & r,
yg::Color const & c,
double depth);
void drawRectangle(m2::RectD const & r,
yg::Color const & c,
double depth);
void drawRoundedRectangle(m2::RectD const & r,
double rad,
yg::Color const & c,
double depth);
};
}
}