• R/O
  • HTTP
  • SSH
  • HTTPS

dialektos: Commit

dialektos


Commit MetaInfo

Revision636961c92ee598e3469ecd50898f6d515550f3f5 (tree)
Time2009-07-12 18:47:37
AuthorAiwota Programmer <aiwotaprog@tett...>
CommiterAiwota Programmer

Log Message

TextView strict layout.

Change Summary

Incremental Difference

--- a/src/text_element_anchor.cxx
+++ b/src/text_element_anchor.cxx
@@ -20,9 +20,12 @@
2020
2121 #include "text_element_anchor.hxx"
2222
23+#include <glibmm/refptr.h>
2324 #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"
2629
2730
2831 namespace dialektos {
@@ -33,10 +36,29 @@ Gdk::CursorType Anchor::get_cursor_type() const {
3336 return Gdk::HAND2;
3437 }
3538
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);
4062 }
4163
4264
--- a/src/text_element_anchor.hxx
+++ b/src/text_element_anchor.hxx
@@ -23,8 +23,9 @@
2323
2424 #include <glibmm/ustring.h>
2525 #include <gdkmm/cursor.h>
26-#include <pangomm/attrlist.h>
2726 #include <boost/range.hpp>
27+#include <pangomm/item.h>
28+#include <pangomm/glyphstring.h>
2829 #include <boost/unordered_map.hpp>
2930 #include "text_element_plain.hxx"
3031
@@ -63,11 +64,12 @@ public:
6364 Glib::ustring get_href() const { return href_; }
6465
6566 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;
7173
7274 private:
7375 virtual Anchor* do_clone() const { return new Anchor(*this); }
--- a/src/text_element_char_size_cache.cxx
+++ b/src/text_element_char_size_cache.cxx
@@ -20,6 +20,9 @@
2020
2121 #include "text_element_char_size_cache.hxx"
2222
23+#include <pangomm/glyphstring.h>
24+#include <boost/foreach.hpp>
25+
2326
2427 namespace dialektos {
2528
@@ -33,44 +36,42 @@ inline gunichar ucs4_to_ucs2(const gunichar ucs4) {
3336 } // anonymous namespace
3437
3538
36-CharSizeCache::CharSizeCache() { initialize(); }
39+CharSizeCache::ArrayClass::ArrayClass() : array_() {
40+ BOOST_FOREACH(int& i, array_) i = -1;
41+}
3742
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];
4548 }
4649
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) {
5052
5153 const gunichar ucs2 = ucs4_to_ucs2(uch);
5254
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;
6261 }
63-
64- width = double(w) / Pango::SCALE;
65- height = double(h) / Pango::SCALE;
62+ return double(width) / Pango::SCALE;
6663 }
6764
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+}
7069
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));
7475 }
7576
7677
--- a/src/text_element_char_size_cache.hxx
+++ b/src/text_element_char_size_cache.hxx
@@ -22,9 +22,10 @@
2222 #define TEXT_ELEMENT_CHAR_SIZE_CACHE_HXX
2323
2424 #include <glibmm/refptr.h>
25-#include <pangomm/layout.h>
25+#include <pangomm/item.h>
2626 #include <boost/array.hpp>
2727 #include <boost/utility.hpp>
28+#include <boost/unordered_map.hpp>
2829
2930
3031 namespace dialektos {
@@ -33,32 +34,22 @@ namespace text_element {
3334
3435
3536 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;
3745 public:
3846 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&);
4449 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_;
6253 };
6354
6455
--- a/src/text_element_id.cxx
+++ b/src/text_element_id.cxx
@@ -20,9 +20,13 @@
2020
2121 #include "text_element_id.hxx"
2222
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+
2528 #include "text_element_id_map.hxx"
29+#include "text_view_drawing_set.hxx"
2630
2731
2832 namespace dialektos {
@@ -30,22 +34,33 @@ namespace dialektos {
3034 namespace text_element {
3135
3236
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 {
3740
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+ }
4654 }
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);
4761 }
4862
63+
4964 } // namespace text_element
5065
5166 } // namespace dialektos
--- a/src/text_element_id.hxx
+++ b/src/text_element_id.hxx
@@ -21,6 +21,8 @@
2121 #ifndef TEXT_ELEMENT_ID_HXX
2222 #define TEXT_ELEMENT_ID_HXX
2323
24+#include <pangomm/item.h>
25+#include <pangomm/glyphstring.h>
2426 #include <boost/shared_ptr.hpp>
2527 #include "text_element_anchor.hxx"
2628
@@ -47,17 +49,13 @@ public:
4749 Anchor(range, bold, id), id_map_(id_map) {
4850 }
4951 virtual ~ID() {}
50-
5152 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;
5756
5857 private:
5958 virtual ID* do_clone() const { return new ID(*this); }
60-
6159 boost::shared_ptr<const IDMap> id_map_;
6260 };
6361
--- a/src/text_element_plain.cxx
+++ b/src/text_element_plain.cxx
@@ -26,6 +26,8 @@
2626 #include <pangomm/context.h>
2727 #include <pangomm/font.h>
2828 #include <pangomm/rectangle.h>
29+#include <pangomm/item.h>
30+#include <pangomm/glyphstring.h>
2931 #include <glibmm/refptr.h>
3032 #include <glibmm/ustring.h>
3133 #include <gdkmm/gc.h>
@@ -46,20 +48,13 @@ namespace text_element {
4648
4749 /* static data members */
4850 CharSizeCache Plain::char_size_cache;
49-gdouble Plain::approximate_char_height = -1;
5051
5152
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;
6358 }
6459
6560 void Plain::trim_right() {
@@ -85,101 +80,133 @@ void Plain::layout(text_view::LayoutSet& set) {
8580 x_start_ = set.x_start;
8681 x_end_ = set.x_end;
8782
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;
10393 }
104-
105- set.x += w;
10694 }
10795 }
10896
10997 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-
12298 size_t start_index = 0;
12399 size_t end_index = 0;
124100 get_selection_start_end_index(set.start_element, set.start_index,
125101 set.end_element, set.end_index, start_index, end_index);
126102
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;
138145 }
139146
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);
155166 }
167+
168+ do_draw_glyphs(set, item, glyphs, x, y, in_selection);
156169 }
157170
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);
158177
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);
160181 }
161182
183+Pango::FontMetrics Plain::get_metrics() const {
184+ return metrics_;
185+}
186+
187+
162188 bool Plain::is_xy_on_this(const gdouble x, const gdouble y) const {
163189
164190 gdouble x_pos = x_;
165191 gdouble y_pos = y_;
166192
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);
170196
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+ }
176202
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+ }
181207
182- x_pos += w;
208+ x_pos += w;
209+ }
183210 }
184211
185212 return false;
@@ -189,28 +216,30 @@ bool Plain::is_xy_near_to_this(const gdouble x, const gdouble y) const {
189216 gdouble x_pos = x_;
190217 gdouble y_pos = y_;
191218
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);
195222
196- if (x_pos + w > x_end_) {
197- // begin new line
223+ if (x_pos + w > x_end_) {
224+ // begin new line
198225
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_);
202234 }
203235
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+ }
207240
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;
211242 }
212-
213- x_pos += w;
214243 }
215244
216245 return false;
@@ -220,24 +249,27 @@ bool Plain::is_xy_near_to_this(const gdouble x, const gdouble y) const {
220249 Gdk::Rectangle Plain::xy_to_rectangle(gdouble x, gdouble y) const {
221250 gdouble x_pos = x_;
222251 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);
232255
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+ }
236261
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+ }
238269 }
239270
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_));
241273 }
242274
243275
@@ -247,35 +279,36 @@ int Plain::xy_to_index(const gdouble x, const gdouble y) const {
247279 gdouble y_pos = y_;
248280 int index = 0;
249281
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);
253285
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+ }
261293
262294 x_pos = x_start_;
263- y_pos += approximate_char_height;
264- }
295+ y_pos += get_approximate_char_height(metrics_);
296+ }
265297
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+ }
274307 }
275- }
276308
277- x_pos += w;
278- ++index;
309+ x_pos += w;
310+ ++index;
311+ }
279312 }
280313 return index;
281314 }
@@ -284,6 +317,17 @@ Gdk::CursorType Plain::get_cursor_type() const {
284317 return Gdk::XTERM;
285318 }
286319
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+
287331 void Plain::get_selection_start_end_index(
288332 const Plain* const start_element, const size_t start_index,
289333 const Plain* const end_element, const size_t end_index,
--- a/src/text_element_plain.hxx
+++ b/src/text_element_plain.hxx
@@ -25,8 +25,9 @@
2525 #include <glibmm/ustring.h>
2626 #include <gdkmm/cursor.h>
2727 #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>
3031 #include <boost/range.hpp>
3132 #include "text_element_char_size_cache.hxx"
3233
@@ -77,7 +78,7 @@ public:
7778 template <typename RangeT>
7879 Plain(const RangeT& range, bool bold) :
7980 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_() {}
8182
8283 virtual ~Plain() {}
8384
@@ -156,23 +157,30 @@ public:
156157 */
157158 virtual Gdk::CursorType get_cursor_type() const;
158159
160+ void itemize(const Glib::RefPtr<Pango::Context>&, const Pango::FontMetrics&);
161+
159162 /*! @brief return an approximate character height.
160163 *
161164 * @param layout for calculating the character height.
162165 * @return the approximate height.
163166 */
164- static double get_approximate_char_height(Glib::RefPtr<const Pango::Layout> layout);
167+ static double get_approximate_char_height(const Pango::FontMetrics&);
165168
166169 protected:
167170
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;
173176
174177 private:
175178 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+
176184 void get_selection_start_end_index(const Plain*, size_t, const Plain*, size_t,
177185 size_t&, size_t&) const;
178186
@@ -185,8 +193,11 @@ private:
185193 gdouble x_start_;
186194 gdouble x_end_;
187195
196+ std::vector<Pango::Item> items_;
197+
198+ Pango::FontMetrics metrics_;
199+
188200 static CharSizeCache char_size_cache;
189- static gdouble approximate_char_height;
190201 };
191202
192203 /*! @brief clone the text element type. This function is for Boost.PtrContainer.
--- a/src/text_element_res_num.cxx
+++ b/src/text_element_res_num.cxx
@@ -20,9 +20,12 @@
2020
2121 #include "text_element_res_num.hxx"
2222
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>
2527 #include "text_element_res_num_map.hxx"
28+#include "text_view_drawing_set.hxx"
2629
2730
2831 namespace dialektos {
@@ -30,20 +33,30 @@ namespace dialektos {
3033 namespace text_element {
3134
3235
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 {
3539
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+ }
4653 }
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);
4760 }
4861
4962
--- a/src/text_element_res_num.hxx
+++ b/src/text_element_res_num.hxx
@@ -22,7 +22,8 @@
2222 #define TEXT_ELEMENT_RES_NUM_HXX
2323
2424 #include <glibmm/ustring.h>
25-#include <pangomm/attrlist.h>
25+#include <pangomm/item.h>
26+#include <pangomm/glyphstring.h>
2627 #include <boost/lexical_cast.hpp>
2728 #include <boost/shared_ptr.hpp>
2829 #include "text_element_anchor.hxx"
@@ -57,11 +58,9 @@ public:
5758 size_t get_res_num() const { return res_num_; }
5859 protected:
5960
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;
6564
6665 private:
6766 virtual ResNum* do_clone() const { return new ResNum(*this); }
--- a/src/text_line.cxx
+++ b/src/text_line.cxx
@@ -32,13 +32,14 @@ namespace dialektos {
3232
3333 TextLine::TextLine(int res_num, int l_mgn) :
3434 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_() {
3636 }
3737
3838 TextLine::TextLine(const TextLine& rhs) :
3939 res_num_(rhs.res_num_), element_list_(rhs.element_list_),
4040 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_) {
4243 }
4344
4445 TextLine::~TextLine(){}
@@ -53,6 +54,14 @@ void TextLine::trim_right() {
5354 element_list_.back().trim_right();
5455 }
5556
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+
5665 bool TextLine::empty() const {
5766 return element_list_.empty();
5867 }
@@ -83,7 +92,7 @@ void TextLine::layout(text_view::LayoutSet& set) {
8392 BOOST_FOREACH(text_element::Plain& elem, element_list_) {
8493 elem.layout(set);
8594 }
86- set.y += text_element::Plain::get_approximate_char_height(set.layout);
95+ set.y += text_element::Plain::get_approximate_char_height(metrics_);
8796
8897 height_ = set.y - y_;
8998 }
--- a/src/text_line.hxx
+++ b/src/text_line.hxx
@@ -23,6 +23,9 @@
2323
2424 #include <boost/ptr_container/ptr_vector.hpp>
2525 #include <glibmm/ustring.h>
26+#include <glibmm/refptr.h>
27+#include <pangomm/context.h>
28+#include <pangomm/fontmetrics.h>
2629
2730
2831 namespace dialektos {
@@ -46,6 +49,7 @@ public:
4649 ~TextLine();
4750 void add_element(text_element::Plain* element);
4851 void trim_right();
52+ void itemize(const Glib::RefPtr<Pango::Context>&, const Pango::FontMetrics&);
4953 bool empty() const;
5054 bool includes(const text_element::Plain&) const;
5155 Glib::ustring get_selected_text(const text_view::GetSelectedSet& set) const;
@@ -67,6 +71,8 @@ private:
6771 int width_;
6872 int left_margin_;
6973 int right_margin_;
74+
75+ Pango::FontMetrics metrics_;
7076 };
7177
7278
--- a/src/text_view_drawable.cxx
+++ b/src/text_view_drawable.cxx
@@ -49,7 +49,6 @@ bool Drawable::on_expose_event(GdkEventExpose* event) {
4949
5050 DrawingSet set;
5151 set.window = window;
52- set.layout = pango_layout_;
5352 set.style = style;
5453 set.adj_value = value;
5554 set.start_element = pressed_element_;
--- a/src/text_view_drawing_set.hxx
+++ b/src/text_view_drawing_set.hxx
@@ -24,7 +24,6 @@
2424 #include <glibmm/refptr.h>
2525 #include <gdkmm/drawable.h>
2626 #include <gtkmm/style.h>
27-#include <pangomm/layout.h>
2827
2928
3029 namespace dialektos {
@@ -36,8 +35,6 @@ namespace text_view {
3635
3736
3837 struct LayoutSet {
39- Glib::RefPtr<Pango::Layout> layout;
40-
4138 gdouble x;
4239 gdouble y; // y position on the adjustment
4340
@@ -47,7 +44,6 @@ struct LayoutSet {
4744
4845 struct DrawingSet {
4946 Glib::RefPtr<Gdk::Drawable> window;
50- Glib::RefPtr<Pango::Layout> layout;
5147 Glib::RefPtr<const Gtk::Style> style;
5248
5349 gdouble adj_value; // adjustment value
--- a/src/text_view_layoutable.cxx
+++ b/src/text_view_layoutable.cxx
@@ -38,6 +38,8 @@ Layoutable::Layoutable():
3838 id_map_(new text_element::IDMap),
3939 res_num_map_(new text_element::ResNumMap),
4040 res_num_(0),
41+ metrics_(get_pango_context()->get_metrics(
42+ get_pango_context()->get_font_description())),
4143 width_(-1) {
4244 }
4345
@@ -45,13 +47,13 @@ Layoutable::~Layoutable() {
4547 }
4648
4749 void Layoutable::add_line(TextLine* line) {
50+ line->itemize(get_pango_context(), metrics_);
4851 line_list_.push_back(line);
4952 }
5053
5154 void Layoutable::relayout() {
5255 const int width = get_width();
5356 LayoutSet set;
54- set.layout = pango_layout_;
5557 set.y = 0;
5658
5759 BOOST_FOREACH(TextLine& line, line_list_) {
@@ -66,7 +68,7 @@ void Layoutable::relayout() {
6668 adjustment_.set_upper(set.y);
6769 }
6870
69-bool Layoutable::on_configure_event(GdkEventConfigure* event) {
71+void Layoutable::safe_layout() {
7072 if (width_ == -1)
7173 relayout();
7274 else if (width_ != get_width()) {
@@ -93,9 +95,27 @@ bool Layoutable::on_configure_event(GdkEventConfigure* event) {
9395 }
9496 adjustment_.set_value(y - delta);
9597 }
98+}
99+
100+bool Layoutable::on_configure_event(GdkEventConfigure* event) {
101+ safe_layout();
96102 return Scrollable::on_configure_event(event);
97103 }
98104
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+}
99119
100120 const TextLine* Layoutable::get_text_line(const gdouble y_adj) const {
101121
--- a/src/text_view_layoutable.hxx
+++ b/src/text_view_layoutable.hxx
@@ -52,6 +52,7 @@ public:
5252 Layoutable();
5353 virtual ~Layoutable();
5454 void relayout();
55+ void safe_layout();
5556 void add_line(TextLine*);
5657 void set_id_map(IDMapPtrType map) { id_map_ = map; }
5758 void set_res_num_map(ResNumMapPtrType map) { res_num_map_ = map; }
@@ -62,6 +63,8 @@ public:
6263 protected:
6364 //virtual bool on_expose_event(GdkEventExpose*);
6465 virtual bool on_configure_event(GdkEventConfigure*);
66+ virtual void on_realize();
67+ virtual void on_style_changed(const Glib::RefPtr<Gtk::Style>& previous);
6568
6669 const TextLine* get_text_line(gdouble y) const;
6770 const TextLine* get_nearest_text_line(gdouble& y) const;
@@ -73,6 +76,7 @@ protected:
7376 boost::shared_ptr<text_element::IDMap> id_map_;
7477 boost::shared_ptr<text_element::ResNumMap> res_num_map_;
7578 int res_num_;
79+ Pango::FontMetrics metrics_;
7680 /* cached */
7781 gint width_;
7882 };
--- a/src/text_view_popup.hxx
+++ b/src/text_view_popup.hxx
@@ -52,6 +52,11 @@ class Popup: public Gtk::Window {
5252 original_line_list_(original) {
5353 }
5454
55+ void show() {
56+ TextView::show();
57+ realize();
58+ }
59+
5560 private:
5661 virtual const LineListType& get_original_line_list() const {
5762 return original_line_list_;
Show on old repository browser