fixed Ruler to use CachedTextView and path-rendering DisplayList.

This commit is contained in:
rachytski 2013-03-29 23:23:33 +03:00 committed by Alex Zolotarev
parent bcda0a2661
commit 4edc3fa10a
2 changed files with 196 additions and 130 deletions

View file

@ -1,19 +1,24 @@
#include "ruler.hpp"
#include "framework.hpp"
#include "measurement_utils.hpp"
#include "../platform/settings.hpp"
#include "../graphics/overlay_renderer.hpp"
#include "../gui/cached_text_view.hpp"
#include "../gui/controller.hpp"
#include "../graphics/pen.hpp"
#include "../graphics/screen.hpp"
#include "../graphics/display_list.hpp"
#include "../indexer/mercator.hpp"
#include "../geometry/distance_on_sphere.hpp"
#include "../geometry/transformations.hpp"
#include "../base/logging.hpp"
#include "../base/string_utils.hpp"
#include "../base/macros.hpp"
namespace
{
struct UnitValue
@ -80,6 +85,80 @@ namespace
}
}
void Ruler::CalcMetresDiff(double v)
{
UnitValue * arrU;
int count;
switch (m_currSystem)
{
default:
ASSERT_EQUAL ( m_currSystem, 0, () );
arrU = g_arrMetres;
count = ARRAY_SIZE(g_arrMetres);
break;
case 1:
arrU = g_arrFeets;
count = ARRAY_SIZE(g_arrFeets);
break;
case 2:
arrU = g_arrYards;
count = ARRAY_SIZE(g_arrYards);
break;
}
string s;
if (arrU[0].m_i > v)
{
s = string("< ") + arrU[0].m_s;
m_metresDiff = m_minMetersWidth - 1.0;
}
else if (arrU[count-1].m_i <= v)
{
s = string("> ") + arrU[count-1].m_s;
m_metresDiff = m_maxMetersWidth + 1.0;
}
else
for (int i = 0; i < count; ++i)
{
if (arrU[i].m_i > v)
{
m_metresDiff = arrU[i].m_i / m_conversionFn(1.0);
s = arrU[i].m_s;
break;
}
}
m_scaleText->setText(s);
}
Ruler::Params::Params()
: m_framework(0)
{}
Ruler::Ruler(Params const & p)
: base_t(p),
m_boundRects(1),
m_currSystem(0),
m_cacheLength(500),
m_framework(p.m_framework)
{
gui::CachedTextView::Params pp;
pp.m_depth = depth();
m_scaleText.reset(new gui::CachedTextView(pp));
}
void Ruler::setController(gui::Controller * controller)
{
gui::Element::setController(controller);
m_scaleText->setController(controller);
}
void Ruler::layout()
{
Settings::Units units = Settings::Metric;
@ -105,102 +184,44 @@ void Ruler::layout()
}
}
void Ruler::CalcMetresDiff(double v)
{
UnitValue * arrU;
int count;
switch (m_currSystem)
{
default:
ASSERT_EQUAL ( m_currSystem, 0, () );
arrU = g_arrMetres;
count = ARRAY_SIZE(g_arrMetres);
break;
case 1:
arrU = g_arrFeets;
count = ARRAY_SIZE(g_arrFeets);
break;
case 2:
arrU = g_arrYards;
count = ARRAY_SIZE(g_arrYards);
break;
}
if (arrU[0].m_i > v)
{
m_scalerText = string("< ") + arrU[0].m_s;
m_metresDiff = m_minMetersWidth - 1.0;
}
else if (arrU[count-1].m_i <= v)
{
m_scalerText = string("> ") + arrU[count-1].m_s;
m_metresDiff = m_maxMetersWidth + 1.0;
}
else
for (int i = 0; i < count; ++i)
{
if (arrU[i].m_i > v)
{
m_metresDiff = arrU[i].m_i / m_conversionFn(1.0);
m_scalerText = arrU[i].m_s;
break;
}
}
}
Ruler::Ruler(Params const & p)
: base_t(p),
m_boundRects(1),
m_currSystem(0)
{}
void Ruler::setScreen(ScreenBase const & screen)
{
m_screen = screen;
setIsDirtyRect(true);
}
ScreenBase const & Ruler::screen() const
{
return m_screen;
}
void Ruler::setMinPxWidth(unsigned minPxWidth)
{
m_minPxWidth = minPxWidth;
setIsDirtyRect(true);
setIsDirtyLayout(true);
}
void Ruler::setMinMetersWidth(double v)
{
m_minMetersWidth = v;
setIsDirtyRect(true);
setIsDirtyLayout(true);
}
void Ruler::setMaxMetersWidth(double v)
{
m_maxMetersWidth = v;
setIsDirtyRect(true);
setIsDirtyLayout(true);
}
void Ruler::purge()
{
m_scaleText->purge();
m_dl.reset();
}
void Ruler::update()
{
checkDirtyLayout();
double k = visualScale();
ScreenBase const & screen = m_framework->GetNavigator().Screen();
int const rulerHeight = my::rounds(5 * k);
int const minPxWidth = my::rounds(m_minPxWidth * k);
// pivot() here is the down right point of the ruler.
// Get global points of ruler and distance according to minPxWidth.
m2::PointD pt1 = m_screen.PtoG(pivot());
m2::PointD pt0 = m_screen.PtoG(pivot() - m2::PointD(minPxWidth, 0));
m2::PointD pt1 = screen.PtoG(pivot());
m2::PointD pt0 = screen.PtoG(pivot() - m2::PointD(minPxWidth, 0));
double const distanceInMetres = ms::DistanceOnEarth(
MercatorBounds::YToLat(pt0.y), MercatorBounds::XToLon(pt0.x),
@ -225,79 +246,107 @@ void Ruler::update()
double const a = ang::AngleTo(pt1, pt0);
pt0 = MercatorBounds::GetSmPoint(pt1, cos(a) * m_metresDiff, sin(a) * m_metresDiff);
scalerWidthInPx = my::rounds(pivot().Length(m_screen.GtoP(pt0)));
scalerWidthInPx = my::rounds(pivot().Length(screen.GtoP(pt0)));
}
m2::PointD scalerOrg = pivot() + m2::PointD(-scalerWidthInPx / 2, rulerHeight / 2);
m_scalerOrg = pivot() + m2::PointD(-scalerWidthInPx / 2, rulerHeight / 2);
if (position() & graphics::EPosLeft)
scalerOrg.x -= scalerWidthInPx / 2;
m_scalerOrg.x -= scalerWidthInPx / 2;
if (position() & graphics::EPosRight)
scalerOrg.x += scalerWidthInPx / 2;
m_scalerOrg.x += scalerWidthInPx / 2;
if (position() & graphics::EPosAbove)
scalerOrg.y -= rulerHeight / 2;
m_scalerOrg.y -= rulerHeight / 2;
if (position() & graphics::EPosUnder)
scalerOrg.y += rulerHeight / 2;
m_scalerOrg.y += rulerHeight / 2;
m_path.clear();
m_path.push_back(scalerOrg);
m_path.push_back(scalerOrg + m2::PointD(scalerWidthInPx, 0));
m_scaleKoeff = scalerWidthInPx / m_cacheLength;
m_boundRect = m2::RectD(m_path[0], m_path[1]);
setIsDirtyRect(true);
if (position() & graphics::EPosLeft)
{
m_scaleText->setPosition(graphics::EPosAboveLeft);
m_scaleText->setPivot(m_scalerOrg + m2::PointD(scalerWidthInPx, 0) + m2::PointD(1 * k, -2 * k));
}
else
if (position() & graphics::EPosRight)
{
m_scaleText->setPosition(graphics::EPosAboveRight);
m_scaleText->setPivot(m_scalerOrg + m2::PointD(7 * k, -4 * k));
}
else
{
m_scaleText->setPosition(graphics::EPosAbove);
m_scaleText->setPivot(m_scalerOrg + m2::PointD(scalerWidthInPx / 2.0, 0) + m2::PointD(7 * k, -4 * k));
}
}
void Ruler::setFont(gui::Element::EState state, graphics::FontDesc const & f)
{
gui::Element::setFont(state, f);
m_scaleText->setFont(state, f);
}
vector<m2::AnyRectD> const & Ruler::boundRects() const
{
if (isDirtyRect())
{
m_boundRects[0] = m2::AnyRectD(m_boundRect);
m_boundRects[0] = m2::AnyRectD(m_scaleText->roughBoundRect());
setIsDirtyRect(false);
}
return m_boundRects;
}
void Ruler::cache()
{
layout();
graphics::Screen * cs = m_controller->GetCacheScreen();
m_dl.reset();
m_dl.reset(cs->createDisplayList());
cs->beginFrame();
cs->setDisplayList(m_dl.get());
cs->applySharpStates();
cs->setUseNormals(true);
double k = visualScale();
m2::PointD path[2] = {
m2::PointD(0, 0),
m2::PointD(0, 0) + m2::PointD(m_cacheLength, 0)
};
cs->drawPath(
path, ARRAY_SIZE(path), 0,
cs->mapInfo(graphics::Pen::Info(graphics::Color(0, 0, 0, 0x99), 4 * k, 0, 0, 0)),
depth());
cs->setDisplayList(0);
cs->setUseNormals(false);
cs->applyStates();
cs->endFrame();
}
void Ruler::draw(graphics::OverlayRenderer * s, math::Matrix<double, 3, 3> const & m) const
{
if (isVisible())
{
checkDirtyLayout();
double k = visualScale();
s->drawDisplayList(m_dl.get(),
math::Shift(
math::Scale(m, m2::PointD(m_scaleKoeff, 1.0)),
m_scalerOrg));
s->drawPath(
&m_path[0], m_path.size(), 0,
s->mapInfo(graphics::Pen::Info(graphics::Color(0, 0, 0, 0x99), 4 * k, 0, 0, 0)),
depth());
graphics::FontDesc f = font(state());
if (position() & graphics::EPosLeft)
s->drawText(f,
m_path[1] + m2::PointD(1 * k, -2 * k),
graphics::EPosAboveLeft,
m_scalerText,
depth(),
false);
else
if (position() & graphics::EPosRight)
s->drawText(f,
m_path[0] + m2::PointD(7 * k, -4 * k),
graphics::EPosAboveRight,
m_scalerText,
depth(),
false);
else
s->drawText(f,
(m_path[0] + m_path[1]) * 0.5
+ m2::PointD(7 * k, -4 * k),
graphics::EPosAbove,
m_scalerText,
depth(),
false);
m_scaleText->draw(s, m);
}
}

