void graphics_context::fill_shape(const point& aCentre, const vertex_list3& aVertices, const colour& aColour) const { vertex_list2 vertices; vertices.reserve(aVertices.size()); for (const auto& v : aVertices) vertices.push_back(to_device_units(v.xy) + iOrigin.to_vector()); iNativeGraphicsContext->fill_shape(to_device_units(aCentre) + iOrigin, vertices, aColour); }
margins units_converter::to_device_units(const margins& aValue) const { return margins{ to_device_units(iContext.device_metrics().extents(), size{ aValue.left, 0 }).cx, to_device_units(iContext.device_metrics().extents(), size{ 0, aValue.top }).cy, to_device_units(iContext.device_metrics().extents(), size{ aValue.right, 0 }).cx, to_device_units(iContext.device_metrics().extents(), size{ 0, aValue.bottom }).cy }; }
path graphics_context::to_device_units(const path& aValue) const { path result = aValue; result.set_position(to_device_units(result.position())); for (std::size_t i = 0; i < result.paths().size(); ++i) for (std::size_t j = 0; j < result.paths()[i].size(); ++j) result.paths()[i][j] = to_device_units(result.paths()[i][j]); return result; }
void graphics_context::clip_to(const path& aPath, dimension aPathOutline) const { path path = to_device_units(aPath); path.set_shape(path::ConvexPolygon); path.set_position(path.position() + iOrigin); iNativeGraphicsContext->clip_to(path, aPathOutline); }
size graphics_context::draw_glyph(const point& aPoint, const glyph& aGlyph, const font& aFont, const colour& aColour) const { size result; { glyph_drawing gd(*this); result = iNativeGraphicsContext->draw_glyph(to_device_units(aPoint) + iOrigin, aGlyph, aFont, aColour); } if (iDrawingGlyphs == 0 && (aGlyph.underline() || (mnemonics_shown() && aGlyph.mnemonic()))) draw_glyph_underline(aPoint, aGlyph, aFont, aColour); return result; }
rect units_converter::to_device_units(const size& aExtents, const rect& aValue) const { return rect(to_device_units(aExtents, aValue.position()), to_device_units(aExtents, aValue.extents())); }
void graphics_context::fill_arc(const point& aCentre, dimension aRadius, angle aStartAngle, angle aEndAngle, const colour& aColour) const { iNativeGraphicsContext->fill_arc(to_device_units(aCentre) + iOrigin, aRadius, aStartAngle, aEndAngle, aColour); }
void graphics_context::fill_circle(const point& aCentre, dimension aRadius, const colour& aColour) const { iNativeGraphicsContext->fill_circle(to_device_units(aCentre) + iOrigin, aRadius, aColour); }
void graphics_context::fill_rounded_rect(const rect& aRect, dimension aRadius, const gradient& aGradient) const { iNativeGraphicsContext->fill_rounded_rect(to_device_units(aRect) + iOrigin, aRadius, aGradient); }
dimension units_converter::to_device_units(dimension aValue) const { return to_device_units(iContext.device_metrics().extents(), size{ aValue, 0 }).cx; }
void graphics_context::clip_to(const rect& aRect) const { iNativeGraphicsContext->clip_to(to_device_units(aRect) + iOrigin); }
void graphics_context::draw_multiline_text(const point& aPoint, const string& aText, const font& aFont, dimension aMaxWidth, const colour& aColour, alignment aAlignment, bool aUseCache) const { const auto& glyphText = aUseCache && !iGlyphTextCache->empty() ? *iGlyphTextCache : to_glyph_text(aText.begin(), aText.end(), aFont); if (aUseCache && iGlyphTextCache->empty()) *iGlyphTextCache = glyphText; typedef std::pair<glyph_text::const_iterator, glyph_text::const_iterator> line_t; typedef std::vector<line_t> lines_t; lines_t lines; std::array<glyph, 2> delimeters = { glyph(text_direction::Whitespace, '\r'), glyph(text_direction::Whitespace, '\n') }; neolib::tokens(glyphText.cbegin(), glyphText.cend(), delimeters.begin(), delimeters.end(), lines, 0, false); size textExtent = multiline_text_extent(aText, aFont, aMaxWidth, aUseCache); point pos = aPoint; for (lines_t::const_iterator i = lines.begin(); i != lines.end(); ++i) { const auto& line = (logical_coordinates()[1] > logical_coordinates()[3] ? *i : *(lines.rbegin() + (i - lines.begin()))); if (aMaxWidth == 0) { point linePos = pos; size lineExtent = from_device_units(glyph_text::extents(aFont, line.first, line.second)); if (glyph_text_direction(line.first, line.second) == text_direction::RTL) linePos.x += textExtent.cx - lineExtent.cx; draw_glyph_text(linePos, line.first, line.second, aFont, aColour); pos.y += lineExtent.cy; } else { glyph_text::const_iterator next = line.first; glyph_text::const_iterator lineStart = next; glyph_text::const_iterator lineEnd = line.second; dimension maxWidth = to_device_units(size(aMaxWidth, 0)).cx; dimension lineWidth = 0; while(next != line.second) { bool gotLine = false; if (lineWidth + next->advance().cx > maxWidth) { std::pair<glyph_text::const_iterator, glyph_text::const_iterator> wordBreak = glyphText.word_break(lineStart, next); lineWidth -= glyph_text::extents(aFont, wordBreak.first, next).cx; lineEnd = wordBreak.first; next = wordBreak.second; if (lineEnd == next) { while(lineEnd != line.second && (lineEnd + 1)->source() == wordBreak.first->source()) ++lineEnd; next = lineEnd; } gotLine = true; } else { lineWidth += next->advance().cx; ++next; } if (gotLine || next == line.second) { point linePos = pos; if (aAlignment == alignment::Left && glyph_text_direction(lineStart, next) == text_direction::RTL || aAlignment == alignment::Right && glyph_text_direction(lineStart, next) == text_direction::LTR) linePos.x += textExtent.cx - from_device_units(size(lineWidth, 0)).cx; else if (aAlignment == alignment::Centre) linePos.x += std::ceil((textExtent.cx - from_device_units(size(lineWidth, 0)).cx) / 2); draw_glyph_text(linePos, lineStart, lineEnd, aFont, aColour); pos.y += glyph_text::extents(aFont, lineStart, lineEnd).cy; lineStart = next; lineEnd = line.second; lineWidth = 0; } } if (line.first == line.second) pos.y += font().height(); } } }
void graphics_context::draw_arc(const point& aCentre, dimension aRadius, angle aStartAngle, angle aEndAngle, const pen& aPen) const { iNativeGraphicsContext->draw_arc(to_device_units(aCentre) + iOrigin, aRadius, aStartAngle, aEndAngle, aPen); }
void graphics_context::draw_circle(const point& aCentre, dimension aRadius, const pen& aPen) const { iNativeGraphicsContext->draw_circle(to_device_units(aCentre) + iOrigin, aRadius, aPen); }
void graphics_context::draw_rounded_rect(const rect& aRect, dimension aRadius, const pen& aPen) const { iNativeGraphicsContext->draw_rounded_rect(to_device_units(aRect) + iOrigin, aRadius, aPen); }
void graphics_context::draw_rect(const rect& aRect, const pen& aPen) const { iNativeGraphicsContext->draw_rect(to_device_units(aRect) + iOrigin, aPen); }
void graphics_context::draw_line(const point& aFrom, const point& aTo, const pen& aPen) const { iNativeGraphicsContext->draw_line(to_device_units(aFrom) + iOrigin, to_device_units(aTo) + iOrigin, aPen); }
void graphics_context::draw_pixel(const point& aPoint, const colour& aColour) const { iNativeGraphicsContext->fill_rect(rect{ to_device_units(aPoint) + iOrigin, size{1.0, 1.0} }, aColour); }
void graphics_context::set_origin(const point& aOrigin) const { iOrigin = to_device_units(aOrigin); }
void graphics_context::fill_and_draw_path(const path& aPath, const colour& aFillColour, const pen& aOutlinePen) const { path path = to_device_units(aPath); path.set_position(path.position() + iOrigin); iNativeGraphicsContext->fill_and_draw_path(path, aFillColour, aOutlinePen); }
size graphics_context::multiline_text_extent(const string& aText, const font& aFont, dimension aMaxWidth, bool aUseCache) const { const auto& glyphText = aUseCache && !iGlyphTextCache->empty() ? *iGlyphTextCache : to_glyph_text(aText.begin(), aText.end(), aFont); if (aUseCache && iGlyphTextCache->empty()) *iGlyphTextCache = glyphText; typedef std::pair<glyph_text::const_iterator, glyph_text::const_iterator> line_t; typedef std::vector<line_t> lines_t; lines_t lines; std::array<glyph, 2> delimeters = { glyph(text_direction::Whitespace, '\r'), glyph(text_direction::Whitespace, '\n') }; neolib::tokens(glyphText.cbegin(), glyphText.cend(), delimeters.begin(), delimeters.end(), lines, 0, false); size result; for (lines_t::const_iterator i = lines.begin(); i != lines.end(); ++i) { if (aMaxWidth == 0) { size lineExtent = from_device_units(glyph_text::extents(aFont, i->first, i->second)); result.cx = std::max(result.cx, lineExtent.cx); result.cy += lineExtent.cy; } else { glyph_text::const_iterator next = i->first; glyph_text::const_iterator lineStart = next; glyph_text::const_iterator lineEnd = i->second; dimension maxWidth = to_device_units(size(aMaxWidth, 0)).cx; dimension lineWidth = 0; bool gotLine = false; while(next != i->second) { if (lineWidth + next->advance().cx > maxWidth) { std::pair<glyph_text::const_iterator, glyph_text::const_iterator> wordBreak = glyphText.word_break(lineStart, next); lineWidth -= glyph_text::extents(aFont, wordBreak.first, next).cx; lineEnd = wordBreak.first; next = wordBreak.second; if (lineEnd == next) { while(lineEnd != i->second && (lineEnd + 1)->source() == wordBreak.first->source()) ++lineEnd; next = lineEnd; } gotLine = true; } else { lineWidth += next->advance().cx; ++next; } if (gotLine || next == i->second) { result.cx = std::max(result.cx, from_device_units(size(lineWidth, 0)).cx); result.cy += from_device_units(glyph_text::extents(aFont, i->first, i->second)).cy; lineStart = next; lineEnd = i->second; lineWidth = 0; gotLine = false; } } } } if (result.cy == 0) result.cy = from_device_units(size(0, aFont.height())).cy; return result; }
void graphics_context::draw_texture(const point& aPoint, const i_texture& aTexture, const rect& aTextureRect, const optional_colour& aColour) const { iNativeGraphicsContext->draw_texture(rect{to_device_units(aPoint) + iOrigin, aTexture.extents()}.to_vector(), aTexture, aTextureRect, aColour); }
void graphics_context::scissor_on(const rect& aRect) const { iNativeGraphicsContext->scissor_on(to_device_units(aRect) + iOrigin); }
dimension units_converter::to_device_units(const size& aExtents, dimension aValue) const { return to_device_units(aExtents, size{ aValue, 0 }).cx; }
void graphics_context::draw_path(const path& aPath, const pen& aPen) const { path path = to_device_units(aPath); path.set_position(path.position() + iOrigin); iNativeGraphicsContext->draw_path(path, aPen); }
rect units_converter::to_device_units(const rect& aValue) const { return to_device_units(iContext.device_metrics().extents(), aValue); }
void graphics_context::draw_texture(const texture_map& aTextureMap, const i_texture& aTexture, const optional_colour& aColour) const { iNativeGraphicsContext->draw_texture(to_device_units(aTextureMap) + iOrigin.to_vector(), aTexture, rect(point(0.0, 0.0), aTexture.extents()), aColour); }
void graphics_context::fill_rect(const rect& aRect, const colour& aColour) const { iNativeGraphicsContext->fill_rect(to_device_units(aRect) + iOrigin, aColour); }
void graphics_context::draw_texture(const texture_map& aTextureMap, const i_texture& aTexture, const rect& aTextureRect, const optional_colour& aColour) const { iNativeGraphicsContext->draw_texture(to_device_units(aTextureMap) + iOrigin.to_vector(), aTexture, aTextureRect, aColour); }
void graphics_context::fill_rect(const rect& aRect, const gradient& aGradient) const { iNativeGraphicsContext->fill_rect(to_device_units(aRect) + iOrigin, aGradient); }