2 * Copyright (C) 2009 by Aiwota Programmer
3 * aiwotaprog@tetteke.tk
5 * This file is part of Dialektos.
7 * Dialektos is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * Dialektos is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
21 #include "text_element_plain.hxx"
23 #include <pangomm/layout.h>
24 #include <pangomm/attributes.h>
25 #include <pangomm/attrlist.h>
26 #include <pangomm/context.h>
27 #include <pangomm/font.h>
28 #include <pangomm/rectangle.h>
29 #include <glibmm/refptr.h>
30 #include <glibmm/ustring.h>
32 #include <gdkmm/cursor.h>
33 #include <gdkmm/rectangle.h>
34 #include <boost/foreach.hpp>
35 #include <boost/algorithm/string.hpp>
36 #include <boost/lambda/lambda.hpp>
37 #include <boost/array.hpp>
38 #include "text_view_drawing_set.hxx"
39 #include "text_element_char_size_cache.hxx"
44 namespace text_element {
47 /* static data members */
48 CharSizeCache Plain::char_size_cache;
49 gdouble Plain::approximate_char_height = -1;
52 double Plain::get_approximate_char_height(
53 Glib::RefPtr<const Pango::Layout> layout) {
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;
62 return approximate_char_height;
65 void Plain::trim_right() {
66 using namespace boost::lambda;
68 boost::trim_right_if(str_, _1 == ' ');
71 void Plain::layout(text_view::LayoutSet& set) {
73 /* caching for drawing */
76 x_start_ = set.x_start;
79 Pango::AttrList list = Pango::AttrList();
80 Pango::AttrInt attr = bold_ ?
81 Pango::Attribute::create_attr_weight(Pango::WEIGHT_BOLD):
82 Pango::Attribute::create_attr_weight(Pango::WEIGHT_NORMAL);
84 set.layout->set_attributes(list);
86 BOOST_FOREACH(const gunichar& uch, str_) {
88 char_size_cache.get_char_size(uch, set.layout, w, h, bold_);
90 if (set.x + w > x_end_) {
93 set.y += get_approximate_char_height(set.layout);
100 void Plain::draw(text_view::DrawingSet& set) const {
102 Glib::RefPtr<const Gdk::GC> gc = set.style->get_text_gc(Gtk::STATE_NORMAL);
104 Pango::AttrList list = Pango::AttrList();
105 Pango::AttrInt attr = bold_ ?
106 Pango::Attribute::create_attr_weight(Pango::WEIGHT_BOLD):
107 Pango::Attribute::create_attr_weight(Pango::WEIGHT_NORMAL);
110 set_attributes(list);
111 set.layout->set_attributes(list);
113 size_t start_index = 0;
114 size_t end_index = 0;
115 get_selection_start_end_index(set.start_element, set.start_index,
116 set.end_element, set.end_index, start_index, end_index);
120 size_t index_count = 0;
121 BOOST_FOREACH(const gunichar& uch, str_) {
123 char_size_cache.get_char_size_from_cache(uch, w, h, bold_);
125 if (x + w > x_end_) {
128 y += approximate_char_height;//(set.layout);
131 double deltaY = approximate_char_height - h;
132 set.layout->set_text(Glib::ustring(1, uch));
134 if (start_index != end_index &&
135 index_count >= start_index && index_count < end_index)
136 set.window->draw_layout(gc, x, y + deltaY - set.adj_value,
138 set.style->get_fg(Gtk::STATE_SELECTED),
139 set.style->get_bg(Gtk::STATE_SELECTED));
141 set.window->draw_layout(gc, x, y + deltaY - set.adj_value,
150 void Plain::set_attributes(Pango::AttrList& list) const {
153 bool Plain::is_xy_on_this(const gdouble x, const gdouble y) const {
158 BOOST_FOREACH(const gunichar& uch, str_) {
160 char_size_cache.get_char_size_from_cache(uch, w, h, bold_);
162 if (x_pos + w > x_end_) {
165 y_pos += approximate_char_height;
168 if (x >= x_pos && x < x_pos + w &&
169 y >= y_pos && y < y_pos + approximate_char_height) {
179 bool Plain::is_xy_near_to_this(const gdouble x, const gdouble y) const {
183 BOOST_FOREACH(const gunichar& uch, str_) {
185 char_size_cache.get_char_size_from_cache(uch, w, h, bold_);
187 if (x_pos + w > x_end_) {
190 if (x >= x_pos && y >= y_pos && y < y_pos + approximate_char_height) {
191 // (x, y) is on the spaces caused by wrapping
196 y_pos += approximate_char_height;
199 if (x >= x_pos && x < x_pos + w &&
200 y >= y_pos && y < y_pos + approximate_char_height) {
211 Gdk::Rectangle Plain::xy_to_rectangle(gdouble x, gdouble y) const {
214 BOOST_FOREACH(const gunichar& uch, str_) {
216 char_size_cache.get_char_size_from_cache(uch, w, h, bold_);
218 if (x_pos + w > x_end_) {
221 y_pos += approximate_char_height;
224 if (x >= x_pos && x < x_pos + w &&
225 y >= y_pos && y < y_pos + approximate_char_height)
226 return Gdk::Rectangle(x_pos, y_pos, w, approximate_char_height);
231 return Gdk::Rectangle(x_pos, y_pos, 0, approximate_char_height);
235 int Plain::xy_to_index(const gdouble x, const gdouble y) const {
241 BOOST_FOREACH(const gunichar& uch, str_) {
243 char_size_cache.get_char_size_from_cache(uch, w, h, bold_);
245 if (x_pos + w > x_end_) {
248 y >= y_pos && y < y_pos + approximate_char_height) {
249 // (x, y) is on the spaces caused by wrapping
254 y_pos += approximate_char_height;
257 if (x >= x_pos && x < x_pos + w &&
258 y >= y_pos && y < y_pos + approximate_char_height) {
259 if (x <= x_pos + w/2) {
260 // left of this character
263 // right of this character
274 Gdk::CursorType Plain::get_cursor_type() const {
278 void Plain::get_selection_start_end_index(
279 const Plain* const start_element, const size_t start_index,
280 const Plain* const end_element, const size_t end_index,
281 size_t& start, size_t& end) const {
285 if (start_element && end_element) {
286 if (start_element == this && end_element == this) {
289 } else if (start_element == this) {
292 } else if (end_element == this) {
294 } else if (start_element->y_ < y_ && end_element->y_ > y_) {
296 } else if (start_element->y_ == y_ && end_element->y_ == y_ &&
297 start_element->x_ < x_ && end_element->x_ > x_) {
299 } else if (start_element->y_ == y_ && end_element->y_ != y_ &&
300 start_element->x_ < x_) {
302 } else if (end_element->y_ == y_ && start_element->y_ != y_ &&
303 end_element->x_ > x_) {
311 } // namespace text_element
313 } // namespace dialektos