From 97d2659c5179b6de5d248c70dc8d22d863d5cde7 Mon Sep 17 00:00:00 2001 From: rachytski Date: Thu, 24 Jan 2013 18:57:09 +0300 Subject: [PATCH] added gui::Balloon element. --- graphics/graphics.pro | 3 +- graphics/path.hpp | 44 ++++++++ gui/balloon.cpp | 248 ++++++++++++++++++++++++++++++++++++++++++ gui/balloon.hpp | 78 +++++++++++++ gui/gui.pro | 2 + 5 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 graphics/path.hpp create mode 100644 gui/balloon.cpp create mode 100644 gui/balloon.hpp diff --git a/graphics/graphics.pro b/graphics/graphics.pro index 892d5e57d6..1e986b619b 100644 --- a/graphics/graphics.pro +++ b/graphics/graphics.pro @@ -71,8 +71,8 @@ SOURCES += \ defines.cpp \ icon.cpp \ brush.cpp \ - geometry_pipeline.cpp \ pipeline_manager.cpp \ + geometry_pipeline.cpp \ path_view.cpp \ HEADERS += \ @@ -143,6 +143,7 @@ HEADERS += \ pipeline_manager.hpp \ vertex_stream.hpp \ path_view.hpp \ + path.hpp \ win32* { SOURCES += opengl/opengl_win32.cpp diff --git a/graphics/path.hpp b/graphics/path.hpp new file mode 100644 index 0000000000..ba8a239e56 --- /dev/null +++ b/graphics/path.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "../geometry/point2d.hpp" + +namespace graphics +{ + template + class Path + { + private: + + vector > m_pts; + + public: + + void reset(m2::Point const & pt) + { + m_pts.clear(); + m_pts.push_back(pt); + } + + void lineRel(m2::Point const & pt) + { + m2::Point const & p = m_pts.back(); + m_pts.push_back(p + pt); + } + + void eclipseArcRel(m2::Point const & pt) + { + /// TODO : write implementation + } + + m2::Point const * points() const + { + ASSERT(!m_pts.empty(), ()); + return &m_pts[0]; + } + + unsigned size() const + { + return m_pts.size(); + } + }; +} diff --git a/gui/balloon.cpp b/gui/balloon.cpp new file mode 100644 index 0000000000..df97ce32e6 --- /dev/null +++ b/gui/balloon.cpp @@ -0,0 +1,248 @@ +#include "balloon.hpp" +#include "controller.hpp" + +#include "../geometry/transformations.hpp" + +#include "../graphics/overlay_renderer.hpp" +#include "../graphics/brush.hpp" +#include "../graphics/screen.hpp" +#include "../graphics/path.hpp" + +namespace gui +{ + Balloon::Params::Params() + {} + + Balloon::Balloon(Params const & p) + : Element(p), + m_boundRects(1), + m_text(p.m_text), + m_image(p.m_image) + { + m_textMarginLeft = p.m_textMarginLeft; + m_textMarginRight = p.m_textMarginRight; + m_textMarginTop = p.m_textMarginTop; + m_textMarginBottom = p.m_textMarginBottom; + + m_imageMarginLeft = p.m_imageMarginLeft; + m_imageMarginRight = p.m_imageMarginRight; + m_imageMarginTop = p.m_imageMarginTop; + m_imageMarginBottom = p.m_imageMarginBottom; + + TextView::Params tp; + + tp.m_text = m_text; + tp.m_position = graphics::EPosRight; + tp.m_pivot = m2::PointD(0, 0); + tp.m_depth = depth(); + + m_textView.reset(new TextView(tp)); + + m_textView->setFont(Element::EActive, graphics::FontDesc(20, graphics::Color(0, 0, 0, 255), true)); + + ImageView::Params ip; + + ip.m_pivot = m2::PointD(0, 0); + ip.m_position = graphics::EPosRight; + ip.m_depth = depth(); + ip.m_image = m_image; + + m_imageView.reset(new ImageView(ip)); + + m_arrowHeight = 20; + m_arrowAngle = ang::DegreeToRad(90); + m_arrowWidth = 2 * tan(m_arrowAngle / 2) * m_arrowHeight; + } + + vector const & Balloon::boundRects() const + { + if (isDirtyRect()) + { + m2::RectD tr = m_textView->roughBoundRect(); + m2::RectD ir = m_imageView->roughBoundRect(); + + double k = visualScale(); + + tr.setMinX(tr.minX() - m_textMarginLeft * k); + tr.setMinY(tr.minY() - m_textMarginTop * k); + tr.setMaxX(tr.maxX() + m_textMarginRight * k); + tr.setMaxY(tr.maxY() + m_textMarginBottom * k); + + ir.setMinX(ir.minX() - m_imageMarginLeft * k); + ir.setMinY(ir.minY() - m_imageMarginTop * k); + ir.setMaxX(ir.maxX() + m_imageMarginRight * k); + ir.setMaxY(ir.maxY() + m_imageMarginBottom * k); + + m2::RectD r(tr); + r.Add(ir); + + graphics::EPosition pos = position(); + + if (pos == graphics::EPosAbove) + r.setMaxY(r.maxY() + m_arrowHeight); + else if (pos == graphics::EPosUnder) + r.setMinY(r.minY() - m_arrowHeight); + else if (pos == graphics::EPosRight) + r.setMinX(r.minX() - m_arrowHeight); + else if (pos == graphics::EPosLeft) + r.setMaxX(r.maxX() + m_arrowHeight); + + m_boundRects[0] = m2::AnyRectD(r); + + setIsDirtyRect(false); + } + + return m_boundRects; + } + + void Balloon::layout() + { + m2::RectD tr = m_textView->roughBoundRect(); + m2::RectD ir = m_imageView->roughBoundRect(); + + double w = m_textMarginLeft + tr.SizeX() + m_textMarginRight + + m_imageMarginLeft + ir.SizeX() + m_imageMarginRight; + + double h = max(ir.SizeY() + m_imageMarginBottom + m_imageMarginTop, + tr.SizeY() + m_textMarginBottom + m_textMarginTop); + + m2::PointD const & pv = pivot(); + graphics::EPosition pos = position(); + + if (pos == graphics::EPosAbove) + { + m_textView->setPivot(m2::PointD(pv.x - w / 2 + m_textMarginLeft, + pv.y - h / 2 - m_arrowHeight)); + m_imageView->setPivot(m2::PointD(pv.x + w / 2 - m_imageMarginRight - ir.SizeX(), + pv.y - h / 2 - m_arrowHeight)); + } + else if (pos == graphics::EPosUnder) + { + m_textView->setPivot(m2::PointD(pv.x - w / 2 + m_textMarginLeft, + pv.y + h / 2 + m_arrowHeight)); + m_imageView->setPivot(m2::PointD(pv.x + w / 2 - m_imageMarginRight - ir.SizeX(), + pv.y + h / 2 + m_arrowHeight)); + } + else if (pos == graphics::EPosLeft) + { + m_textView->setPivot(m2::PointD(pv.x - w - m_arrowHeight + m_textMarginLeft, + pv.y)); + m_imageView->setPivot(m2::PointD(pv.x - m_arrowHeight - m_imageMarginRight - ir.SizeX(), + pv.y)); + } + else if (pos == graphics::EPosRight) + { + m_textView->setPivot(m2::PointD(pv.x + m_arrowHeight + m_textMarginLeft, + pv.y)); + m_imageView->setPivot(m2::PointD(pv.x + m_arrowHeight + m_textMarginLeft + tr.SizeX() + m_textMarginRight + m_imageMarginRight, + pv.y)); + } + + m_textView->setPosition(graphics::EPosRight); + m_imageView->setPosition(graphics::EPosRight); + } + + void Balloon::setPivot(m2::PointD const & pv) + { + Element::setPivot(pv); + layout(); + } + + void Balloon::cache() + { + graphics::Screen * cs = m_controller->GetCacheScreen(); + + m_displayList.reset(); + m_displayList.reset(cs->createDisplayList()); + + cs->beginFrame(); + cs->setDisplayList(m_displayList.get()); + + m2::RectD const & r = roughBoundRect(); + + double bw = r.SizeX(); + double bh = r.SizeY(); + double aw = m_arrowWidth; + double ah = m_arrowHeight; + + graphics::EPosition pos = position(); + graphics::Path p; + + if (pos & graphics::EPosAbove) + { + bh -= m_arrowHeight; + + p.reset(m2::PointF(-aw / 2, -ah)); + p.lineRel(m2::PointF(-bw / 2 + aw / 2, 0)); + p.lineRel(m2::PointF(0, -bh)); + p.lineRel(m2::PointF(bw, 0)); + p.lineRel(m2::PointF(0, bh)); + p.lineRel(m2::PointF(-bw / 2 + aw / 2, 0)); + p.lineRel(m2::PointF(-aw / 2, ah)); + p.lineRel(m2::PointF(-aw / 2, -ah)); + } + else if (pos & graphics::EPosUnder) + { + bh -= m_arrowHeight; + + p.reset(m2::PointF(aw / 2, ah)); + p.lineRel(m2::PointF(bw / 2 - aw / 2, 0)); + p.lineRel(m2::PointF(0, bh)); + p.lineRel(m2::PointF(-bw, 0)); + p.lineRel(m2::PointF(0, -bh)); + p.lineRel(m2::PointF(bw / 2 - aw / 2, 0)); + p.lineRel(m2::PointF(aw / 2, -ah)); + p.lineRel(m2::PointF(aw / 2, ah)); + } + + graphics::Color c(0, 0, 0, 128); + + uint32_t colorID = cs->mapInfo(graphics::Brush::Info(c)); + + cs->drawTrianglesFan(p.points(), p.size(), colorID, depth()); + + cs->setDisplayList(0); + cs->endFrame(); + } + + void Balloon::purge() + { + m_textView->purge(); + m_imageView->purge(); + m_displayList.reset(); + } + + void Balloon::setController(Controller * controller) + { + Element::setController(controller); + m_textView->setController(controller); + m_imageView->setController(controller); + } + + void Balloon::draw(graphics::OverlayRenderer * r, + math::Matrix const & m) const + { + if (isVisible()) + { + checkDirtyLayout(); + +// r->drawRectangle(roughBoundRect(), graphics::Color(0, 0, 255, 128), depth()); +// r->drawRectangle(m_textView->roughBoundRect(), graphics::Color(0, 255, 255, 128), depth()); +// r->drawRectangle(m_imageView->roughBoundRect(), graphics::Color(0, 255, 0, 128), depth()); + + math::Matrix drawM = math::Shift( + math::Identity(), + pivot() * m); + + r->drawDisplayList(m_displayList.get(), drawM); + + m_textView->draw(r, m); + m_imageView->draw(r, m); + + m2::RectD r1(pivot() * m, pivot() * m); + r1.Inflate(2, 2); + + r->drawRectangle(r1, graphics::Color(255, 0, 0, 255), graphics::maxDepth); + } + } +} diff --git a/gui/balloon.hpp b/gui/balloon.hpp new file mode 100644 index 0000000000..b13efd2422 --- /dev/null +++ b/gui/balloon.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "element.hpp" +#include "text_view.hpp" +#include "image_view.hpp" + +#include "../graphics/font_desc.hpp" +#include "../graphics/image.hpp" + +#include "../base/string_utils.hpp" +#include "../base/matrix.hpp" + +#include "../std/scoped_ptr.hpp" + +namespace graphics +{ + class OverlayRenderer; +} + +namespace gui +{ + class Balloon : public Element + { + private: + + mutable vector m_boundRects; + + void cache(); + void purge(); + void layout(); + + scoped_ptr m_textView; + scoped_ptr m_imageView; + scoped_ptr m_displayList; + + string m_text; + graphics::Image::Info m_image; + + double m_textMarginLeft; + double m_textMarginTop; + double m_textMarginRight; + double m_textMarginBottom; + + double m_imageMarginLeft; + double m_imageMarginTop; + double m_imageMarginRight; + double m_imageMarginBottom; + + double m_arrowHeight; + double m_arrowWidth; + double m_arrowAngle; + + public: + + struct Params : public Element::Params + { + string m_text; + graphics::Image::Info m_image; + double m_textMarginLeft; + double m_textMarginTop; + double m_textMarginRight; + double m_textMarginBottom; + double m_imageMarginLeft; + double m_imageMarginTop; + double m_imageMarginRight; + double m_imageMarginBottom; + Params(); + }; + + Balloon(Params const & p); + + vector const & boundRects() const; + void draw(graphics::OverlayRenderer * r, math::Matrix const & m) const; + + void setController(Controller * controller); + void setPivot(m2::PointD const & pv); + }; +} diff --git a/gui/gui.pro b/gui/gui.pro index 092abd6b2e..d7a6c56f29 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -14,6 +14,7 @@ HEADERS += \ element.hpp \ button.hpp \ text_view.hpp \ + balloon.hpp \ image_view.hpp \ SOURCES += \ @@ -21,4 +22,5 @@ SOURCES += \ element.cpp \ button.cpp \ text_view.cpp \ + balloon.cpp \ image_view.cpp \