renderer_i::texture sfml2_renderer::make_text_label(const std::u32string& text, const color& fill, const font& font, float point_size, text_style style) { const sfml2_font& tmp = dynamic_cast<const sfml2_font&>(*font); const sf::Font& sffont = tmp.sf_font(); sf::String str(reinterpret_cast<const sf::Uint32*>(text.c_str())); sf::Text label(str, sffont, (int)point_size); sf::RenderTexture rt; auto size = label.getLocalBounds(); if (!rt.create(size.width + 1, font->height(point_size) + 1)) throw std::runtime_error("cannot create sf::RenderTexture"); rt.clear(sf::Color::Transparent); label.move(0, -label.getLocalBounds().top); label.setColor(col(fill)); label.setStyle(static_cast<sf::Uint32>(style)); rt.draw(label); rt.display(); return texture{new sfml2_texture{rt.getTexture()}}; }
void graphics_context::draw_glyph_underline(const point& aPoint, const glyph& aGlyph, const font& aFont, const colour& aColour) const { auto yLine = logical_coordinates()[1] > logical_coordinates()[3] ? (aFont.height() + aFont.descender()) - std::ceil(aFont.native_font_face().underline_position()) : -aFont.descender() + std::ceil(aFont.native_font_face().underline_position()); const i_glyph_texture& glyphTexture = !aGlyph.use_fallback() ? aFont.native_font_face().glyph_texture(aGlyph) : aGlyph.fallback_font(aFont).native_font_face().glyph_texture(aGlyph); draw_line( aPoint + point{ glyphTexture.placement().x, yLine }, aPoint + point{ glyphTexture.placement().x + glyphTexture.extents().cx, yLine }, pen{ aColour, std::ceil(aFont.native_font_face().underline_thickness()) }); }
static neogfx::size extents(const font& aFont, const_iterator aBegin, const_iterator aEnd) { neogfx::size result; bool usingNormal = false; bool usingFallback = false; for (glyph_text::const_iterator i = aBegin; i != aEnd; ++i) { result.cx += i->advance().cx; if (!i->use_fallback()) usingNormal = true; else usingFallback = true; } if (usingNormal || !usingFallback) result.cy = aFont.height(); if (usingFallback) result.cy = std::max(result.cy, aFont.fallback().height()); return neogfx::size(std::ceil(result.cx), std::ceil(result.cy)); }
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; }
//////////////////////////////////////////////////////////// /// Toogle button style //////////////////////////////////////////////////////////// void TBtStyle::draw_toggle_button( const canvas& c, const rectangle& rect, const bool enabled, const font& mfont, const long lastx, const long lasty, const ustring& name, const bool is_depressed, const bool is_checked ) const { rectangle area = rect.intersect( c ); if ( area.is_empty() ) return; unsigned char red, green, blue; if ( enabled ) { red = 0; green = 0; blue = 0; } else { red = 128; green = 128; blue = 128; } // compute the name length if it hasn't already been computed if ( name_width == 0 ) { unsigned long height; mfont.compute_size( name, name_width, height ); } // figure out where the name string should appear rectangle name_rect; const unsigned long width = name_width; const unsigned long height = mfont.height(); name_rect.set_left(( rect.right() + rect.left() - width ) / 2 ); name_rect.set_top(( rect.bottom() + rect.top() - height ) / 2 + 1 ); name_rect.set_right( name_rect.left() + width - 1 ); name_rect.set_bottom( name_rect.top() + height ); long d = 0; if ( is_checked ) d = 1; if ( is_depressed ) d = 2; name_rect.set_left( name_rect.left() + d ); name_rect.set_right( name_rect.right() + d ); name_rect.set_top( name_rect.top() + d ); name_rect.set_bottom( name_rect.bottom() + d ); // now draw the edge of the button if ( is_checked || is_depressed ) { fill_rect_with_vertical_gradient( c, rect, rgb_pixel( 233, 241, 246 ), rgb_pixel( 197, 220, 232 ) ); mfont.draw_string( c, name_rect, name, rgb_pixel( red, green, blue ) ); draw_button_down( c, rect ); } else { fill_rect_with_vertical_gradient( c, rect, rgb_pixel( 241, 241, 241 ), rgb_pixel( 210, 210, 210 ) ); mfont.draw_string( c, name_rect, name, rgb_pixel( red, green, blue ) ); draw_button_up( c, rect ); } }