dialektos
Revision | 636961c92ee598e3469ecd50898f6d515550f3f5 (tree) |
---|---|
Time | 2009-07-12 18:47:37 |
Author | Aiwota Programmer <aiwotaprog@tett...> |
Commiter | Aiwota Programmer |
TextView strict layout.
@@ -20,9 +20,12 @@ | ||
20 | 20 | |
21 | 21 | #include "text_element_anchor.hxx" |
22 | 22 | |
23 | +#include <glibmm/refptr.h> | |
23 | 24 | #include <gdkmm/cursor.h> |
24 | -#include <pangomm/attrlist.h> | |
25 | -#include <pangomm/attributes.h> | |
25 | +#include <gdkmm/gc.h> | |
26 | +#include <gtkmm/enums.h> | |
27 | + | |
28 | +#include "text_view_drawing_set.hxx" | |
26 | 29 | |
27 | 30 | |
28 | 31 | namespace dialektos { |
@@ -33,10 +36,29 @@ Gdk::CursorType Anchor::get_cursor_type() const { | ||
33 | 36 | return Gdk::HAND2; |
34 | 37 | } |
35 | 38 | |
36 | -void Anchor::set_attributes(Pango::AttrList& list) const { | |
37 | - using namespace Pango; | |
38 | - AttrInt underline = Attribute::create_attr_underline(UNDERLINE_SINGLE); | |
39 | - list.insert(underline); | |
39 | +void Anchor::do_draw_glyphs(text_view::DrawingSet& set, | |
40 | + const Pango::Item& item, const Pango::GlyphString& glyphs, | |
41 | + double x, double y, bool in_selection) const { | |
42 | + | |
43 | + Glib::RefPtr<const Gdk::GC> gc = set.style->get_text_gc( | |
44 | + in_selection ? Gtk::STATE_SELECTED : Gtk::STATE_NORMAL); | |
45 | + | |
46 | + set.window->draw_glyphs(gc, item.get_analysis().get_font(), | |
47 | + x, y - set.adj_value + get_metrics().get_ascent() / Pango::SCALE, glyphs); | |
48 | + | |
49 | + do_draw_underline(set, gc, double(glyphs.get_width()) / Pango::SCALE, x, y); | |
50 | +} | |
51 | + | |
52 | +void Anchor::do_draw_underline(text_view::DrawingSet& set, | |
53 | + const Glib::RefPtr<const Gdk::GC>& gc, | |
54 | + double width, double x, double y) const { | |
55 | + | |
56 | + const int underline = get_metrics().get_underline_position(); | |
57 | + const int underline_y = y - set.adj_value + | |
58 | + double(get_metrics().get_ascent() - underline) / Pango::SCALE; | |
59 | + | |
60 | + set.window->draw_line(gc, std::ceil(x), underline_y, | |
61 | + std::ceil(x + width), underline_y); | |
40 | 62 | } |
41 | 63 | |
42 | 64 |
@@ -23,8 +23,9 @@ | ||
23 | 23 | |
24 | 24 | #include <glibmm/ustring.h> |
25 | 25 | #include <gdkmm/cursor.h> |
26 | -#include <pangomm/attrlist.h> | |
27 | 26 | #include <boost/range.hpp> |
27 | +#include <pangomm/item.h> | |
28 | +#include <pangomm/glyphstring.h> | |
28 | 29 | #include <boost/unordered_map.hpp> |
29 | 30 | #include "text_element_plain.hxx" |
30 | 31 |
@@ -63,11 +64,12 @@ public: | ||
63 | 64 | Glib::ustring get_href() const { return href_; } |
64 | 65 | |
65 | 66 | protected: |
66 | - /*! @brief set attributes for drawing the anchor text element. | |
67 | - * | |
68 | - * @param list | |
69 | - */ | |
70 | - virtual void set_attributes(Pango::AttrList& list) const; | |
67 | + virtual void do_draw_glyphs(text_view::DrawingSet&, const Pango::Item&, | |
68 | + const Pango::GlyphString&, double x, double y, | |
69 | + bool in_selection) const; | |
70 | + | |
71 | + void do_draw_underline(text_view::DrawingSet&, | |
72 | + const Glib::RefPtr<const Gdk::GC>&, double width, double x, double y) const; | |
71 | 73 | |
72 | 74 | private: |
73 | 75 | virtual Anchor* do_clone() const { return new Anchor(*this); } |
@@ -20,6 +20,9 @@ | ||
20 | 20 | |
21 | 21 | #include "text_element_char_size_cache.hxx" |
22 | 22 | |
23 | +#include <pangomm/glyphstring.h> | |
24 | +#include <boost/foreach.hpp> | |
25 | + | |
23 | 26 | |
24 | 27 | namespace dialektos { |
25 | 28 |
@@ -33,44 +36,42 @@ inline gunichar ucs4_to_ucs2(const gunichar ucs4) { | ||
33 | 36 | } // anonymous namespace |
34 | 37 | |
35 | 38 | |
36 | -CharSizeCache::CharSizeCache() { initialize(); } | |
39 | +CharSizeCache::ArrayClass::ArrayClass() : array_() { | |
40 | + BOOST_FOREACH(int& i, array_) i = -1; | |
41 | +} | |
37 | 42 | |
38 | -void CharSizeCache::initialize() { | |
39 | - for (size_t i = 0; i != ArrayType::size(); ++i) { | |
40 | - char_width_cache[i] = -1; | |
41 | - char_height_cache[i] = -1; | |
42 | - bold_char_width_cache[i] = -1; | |
43 | - bold_char_height_cache[i] = -1; | |
44 | - } | |
43 | + | |
44 | +CharSizeCache::CharSizeCache() {} | |
45 | + | |
46 | +CharSizeCache::ArrayClass& CharSizeCache::get_map(int font_id) { | |
47 | + return map_[font_id]; | |
45 | 48 | } |
46 | 49 | |
47 | -void CharSizeCache::get_char_size(gunichar uch, | |
48 | - Glib::RefPtr<Pango::Layout>& layout, | |
49 | - double& width, double& height, bool bold) { | |
50 | +double CharSizeCache::get_char_width( | |
51 | + gunichar uch, const Pango::Item& item, ArrayClass& cache) { | |
50 | 52 | |
51 | 53 | const gunichar ucs2 = ucs4_to_ucs2(uch); |
52 | 54 | |
53 | - int w = get_width_cache_array(bold)[ucs2]; | |
54 | - int h = get_height_cache_array(bold)[ucs2]; | |
55 | - | |
56 | - if (w == -1 || h == -1) { | |
57 | - Glib::ustring ch(1, ucs2); | |
58 | - layout->set_text(ch); | |
59 | - layout->get_size(w, h); | |
60 | - get_width_cache_array(bold)[ucs2] = w; | |
61 | - get_height_cache_array(bold)[ucs2] = h; | |
55 | + int width = cache.array_[ucs2]; | |
56 | + if (width == -1) { | |
57 | + const Glib::ustring text(1, uch); | |
58 | + Pango::GlyphString glyphs = item.shape(text); | |
59 | + width = glyphs.get_width(); | |
60 | + cache.array_[ucs2] = width; | |
62 | 61 | } |
63 | - | |
64 | - width = double(w) / Pango::SCALE; | |
65 | - height = double(h) / Pango::SCALE; | |
62 | + return double(width) / Pango::SCALE; | |
66 | 63 | } |
67 | 64 | |
68 | -void CharSizeCache::get_char_size_from_cache(gunichar uch, | |
69 | - double& width, double& height, bool bold) const { | |
65 | +double CharSizeCache::get_char_width( | |
66 | + gunichar uch, const Pango::Item& item, int font_id) { | |
67 | + return get_char_width(uch, item, get_map(font_id)); | |
68 | +} | |
70 | 69 | |
71 | - const gunichar ucs2 = ucs4_to_ucs2(uch); | |
72 | - width = double(get_width_cache_array(bold)[ucs2]) / Pango::SCALE; | |
73 | - height = double(get_height_cache_array(bold)[ucs2]) / Pango::SCALE; | |
70 | +double CharSizeCache::get_char_width(gunichar uch, const Pango::Item& item) { | |
71 | + Pango::Analysis analysis = item.get_analysis(); | |
72 | + Glib::RefPtr<Pango::Font> font = analysis.get_font(); | |
73 | + const int font_id = reinterpret_cast<int>(font->gobj()); | |
74 | + return get_char_width(uch, item, get_map(font_id)); | |
74 | 75 | } |
75 | 76 | |
76 | 77 |
@@ -22,9 +22,10 @@ | ||
22 | 22 | #define TEXT_ELEMENT_CHAR_SIZE_CACHE_HXX |
23 | 23 | |
24 | 24 | #include <glibmm/refptr.h> |
25 | -#include <pangomm/layout.h> | |
25 | +#include <pangomm/item.h> | |
26 | 26 | #include <boost/array.hpp> |
27 | 27 | #include <boost/utility.hpp> |
28 | +#include <boost/unordered_map.hpp> | |
28 | 29 | |
29 | 30 | |
30 | 31 | namespace dialektos { |
@@ -33,32 +34,22 @@ namespace text_element { | ||
33 | 34 | |
34 | 35 | |
35 | 36 | class CharSizeCache : boost::noncopyable { |
36 | - typedef boost::array<int, 1<<16> ArrayType; | |
37 | + | |
38 | + struct ArrayClass { | |
39 | + typedef boost::array<int, 1<<16> ArrayType; | |
40 | + ArrayType array_; | |
41 | + ArrayClass(); | |
42 | + }; | |
43 | + | |
44 | + typedef boost::unordered_map<int, ArrayClass> MapType; | |
37 | 45 | public: |
38 | 46 | CharSizeCache(); |
39 | - void initialize(); | |
40 | - void get_char_size(gunichar uch, Glib::RefPtr<Pango::Layout>& layout, | |
41 | - double& width, double& height, bool bold); | |
42 | - void get_char_size_from_cache(gunichar uch, | |
43 | - double& width, double& height, bool bold) const; | |
47 | + double get_char_width(gunichar uch, const Pango::Item&, int font_id); | |
48 | + double get_char_width(gunichar uch, const Pango::Item&); | |
44 | 49 | private: |
45 | - ArrayType& get_width_cache_array(bool bold) { | |
46 | - return bold ? bold_char_width_cache : char_width_cache; | |
47 | - } | |
48 | - ArrayType& get_height_cache_array(bool bold) { | |
49 | - return bold ? bold_char_height_cache : char_height_cache; | |
50 | - } | |
51 | - const ArrayType& get_width_cache_array(bool bold) const { | |
52 | - return bold ? bold_char_width_cache : char_width_cache; | |
53 | - } | |
54 | - const ArrayType& get_height_cache_array(bool bold) const { | |
55 | - return bold ? bold_char_height_cache : char_height_cache; | |
56 | - } | |
57 | - | |
58 | - ArrayType char_width_cache; // pango units | |
59 | - ArrayType char_height_cache; // pango units | |
60 | - ArrayType bold_char_width_cache; // pango units | |
61 | - ArrayType bold_char_height_cache; // pango units | |
50 | + ArrayClass& get_map(int font_id); | |
51 | + double get_char_width(gunichar uch, const Pango::Item&, ArrayClass& cache); | |
52 | + MapType map_; | |
62 | 53 | }; |
63 | 54 | |
64 | 55 |
@@ -20,9 +20,13 @@ | ||
20 | 20 | |
21 | 21 | #include "text_element_id.hxx" |
22 | 22 | |
23 | -#include <pangomm/attributes.h> | |
24 | -#include <pangomm/attrlist.h> | |
23 | +#include <pangomm/font.h> | |
24 | +#include <glibmm/refptr.h> | |
25 | +#include <gdkmm/gc.h> | |
26 | +#include <gtkmm/enums.h> | |
27 | + | |
25 | 28 | #include "text_element_id_map.hxx" |
29 | +#include "text_view_drawing_set.hxx" | |
26 | 30 | |
27 | 31 | |
28 | 32 | namespace dialektos { |
@@ -30,22 +34,33 @@ namespace dialektos { | ||
30 | 34 | namespace text_element { |
31 | 35 | |
32 | 36 | |
33 | -void ID::set_attributes(Pango::AttrList& list) const { | |
34 | - using namespace Pango; | |
35 | - | |
36 | - Anchor::set_attributes(list); | |
37 | +void ID::do_draw_glyphs(text_view::DrawingSet& set, | |
38 | + const Pango::Item& item, const Pango::GlyphString& glyphs, | |
39 | + double x, double y, bool in_selection) const { | |
37 | 40 | |
38 | - const int count = id_map_->get_count(href_); | |
39 | - if (count > 4) { | |
40 | - AttrColor attr = Attribute::create_attr_foreground(0xffff, 0, 0); | |
41 | - list.insert(attr); | |
42 | - } | |
43 | - else if (count > 1) { | |
44 | - AttrColor attr = Attribute::create_attr_foreground(0, 0, 0xffff); | |
45 | - list.insert(attr); | |
41 | + Glib::RefPtr<const Gdk::GC> gc; | |
42 | + if (in_selection) gc = set.style->get_text_gc(Gtk::STATE_SELECTED); | |
43 | + else { | |
44 | + const int count = id_map_->get_count(href_); | |
45 | + if (count < 2) gc = set.style->get_text_gc(Gtk::STATE_NORMAL); | |
46 | + else { | |
47 | + Gdk::Color color; | |
48 | + if (count > 4) color.set_rgb(0xffff, 0, 0); | |
49 | + else if (count > 1) color.set_rgb(0, 0, 0xffff); | |
50 | + Glib::RefPtr<Gdk::GC> _gc = Gdk::GC::create(set.window); | |
51 | + _gc->set_rgb_fg_color(color); | |
52 | + gc = _gc; | |
53 | + } | |
46 | 54 | } |
55 | + | |
56 | + set.window->draw_glyphs(gc, item.get_analysis().get_font(), | |
57 | + std::ceil(x), | |
58 | + y - set.adj_value + get_metrics().get_ascent() / Pango::SCALE, glyphs); | |
59 | + | |
60 | + do_draw_underline(set, gc, double(glyphs.get_width()) / Pango::SCALE, x, y); | |
47 | 61 | } |
48 | 62 | |
63 | + | |
49 | 64 | } // namespace text_element |
50 | 65 | |
51 | 66 | } // namespace dialektos |
@@ -21,6 +21,8 @@ | ||
21 | 21 | #ifndef TEXT_ELEMENT_ID_HXX |
22 | 22 | #define TEXT_ELEMENT_ID_HXX |
23 | 23 | |
24 | +#include <pangomm/item.h> | |
25 | +#include <pangomm/glyphstring.h> | |
24 | 26 | #include <boost/shared_ptr.hpp> |
25 | 27 | #include "text_element_anchor.hxx" |
26 | 28 |
@@ -47,17 +49,13 @@ public: | ||
47 | 49 | Anchor(range, bold, id), id_map_(id_map) { |
48 | 50 | } |
49 | 51 | virtual ~ID() {} |
50 | - | |
51 | 52 | protected: |
52 | - /*! @brief set attributes for drawing the ID text element. | |
53 | - * | |
54 | - * @param list | |
55 | - */ | |
56 | - virtual void set_attributes(Pango::AttrList& list) const; | |
53 | + virtual void do_draw_glyphs(text_view::DrawingSet&, const Pango::Item&, | |
54 | + const Pango::GlyphString&, double x, double y, | |
55 | + bool in_selection) const; | |
57 | 56 | |
58 | 57 | private: |
59 | 58 | virtual ID* do_clone() const { return new ID(*this); } |
60 | - | |
61 | 59 | boost::shared_ptr<const IDMap> id_map_; |
62 | 60 | }; |
63 | 61 |
@@ -26,6 +26,8 @@ | ||
26 | 26 | #include <pangomm/context.h> |
27 | 27 | #include <pangomm/font.h> |
28 | 28 | #include <pangomm/rectangle.h> |
29 | +#include <pangomm/item.h> | |
30 | +#include <pangomm/glyphstring.h> | |
29 | 31 | #include <glibmm/refptr.h> |
30 | 32 | #include <glibmm/ustring.h> |
31 | 33 | #include <gdkmm/gc.h> |
@@ -46,20 +48,13 @@ namespace text_element { | ||
46 | 48 | |
47 | 49 | /* static data members */ |
48 | 50 | CharSizeCache Plain::char_size_cache; |
49 | -gdouble Plain::approximate_char_height = -1; | |
50 | 51 | |
51 | 52 | |
52 | -double Plain::get_approximate_char_height( | |
53 | - Glib::RefPtr<const Pango::Layout> layout) { | |
54 | - | |
55 | - if (approximate_char_height < 0) { | |
56 | - Glib::RefPtr<Pango::Context> context = layout->get_context(); | |
57 | - Pango::FontDescription desc = context->get_font_description(); | |
58 | - Glib::RefPtr<Pango::Font> font = context->load_font(desc); | |
59 | - Pango::Rectangle rect = font->get_glyph_logical_extents(0); | |
60 | - approximate_char_height = double(rect.get_height())/Pango::SCALE*1.2; | |
61 | - } | |
62 | - return approximate_char_height; | |
53 | +double Plain::get_approximate_char_height(const Pango::FontMetrics& metrics) { | |
54 | + return double( | |
55 | + metrics.get_ascent() + | |
56 | + metrics.get_descent()) | |
57 | + / Pango::SCALE * 1.2; | |
63 | 58 | } |
64 | 59 | |
65 | 60 | void Plain::trim_right() { |
@@ -85,101 +80,133 @@ void Plain::layout(text_view::LayoutSet& set) { | ||
85 | 80 | x_start_ = set.x_start; |
86 | 81 | x_end_ = set.x_end; |
87 | 82 | |
88 | - Pango::AttrList list = Pango::AttrList(); | |
89 | - Pango::AttrInt attr = bold_ ? | |
90 | - Pango::Attribute::create_attr_weight(Pango::WEIGHT_BOLD): | |
91 | - Pango::Attribute::create_attr_weight(Pango::WEIGHT_NORMAL); | |
92 | - list.insert(attr); | |
93 | - set.layout->set_attributes(list); | |
94 | - | |
95 | - BOOST_FOREACH(const gunichar& uch, str_) { | |
96 | - double w, h; | |
97 | - char_size_cache.get_char_size(uch, set.layout, w, h, bold_); | |
98 | - | |
99 | - if (set.x + w > x_end_) { | |
100 | - // begin new line | |
101 | - set.x = x_start_; | |
102 | - set.y += get_approximate_char_height(set.layout); | |
83 | + BOOST_FOREACH(const Pango::Item& item, items_) { | |
84 | + Glib::RefPtr<Pango::Font> font = item.get_analysis().get_font(); | |
85 | + const int font_id = reinterpret_cast<int>(font->gobj()); | |
86 | + BOOST_FOREACH(const gunichar& uch, item.get_segment(str_)) { | |
87 | + const double width = char_size_cache.get_char_width(uch, item, font_id); | |
88 | + if (set.x + width > x_end_) { | |
89 | + set.x = x_start_; | |
90 | + set.y += get_approximate_char_height(metrics_); | |
91 | + } | |
92 | + set.x += width; | |
103 | 93 | } |
104 | - | |
105 | - set.x += w; | |
106 | 94 | } |
107 | 95 | } |
108 | 96 | |
109 | 97 | void Plain::draw(text_view::DrawingSet& set) const { |
110 | - | |
111 | - Glib::RefPtr<const Gdk::GC> gc = set.style->get_text_gc(Gtk::STATE_NORMAL); | |
112 | - | |
113 | - Pango::AttrList list = Pango::AttrList(); | |
114 | - Pango::AttrInt attr = bold_ ? | |
115 | - Pango::Attribute::create_attr_weight(Pango::WEIGHT_BOLD): | |
116 | - Pango::Attribute::create_attr_weight(Pango::WEIGHT_NORMAL); | |
117 | - list.insert(attr); | |
118 | - | |
119 | - set_attributes(list); | |
120 | - set.layout->set_attributes(list); | |
121 | - | |
122 | 98 | size_t start_index = 0; |
123 | 99 | size_t end_index = 0; |
124 | 100 | get_selection_start_end_index(set.start_element, set.start_index, |
125 | 101 | set.end_element, set.end_index, start_index, end_index); |
126 | 102 | |
127 | - gdouble x = x_; | |
128 | - gdouble y = y_; | |
129 | - size_t index_count = 0; | |
130 | - BOOST_FOREACH(const gunichar& uch, str_) { | |
131 | - double w, h; | |
132 | - char_size_cache.get_char_size_from_cache(uch, w, h, bold_); | |
133 | - | |
134 | - if (x + w > x_end_) { | |
135 | - // begin new line | |
136 | - x = x_start_; | |
137 | - y += approximate_char_height;//(set.layout); | |
103 | + double x = x_; | |
104 | + double y = y_; | |
105 | + | |
106 | + size_t str_count = 0; | |
107 | + size_t str_start = 0; | |
108 | + | |
109 | + BOOST_FOREACH(Pango::Item item, items_) { | |
110 | + const Glib::ustring sub = item.get_segment(str_); | |
111 | + double draw_start_x = x; | |
112 | + double draw_start_y = y; | |
113 | + Glib::ustring text; | |
114 | + bool need_draw = false; | |
115 | + | |
116 | + BOOST_FOREACH(const gunichar& uch, sub) { | |
117 | + const double width = char_size_cache.get_char_width(uch, item); | |
118 | + if (x + width > x_end_) { | |
119 | + need_draw = true; | |
120 | + x = x_start_; | |
121 | + y += get_approximate_char_height(metrics_); | |
122 | + } | |
123 | + | |
124 | + if (str_count == start_index && str_count != end_index) | |
125 | + need_draw = true; | |
126 | + if (str_count == end_index && str_count != start_index) | |
127 | + need_draw = true; | |
128 | + | |
129 | + if (need_draw) { | |
130 | + | |
131 | + if (!text.empty()) | |
132 | + do_draw(set, item, item.shape(text), draw_start_x, draw_start_y, | |
133 | + str_start >= start_index && str_count <= end_index); | |
134 | + | |
135 | + str_start = str_count; | |
136 | + draw_start_x = x; | |
137 | + draw_start_y = y; | |
138 | + text.clear(); | |
139 | + need_draw = false; | |
140 | + } | |
141 | + | |
142 | + x += width; | |
143 | + ++str_count; | |
144 | + text += uch; | |
138 | 145 | } |
139 | 146 | |
140 | - double deltaY = approximate_char_height - h; | |
141 | - set.layout->set_text(Glib::ustring(1, uch)); | |
142 | - | |
143 | - if (start_index != end_index && | |
144 | - index_count >= start_index && index_count < end_index) | |
145 | - set.window->draw_layout(gc, x, y + deltaY - set.adj_value, | |
146 | - set.layout, | |
147 | - set.style->get_fg(Gtk::STATE_SELECTED), | |
148 | - set.style->get_bg(Gtk::STATE_SELECTED)); | |
149 | - else | |
150 | - set.window->draw_layout(gc, x, y + deltaY - set.adj_value, | |
151 | - set.layout); | |
152 | - | |
153 | - x += w; | |
154 | - ++index_count; | |
147 | + if (!text.empty()) | |
148 | + do_draw(set, item, item.shape(text), draw_start_x, draw_start_y, | |
149 | + str_start >= start_index && str_count <= end_index); | |
150 | + | |
151 | + } | |
152 | +} | |
153 | + | |
154 | + | |
155 | +void Plain::do_draw(text_view::DrawingSet& set, | |
156 | + const Pango::Item& item, const Pango::GlyphString& glyphs, | |
157 | + double x, double y, bool in_selection) const { | |
158 | + | |
159 | + // draw a rectangle for a selected region background. | |
160 | + if (in_selection) { | |
161 | + set.window->draw_rectangle( | |
162 | + set.style->get_base_gc(Gtk::STATE_SELECTED), | |
163 | + true, std::ceil(x), y - set.adj_value, | |
164 | + std::ceil(double(glyphs.get_width()) / Pango::SCALE), | |
165 | + (metrics_.get_ascent() + metrics_.get_descent()) / Pango::SCALE); | |
155 | 166 | } |
167 | + | |
168 | + do_draw_glyphs(set, item, glyphs, x, y, in_selection); | |
156 | 169 | } |
157 | 170 | |
171 | +void Plain::do_draw_glyphs(text_view::DrawingSet& set, | |
172 | + const Pango::Item& item, const Pango::GlyphString& glyphs, | |
173 | + double x, double y, bool in_selection) const { | |
174 | + | |
175 | + Glib::RefPtr<const Gdk::GC> gc = set.style->get_text_gc( | |
176 | + in_selection ? Gtk::STATE_SELECTED : Gtk::STATE_NORMAL); | |
158 | 177 | |
159 | -void Plain::set_attributes(Pango::AttrList& list) const { | |
178 | + set.window->draw_glyphs(gc, item.get_analysis().get_font(), | |
179 | + std::ceil(x), | |
180 | + y - set.adj_value + metrics_.get_ascent() / Pango::SCALE, glyphs); | |
160 | 181 | } |
161 | 182 | |
183 | +Pango::FontMetrics Plain::get_metrics() const { | |
184 | + return metrics_; | |
185 | +} | |
186 | + | |
187 | + | |
162 | 188 | bool Plain::is_xy_on_this(const gdouble x, const gdouble y) const { |
163 | 189 | |
164 | 190 | gdouble x_pos = x_; |
165 | 191 | gdouble y_pos = y_; |
166 | 192 | |
167 | - BOOST_FOREACH(const gunichar& uch, str_) { | |
168 | - double w, h; | |
169 | - char_size_cache.get_char_size_from_cache(uch, w, h, bold_); | |
193 | + BOOST_FOREACH(Pango::Item item, items_) { | |
194 | + BOOST_FOREACH(const gunichar& uch, item.get_segment(str_)) { | |
195 | + const double w = char_size_cache.get_char_width(uch, item); | |
170 | 196 | |
171 | - if (x_pos + w > x_end_) { | |
172 | - // begin new line | |
173 | - x_pos = x_start_; | |
174 | - y_pos += approximate_char_height; | |
175 | - } | |
197 | + if (x_pos + w > x_end_) { | |
198 | + // begin new line | |
199 | + x_pos = x_start_; | |
200 | + y_pos += get_approximate_char_height(metrics_); | |
201 | + } | |
176 | 202 | |
177 | - if (x >= x_pos && x < x_pos + w && | |
178 | - y >= y_pos && y < y_pos + approximate_char_height) { | |
179 | - return true; | |
180 | - } | |
203 | + if (x >= x_pos && x < x_pos + w && | |
204 | + y >= y_pos && y < y_pos + get_approximate_char_height(metrics_)) { | |
205 | + return true; | |
206 | + } | |
181 | 207 | |
182 | - x_pos += w; | |
208 | + x_pos += w; | |
209 | + } | |
183 | 210 | } |
184 | 211 | |
185 | 212 | return false; |
@@ -189,28 +216,30 @@ bool Plain::is_xy_near_to_this(const gdouble x, const gdouble y) const { | ||
189 | 216 | gdouble x_pos = x_; |
190 | 217 | gdouble y_pos = y_; |
191 | 218 | |
192 | - BOOST_FOREACH(const gunichar& uch, str_) { | |
193 | - double w, h; | |
194 | - char_size_cache.get_char_size_from_cache(uch, w, h, bold_); | |
219 | + BOOST_FOREACH(Pango::Item item, items_) { | |
220 | + BOOST_FOREACH(const gunichar& uch, item.get_segment(str_)) { | |
221 | + const double w = char_size_cache.get_char_width(uch, item); | |
195 | 222 | |
196 | - if (x_pos + w > x_end_) { | |
197 | - // begin new line | |
223 | + if (x_pos + w > x_end_) { | |
224 | + // begin new line | |
198 | 225 | |
199 | - if (x >= x_pos && y >= y_pos && y < y_pos + approximate_char_height) { | |
200 | - // (x, y) is on the spaces caused by wrapping | |
201 | - return true; | |
226 | + if (x >= x_pos && y >= y_pos && | |
227 | + y < y_pos + get_approximate_char_height(metrics_)) { | |
228 | + // (x, y) is on the spaces caused by wrapping | |
229 | + return true; | |
230 | + } | |
231 | + | |
232 | + x_pos = x_start_; | |
233 | + y_pos += get_approximate_char_height(metrics_); | |
202 | 234 | } |
203 | 235 | |
204 | - x_pos = x_start_; | |
205 | - y_pos += approximate_char_height; | |
206 | - } | |
236 | + if (x >= x_pos && x < x_pos + w && | |
237 | + y >= y_pos && y < y_pos + get_approximate_char_height(metrics_)) { | |
238 | + return true; | |
239 | + } | |
207 | 240 | |
208 | - if (x >= x_pos && x < x_pos + w && | |
209 | - y >= y_pos && y < y_pos + approximate_char_height) { | |
210 | - return true; | |
241 | + x_pos += w; | |
211 | 242 | } |
212 | - | |
213 | - x_pos += w; | |
214 | 243 | } |
215 | 244 | |
216 | 245 | return false; |
@@ -220,24 +249,27 @@ bool Plain::is_xy_near_to_this(const gdouble x, const gdouble y) const { | ||
220 | 249 | Gdk::Rectangle Plain::xy_to_rectangle(gdouble x, gdouble y) const { |
221 | 250 | gdouble x_pos = x_; |
222 | 251 | gdouble y_pos = y_; |
223 | - BOOST_FOREACH(const gunichar& uch, str_) { | |
224 | - double w, h; | |
225 | - char_size_cache.get_char_size_from_cache(uch, w, h, bold_); | |
226 | - | |
227 | - if (x_pos + w > x_end_) { | |
228 | - // begin new line | |
229 | - x_pos = x_start_; | |
230 | - y_pos += approximate_char_height; | |
231 | - } | |
252 | + BOOST_FOREACH(Pango::Item item, items_) { | |
253 | + BOOST_FOREACH(const gunichar& uch, item.get_segment(str_)) { | |
254 | + const double w = char_size_cache.get_char_width(uch, item); | |
232 | 255 | |
233 | - if (x >= x_pos && x < x_pos + w && | |
234 | - y >= y_pos && y < y_pos + approximate_char_height) | |
235 | - return Gdk::Rectangle(x_pos, y_pos, w, approximate_char_height); | |
256 | + if (x_pos + w > x_end_) { | |
257 | + // begin new line | |
258 | + x_pos = x_start_; | |
259 | + y_pos += get_approximate_char_height(metrics_); | |
260 | + } | |
236 | 261 | |
237 | - x_pos += w; | |
262 | + if (x >= x_pos && x < x_pos + w && | |
263 | + y >= y_pos && y < y_pos + get_approximate_char_height(metrics_)) | |
264 | + return Gdk::Rectangle( | |
265 | + x_pos, y_pos, w, get_approximate_char_height(metrics_)); | |
266 | + | |
267 | + x_pos += w; | |
268 | + } | |
238 | 269 | } |
239 | 270 | |
240 | - return Gdk::Rectangle(x_pos, y_pos, 0, approximate_char_height); | |
271 | + return Gdk::Rectangle( | |
272 | + x_pos, y_pos, 0, get_approximate_char_height(metrics_)); | |
241 | 273 | } |
242 | 274 | |
243 | 275 |
@@ -247,35 +279,36 @@ int Plain::xy_to_index(const gdouble x, const gdouble y) const { | ||
247 | 279 | gdouble y_pos = y_; |
248 | 280 | int index = 0; |
249 | 281 | |
250 | - BOOST_FOREACH(const gunichar& uch, str_) { | |
251 | - double w, h; | |
252 | - char_size_cache.get_char_size_from_cache(uch, w, h, bold_); | |
282 | + BOOST_FOREACH(Pango::Item item, items_) { | |
283 | + BOOST_FOREACH(const gunichar& uch, item.get_segment(str_)) { | |
284 | + const double w = char_size_cache.get_char_width(uch, item); | |
253 | 285 | |
254 | - if (x_pos + w > x_end_) { | |
255 | - // begin new line | |
256 | - if (x >= x_pos && | |
257 | - y >= y_pos && y < y_pos + approximate_char_height) { | |
258 | - // (x, y) is on the spaces caused by wrapping | |
259 | - return index; | |
260 | - } | |
286 | + if (x_pos + w > x_end_) { | |
287 | + // begin new line | |
288 | + if (x >= x_pos && | |
289 | + y >= y_pos && y < y_pos + get_approximate_char_height(metrics_)) { | |
290 | + // (x, y) is on the spaces caused by wrapping | |
291 | + return index; | |
292 | + } | |
261 | 293 | |
262 | 294 | x_pos = x_start_; |
263 | - y_pos += approximate_char_height; | |
264 | - } | |
295 | + y_pos += get_approximate_char_height(metrics_); | |
296 | + } | |
265 | 297 | |
266 | - if (x >= x_pos && x < x_pos + w && | |
267 | - y >= y_pos && y < y_pos + approximate_char_height) { | |
268 | - if (x <= x_pos + w/2) { | |
269 | - // left of this character | |
270 | - return index; | |
271 | - } else { | |
272 | - // right of this character | |
273 | - return index+1; | |
298 | + if (x >= x_pos && x < x_pos + w && | |
299 | + y >= y_pos && y < y_pos + get_approximate_char_height(metrics_)) { | |
300 | + if (x <= x_pos + w/2) { | |
301 | + // left of this character | |
302 | + return index; | |
303 | + } else { | |
304 | + // right of this character | |
305 | + return index+1; | |
306 | + } | |
274 | 307 | } |
275 | - } | |
276 | 308 | |
277 | - x_pos += w; | |
278 | - ++index; | |
309 | + x_pos += w; | |
310 | + ++index; | |
311 | + } | |
279 | 312 | } |
280 | 313 | return index; |
281 | 314 | } |
@@ -284,6 +317,17 @@ Gdk::CursorType Plain::get_cursor_type() const { | ||
284 | 317 | return Gdk::XTERM; |
285 | 318 | } |
286 | 319 | |
320 | +void Plain::itemize(const Glib::RefPtr<Pango::Context>& context, | |
321 | + const Pango::FontMetrics& metrics) { | |
322 | + Pango::AttrList list = Pango::AttrList(); | |
323 | + Pango::AttrInt attr = bold_ ? | |
324 | + Pango::Attribute::create_attr_weight(Pango::WEIGHT_BOLD): | |
325 | + Pango::Attribute::create_attr_weight(Pango::WEIGHT_NORMAL); | |
326 | + list.insert(attr); | |
327 | + if (!str_.empty()) items_ = context->itemize(str_, list); | |
328 | + metrics_ = metrics; | |
329 | +} | |
330 | + | |
287 | 331 | void Plain::get_selection_start_end_index( |
288 | 332 | const Plain* const start_element, const size_t start_index, |
289 | 333 | const Plain* const end_element, const size_t end_index, |
@@ -25,8 +25,9 @@ | ||
25 | 25 | #include <glibmm/ustring.h> |
26 | 26 | #include <gdkmm/cursor.h> |
27 | 27 | #include <gdkmm/rectangle.h> |
28 | -#include <pangomm/layout.h> | |
29 | -#include <pangomm/attrlist.h> | |
28 | +#include <pangomm/context.h> | |
29 | +#include <pangomm/item.h> | |
30 | +#include <pangomm/fontmetrics.h> | |
30 | 31 | #include <boost/range.hpp> |
31 | 32 | #include "text_element_char_size_cache.hxx" |
32 | 33 |
@@ -77,7 +78,7 @@ public: | ||
77 | 78 | template <typename RangeT> |
78 | 79 | Plain(const RangeT& range, bool bold) : |
79 | 80 | str_(boost::begin(range), boost::end(range)), |
80 | - bold_(bold), x_(0), y_(0), x_start_(0), x_end_(0) {} | |
81 | + bold_(bold), x_(0), y_(0), x_start_(0), x_end_(0), items_(), metrics_() {} | |
81 | 82 | |
82 | 83 | virtual ~Plain() {} |
83 | 84 |
@@ -156,23 +157,30 @@ public: | ||
156 | 157 | */ |
157 | 158 | virtual Gdk::CursorType get_cursor_type() const; |
158 | 159 | |
160 | + void itemize(const Glib::RefPtr<Pango::Context>&, const Pango::FontMetrics&); | |
161 | + | |
159 | 162 | /*! @brief return an approximate character height. |
160 | 163 | * |
161 | 164 | * @param layout for calculating the character height. |
162 | 165 | * @return the approximate height. |
163 | 166 | */ |
164 | - static double get_approximate_char_height(Glib::RefPtr<const Pango::Layout> layout); | |
167 | + static double get_approximate_char_height(const Pango::FontMetrics&); | |
165 | 168 | |
166 | 169 | protected: |
167 | 170 | |
168 | - /*! @brief set attributes for drawing the plain text element. | |
169 | - * | |
170 | - * @param list | |
171 | - */ | |
172 | - virtual void set_attributes(Pango::AttrList& list) const; | |
171 | + virtual void do_draw_glyphs(text_view::DrawingSet&, const Pango::Item&, | |
172 | + const Pango::GlyphString&, double x, double y, | |
173 | + bool in_selection) const; | |
174 | + | |
175 | + Pango::FontMetrics get_metrics() const; | |
173 | 176 | |
174 | 177 | private: |
175 | 178 | virtual Plain* do_clone() const { return new Plain(*this); } |
179 | + | |
180 | + void do_draw(text_view::DrawingSet&, const Pango::Item&, | |
181 | + const Pango::GlyphString&, double x, double y, | |
182 | + bool in_selection) const; | |
183 | + | |
176 | 184 | void get_selection_start_end_index(const Plain*, size_t, const Plain*, size_t, |
177 | 185 | size_t&, size_t&) const; |
178 | 186 |
@@ -185,8 +193,11 @@ private: | ||
185 | 193 | gdouble x_start_; |
186 | 194 | gdouble x_end_; |
187 | 195 | |
196 | + std::vector<Pango::Item> items_; | |
197 | + | |
198 | + Pango::FontMetrics metrics_; | |
199 | + | |
188 | 200 | static CharSizeCache char_size_cache; |
189 | - static gdouble approximate_char_height; | |
190 | 201 | }; |
191 | 202 | |
192 | 203 | /*! @brief clone the text element type. This function is for Boost.PtrContainer. |
@@ -20,9 +20,12 @@ | ||
20 | 20 | |
21 | 21 | #include "text_element_res_num.hxx" |
22 | 22 | |
23 | -#include <pangomm/attrlist.h> | |
24 | -#include <pangomm/attributes.h> | |
23 | +#include <glibmm/refptr.h> | |
24 | +#include <pangomm/font.h> | |
25 | +#include <gdkmm/gc.h> | |
26 | +#include <gtkmm/enums.h> | |
25 | 27 | #include "text_element_res_num_map.hxx" |
28 | +#include "text_view_drawing_set.hxx" | |
26 | 29 | |
27 | 30 | |
28 | 31 | namespace dialektos { |
@@ -30,20 +33,30 @@ namespace dialektos { | ||
30 | 33 | namespace text_element { |
31 | 34 | |
32 | 35 | |
33 | -void ResNum::set_attributes(Pango::AttrList& list) const { | |
34 | - using namespace Pango; | |
36 | +void ResNum::do_draw_glyphs(text_view::DrawingSet& set, | |
37 | + const Pango::Item& item, const Pango::GlyphString& glyphs, | |
38 | + double x, double y, bool in_selection) const { | |
35 | 39 | |
36 | - Anchor::set_attributes(list); | |
37 | - | |
38 | - const int count = res_num_map_->get_count(res_num_); | |
39 | - if (count > 4) { | |
40 | - AttrColor attr = Attribute::create_attr_foreground(0xffff, 0, 0); | |
41 | - list.insert(attr); | |
42 | - } | |
43 | - else if (count > 0) { | |
44 | - AttrColor attr = Attribute::create_attr_foreground(0, 0, 0xffff); | |
45 | - list.insert(attr); | |
40 | + Glib::RefPtr<const Gdk::GC> gc; | |
41 | + if (in_selection) gc = set.style->get_text_gc(Gtk::STATE_SELECTED); | |
42 | + else { | |
43 | + const int count = res_num_map_->get_count(res_num_); | |
44 | + if (count < 1) gc = set.style->get_text_gc(Gtk::STATE_NORMAL); | |
45 | + else { | |
46 | + Gdk::Color color; | |
47 | + if (count > 4) color.set_rgb(0xffff, 0, 0); | |
48 | + else if (count > 0) color.set_rgb(0, 0, 0xffff); | |
49 | + Glib::RefPtr<Gdk::GC> _gc = Gdk::GC::create(set.window); | |
50 | + _gc->set_rgb_fg_color(color); | |
51 | + gc = _gc; | |
52 | + } | |
46 | 53 | } |
54 | + | |
55 | + set.window->draw_glyphs(gc, item.get_analysis().get_font(), | |
56 | + std::ceil(x), | |
57 | + y - set.adj_value + get_metrics().get_ascent() / Pango::SCALE, glyphs); | |
58 | + | |
59 | + do_draw_underline(set, gc, double(glyphs.get_width()) / Pango::SCALE, x, y); | |
47 | 60 | } |
48 | 61 | |
49 | 62 |
@@ -22,7 +22,8 @@ | ||
22 | 22 | #define TEXT_ELEMENT_RES_NUM_HXX |
23 | 23 | |
24 | 24 | #include <glibmm/ustring.h> |
25 | -#include <pangomm/attrlist.h> | |
25 | +#include <pangomm/item.h> | |
26 | +#include <pangomm/glyphstring.h> | |
26 | 27 | #include <boost/lexical_cast.hpp> |
27 | 28 | #include <boost/shared_ptr.hpp> |
28 | 29 | #include "text_element_anchor.hxx" |
@@ -57,11 +58,9 @@ public: | ||
57 | 58 | size_t get_res_num() const { return res_num_; } |
58 | 59 | protected: |
59 | 60 | |
60 | - /*! @brief set attributes for drawing the ResNum text element. | |
61 | - * | |
62 | - * @param list | |
63 | - */ | |
64 | - virtual void set_attributes(Pango::AttrList& list) const; | |
61 | + virtual void do_draw_glyphs(text_view::DrawingSet&, const Pango::Item&, | |
62 | + const Pango::GlyphString&, double x, double y, | |
63 | + bool in_selection) const; | |
65 | 64 | |
66 | 65 | private: |
67 | 66 | virtual ResNum* do_clone() const { return new ResNum(*this); } |
@@ -32,13 +32,14 @@ namespace dialektos { | ||
32 | 32 | |
33 | 33 | TextLine::TextLine(int res_num, int l_mgn) : |
34 | 34 | res_num_(res_num), element_list_(), height_(12), y_(0), width_(0), |
35 | - left_margin_(l_mgn), right_margin_(1) { | |
35 | + left_margin_(l_mgn), right_margin_(1), metrics_() { | |
36 | 36 | } |
37 | 37 | |
38 | 38 | TextLine::TextLine(const TextLine& rhs) : |
39 | 39 | res_num_(rhs.res_num_), element_list_(rhs.element_list_), |
40 | 40 | height_(rhs.height_), y_(rhs.y_), width_(rhs.width_), |
41 | - left_margin_(rhs.left_margin_), right_margin_(rhs.right_margin_) { | |
41 | + left_margin_(rhs.left_margin_), right_margin_(rhs.right_margin_), | |
42 | + metrics_(rhs.metrics_) { | |
42 | 43 | } |
43 | 44 | |
44 | 45 | TextLine::~TextLine(){} |
@@ -53,6 +54,14 @@ void TextLine::trim_right() { | ||
53 | 54 | element_list_.back().trim_right(); |
54 | 55 | } |
55 | 56 | |
57 | +void TextLine::itemize(const Glib::RefPtr<Pango::Context>& context, | |
58 | + const Pango::FontMetrics& metrics) { | |
59 | + BOOST_FOREACH(text_element::Plain& element, element_list_) | |
60 | + element.itemize(context, metrics); | |
61 | + metrics_ = metrics; | |
62 | +} | |
63 | + | |
64 | + | |
56 | 65 | bool TextLine::empty() const { |
57 | 66 | return element_list_.empty(); |
58 | 67 | } |
@@ -83,7 +92,7 @@ void TextLine::layout(text_view::LayoutSet& set) { | ||
83 | 92 | BOOST_FOREACH(text_element::Plain& elem, element_list_) { |
84 | 93 | elem.layout(set); |
85 | 94 | } |
86 | - set.y += text_element::Plain::get_approximate_char_height(set.layout); | |
95 | + set.y += text_element::Plain::get_approximate_char_height(metrics_); | |
87 | 96 | |
88 | 97 | height_ = set.y - y_; |
89 | 98 | } |
@@ -23,6 +23,9 @@ | ||
23 | 23 | |
24 | 24 | #include <boost/ptr_container/ptr_vector.hpp> |
25 | 25 | #include <glibmm/ustring.h> |
26 | +#include <glibmm/refptr.h> | |
27 | +#include <pangomm/context.h> | |
28 | +#include <pangomm/fontmetrics.h> | |
26 | 29 | |
27 | 30 | |
28 | 31 | namespace dialektos { |
@@ -46,6 +49,7 @@ public: | ||
46 | 49 | ~TextLine(); |
47 | 50 | void add_element(text_element::Plain* element); |
48 | 51 | void trim_right(); |
52 | + void itemize(const Glib::RefPtr<Pango::Context>&, const Pango::FontMetrics&); | |
49 | 53 | bool empty() const; |
50 | 54 | bool includes(const text_element::Plain&) const; |
51 | 55 | Glib::ustring get_selected_text(const text_view::GetSelectedSet& set) const; |
@@ -67,6 +71,8 @@ private: | ||
67 | 71 | int width_; |
68 | 72 | int left_margin_; |
69 | 73 | int right_margin_; |
74 | + | |
75 | + Pango::FontMetrics metrics_; | |
70 | 76 | }; |
71 | 77 | |
72 | 78 |
@@ -49,7 +49,6 @@ bool Drawable::on_expose_event(GdkEventExpose* event) { | ||
49 | 49 | |
50 | 50 | DrawingSet set; |
51 | 51 | set.window = window; |
52 | - set.layout = pango_layout_; | |
53 | 52 | set.style = style; |
54 | 53 | set.adj_value = value; |
55 | 54 | set.start_element = pressed_element_; |
@@ -24,7 +24,6 @@ | ||
24 | 24 | #include <glibmm/refptr.h> |
25 | 25 | #include <gdkmm/drawable.h> |
26 | 26 | #include <gtkmm/style.h> |
27 | -#include <pangomm/layout.h> | |
28 | 27 | |
29 | 28 | |
30 | 29 | namespace dialektos { |
@@ -36,8 +35,6 @@ namespace text_view { | ||
36 | 35 | |
37 | 36 | |
38 | 37 | struct LayoutSet { |
39 | - Glib::RefPtr<Pango::Layout> layout; | |
40 | - | |
41 | 38 | gdouble x; |
42 | 39 | gdouble y; // y position on the adjustment |
43 | 40 |
@@ -47,7 +44,6 @@ struct LayoutSet { | ||
47 | 44 | |
48 | 45 | struct DrawingSet { |
49 | 46 | Glib::RefPtr<Gdk::Drawable> window; |
50 | - Glib::RefPtr<Pango::Layout> layout; | |
51 | 47 | Glib::RefPtr<const Gtk::Style> style; |
52 | 48 | |
53 | 49 | gdouble adj_value; // adjustment value |
@@ -38,6 +38,8 @@ Layoutable::Layoutable(): | ||
38 | 38 | id_map_(new text_element::IDMap), |
39 | 39 | res_num_map_(new text_element::ResNumMap), |
40 | 40 | res_num_(0), |
41 | + metrics_(get_pango_context()->get_metrics( | |
42 | + get_pango_context()->get_font_description())), | |
41 | 43 | width_(-1) { |
42 | 44 | } |
43 | 45 |
@@ -45,13 +47,13 @@ Layoutable::~Layoutable() { | ||
45 | 47 | } |
46 | 48 | |
47 | 49 | void Layoutable::add_line(TextLine* line) { |
50 | + line->itemize(get_pango_context(), metrics_); | |
48 | 51 | line_list_.push_back(line); |
49 | 52 | } |
50 | 53 | |
51 | 54 | void Layoutable::relayout() { |
52 | 55 | const int width = get_width(); |
53 | 56 | LayoutSet set; |
54 | - set.layout = pango_layout_; | |
55 | 57 | set.y = 0; |
56 | 58 | |
57 | 59 | BOOST_FOREACH(TextLine& line, line_list_) { |
@@ -66,7 +68,7 @@ void Layoutable::relayout() { | ||
66 | 68 | adjustment_.set_upper(set.y); |
67 | 69 | } |
68 | 70 | |
69 | -bool Layoutable::on_configure_event(GdkEventConfigure* event) { | |
71 | +void Layoutable::safe_layout() { | |
70 | 72 | if (width_ == -1) |
71 | 73 | relayout(); |
72 | 74 | else if (width_ != get_width()) { |
@@ -93,9 +95,27 @@ bool Layoutable::on_configure_event(GdkEventConfigure* event) { | ||
93 | 95 | } |
94 | 96 | adjustment_.set_value(y - delta); |
95 | 97 | } |
98 | +} | |
99 | + | |
100 | +bool Layoutable::on_configure_event(GdkEventConfigure* event) { | |
101 | + safe_layout(); | |
96 | 102 | return Scrollable::on_configure_event(event); |
97 | 103 | } |
98 | 104 | |
105 | +void Layoutable::on_realize() { | |
106 | + Scrollable::on_realize(); | |
107 | + metrics_ = get_pango_context()->get_metrics( | |
108 | + get_pango_context()->get_font_description()); | |
109 | +} | |
110 | + | |
111 | +void Layoutable::on_style_changed(const Glib::RefPtr<Gtk::Style>& previous) { | |
112 | + Scrollable::on_style_changed(previous); | |
113 | + const Pango::FontMetrics metrics = get_pango_context()->get_metrics( | |
114 | + get_pango_context()->get_font_description()); | |
115 | + BOOST_FOREACH(TextLine& line, line_list_) | |
116 | + line.itemize(get_pango_context(), metrics); | |
117 | + safe_layout(); | |
118 | +} | |
99 | 119 | |
100 | 120 | const TextLine* Layoutable::get_text_line(const gdouble y_adj) const { |
101 | 121 |
@@ -52,6 +52,7 @@ public: | ||
52 | 52 | Layoutable(); |
53 | 53 | virtual ~Layoutable(); |
54 | 54 | void relayout(); |
55 | + void safe_layout(); | |
55 | 56 | void add_line(TextLine*); |
56 | 57 | void set_id_map(IDMapPtrType map) { id_map_ = map; } |
57 | 58 | void set_res_num_map(ResNumMapPtrType map) { res_num_map_ = map; } |
@@ -62,6 +63,8 @@ public: | ||
62 | 63 | protected: |
63 | 64 | //virtual bool on_expose_event(GdkEventExpose*); |
64 | 65 | virtual bool on_configure_event(GdkEventConfigure*); |
66 | + virtual void on_realize(); | |
67 | + virtual void on_style_changed(const Glib::RefPtr<Gtk::Style>& previous); | |
65 | 68 | |
66 | 69 | const TextLine* get_text_line(gdouble y) const; |
67 | 70 | const TextLine* get_nearest_text_line(gdouble& y) const; |
@@ -73,6 +76,7 @@ protected: | ||
73 | 76 | boost::shared_ptr<text_element::IDMap> id_map_; |
74 | 77 | boost::shared_ptr<text_element::ResNumMap> res_num_map_; |
75 | 78 | int res_num_; |
79 | + Pango::FontMetrics metrics_; | |
76 | 80 | /* cached */ |
77 | 81 | gint width_; |
78 | 82 | }; |
@@ -52,6 +52,11 @@ class Popup: public Gtk::Window { | ||
52 | 52 | original_line_list_(original) { |
53 | 53 | } |
54 | 54 | |
55 | + void show() { | |
56 | + TextView::show(); | |
57 | + realize(); | |
58 | + } | |
59 | + | |
55 | 60 | private: |
56 | 61 | virtual const LineListType& get_original_line_list() const { |
57 | 62 | return original_line_list_; |