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_view_popupable.hxx"
23 #include <glibmm/ustring.h>
24 #include <gdkmm/general.h>
25 #include <gdkmm/rectangle.h>
26 #include <boost/foreach.hpp>
27 #include <boost/unordered_set.hpp>
28 #include <boost/algorithm/string.hpp>
29 #include <boost/lambda/lambda.hpp>
30 #include <boost/lexical_cast.hpp>
31 #include "text_line.hxx"
32 #include "text_element_anchor.hxx"
33 #include "text_element_id.hxx"
34 #include "text_element_anchor.hxx"
35 #include "text_element_res_num.hxx"
36 #include "text_element_id_map.hxx"
37 #include "text_element_res_num_map.hxx"
38 #include "text_view_popup.hxx"
46 Popupable::Popupable(): Drawable(), popup_() {}
48 Popupable::~Popupable() {}
50 bool Popupable::on_timeout() {
54 if (is_pointer_on_the_element()) return true;
56 if (is_pointer_on_the_popup()) return true;
62 bool Popupable::is_pointer_on_the_element() const {
63 if (!popup_) return false;
65 using text_element::Plain;
66 using text_element::Anchor;
69 get_pointer(x_ptr, y_ptr);
70 y_ptr += adjustment_.get_value();
72 const Plain* element = get_text_element(x_ptr, y_ptr);
73 if (const Anchor* anchor = dynamic_cast<const Anchor*>(element))
74 if (popup_->is_same_origin(*anchor)) return true;
79 bool Popupable::is_pointer_on_the_popup() const {
80 if (!popup_) return false;
83 popup_->get_pointer(x_ptr, y_ptr);
85 if (x_ptr >= 0 && x_ptr < popup_->get_width() &&
86 y_ptr >= 0 && y_ptr < popup_->get_height())
89 if (popup_->on_the_child()) return true;
94 void Popupable::do_id_hovered_event(const text_element::ID& elem) {
97 Glib::ustring id = elem.get_href();
98 const std::vector<int> res_num_list = id_map_->get_res_num_list(id);
99 const boost::unordered_set<int>
100 res_num_set(res_num_list.begin(), res_num_list.end());
102 if (res_num_set.size() < 2) return;
104 LineListType new_line;
105 build_line_list_for_popup(res_num_set, new_line);
107 do_popup(elem, new_line);
110 void Popupable::do_anchor_hovered_event(const text_element::Anchor& elem) {
113 using namespace boost::lambda;
115 Glib::ustring text = elem.get_text();
116 if (!boost::algorithm::starts_with(text, ">>")) return;
118 boost::trim_left_if(text, _1 == '>');
120 boost::iterator_range<Glib::ustring::iterator> ret =
121 boost::algorithm::find_first(text, "-");
123 boost::unordered_set<int> set;
126 // consider like '123-456'
130 left_num = boost::lexical_cast<int>(
131 Glib::ustring(text.begin(), ret.begin()));
132 right_num = boost::lexical_cast<int>(
133 Glib::ustring(ret.end(), text.end()));
134 } catch (const std::exception&) { return; }
135 if (left_num > right_num) std::swap(left_num, right_num);
136 for (int i = left_num; i <= right_num; ++i) set.insert(i);
138 // consider only digit string.
141 res_num = boost::lexical_cast<int>(text);
142 } catch (const std::exception&) { return; }
146 LineListType new_line;
147 build_line_list_for_popup(set, new_line);
149 do_popup(elem, new_line);
152 void Popupable::do_res_num_hovered_event(const text_element::ResNum& elem) {
155 int res_num = elem.get_res_num();
156 const std::vector<int> res_num_list =
157 res_num_map_->get_res_num_list(res_num);
158 const boost::unordered_set<int>
159 res_num_set(res_num_list.begin(), res_num_list.end());
161 if (res_num_set.empty()) return;
163 LineListType new_line;
164 build_line_list_for_popup(res_num_set, new_line);
166 do_popup(elem, new_line);
169 void Popupable::do_popup(const text_element::Anchor& elem,
170 const LineListType& line) {
172 if (line.empty()) return;
178 y += adjustment_.get_value();
179 Gdk::Rectangle rect = elem.xy_to_rectangle(x, y);
181 //if (popup_) delete popup_;
182 popup_.reset(new Popup(line, get_original_line_list(),
183 elem, id_map_, res_num_map_));
186 get_window()->get_origin(x_org, y_org);
189 popup_->get_size(width, height);
191 x_org += rect.get_x();
192 y_org += rect.get_y() - adjustment_.get_value() - height;
194 if (x_org + width > Gdk::screen_width()) {
195 x_org = Gdk::screen_width() - width;
199 y_org += rect.get_height();
202 popup_->move(x_org, y_org);
205 Glib::signal_timeout().connect(sigc::mem_fun(
206 *this, &Popupable::on_timeout), 100);
209 void Popupable::on_anchor_hovered_event(const text_element::Anchor& elem) {
210 if (popup_ && popup_->is_same_origin(elem)) return;
212 using text_element::ID;
213 using text_element::ResNum;
215 // if (typeid(elem) == typeid(ID)) {
216 if (const ID* id = dynamic_cast<const ID*>(&elem)) {
217 do_id_hovered_event(*id);
221 // if (typeid(elem) == typeid(ResNum)) {
222 if (const ResNum* res_num = dynamic_cast<const ResNum*>(&elem)) {
223 do_res_num_hovered_event(*res_num);
227 do_anchor_hovered_event(elem);
230 const Popupable::LineListType& Popupable::get_original_line_list() const {
234 void Popupable::build_line_list_for_popup(
235 const boost::unordered_set<int>& res_nums, LineListType& target) const {
237 BOOST_FOREACH(const TextLine& line, get_original_line_list()) {
238 const int res_num = line.get_res_num();
239 boost::unordered_set<int>::const_iterator it = res_nums.find(res_num);
240 if (it != res_nums.end()) target.push_back(new TextLine(line));
245 } // namespace text_view
247 } // namespace diakeltos