View file

@ -1,20 +1,30 @@
#pragma once
#include "../std/shared_ptr.hpp"
#include "../gui/element.hpp"
#include "../geometry/screenbase.hpp"
#include "../geometry/point2d.hpp"
#include "../geometry/any_rect2d.hpp"
#include "../graphics/font_desc.hpp"
#include "../graphics/display_list.hpp"
namespace graphics
{
namespace gl
{
class Screen;
class OverlayRenderer;
}
}
namespace gui
{
class CachedTextView;
}
class Framework;
class Ruler : public gui::Element
{
private:
@ -28,16 +38,13 @@ private:
double m_maxMetersWidth;
//@}
ScreenBase m_screen;
/// Current diff in units between two endpoints of the ruler.
/// @todo No need to store it here. It's calculated once for calculating ruler's m_path.
double m_metresDiff;
string m_scalerText;
/// @todo Make static array with 2 elements.
vector<m2::PointD> m_path;
double m_cacheLength;
double m_scaleKoeff;
m2::PointD m_scalerOrg;
m2::RectD m_boundRect;
@ -51,24 +58,34 @@ private:
int m_currSystem;
void CalcMetresDiff(double v);
shared_ptr<gui::CachedTextView> m_scaleText;
scoped_ptr<graphics::DisplayList> m_dl;
Framework * m_framework;
public:
typedef base_t::Params Params;
struct Params : public Element::Params
{
Framework * m_framework;
Params();
};
Ruler(Params const & p);
void setScreen(ScreenBase const & screen);
ScreenBase const & screen() const;
void setController(gui::Controller * controller);
void setMinPxWidth(unsigned minPxWidth);
void setMinMetersWidth(double v);
void setMaxMetersWidth(double v);
void setFontDesc(graphics::FontDesc const & fontDesc);
void setFont(gui::Element::EState state, graphics::FontDesc const & f);
vector<m2::AnyRectD> const & boundRects() const;
void draw(graphics::OverlayRenderer * r, math::Matrix<double, 3, 3> const & m) const;
void layout();
void update();
void layout();
void cache();
void purge();
};