22 #include <libgtkcrnmm_config.h>
28 using namespace GtkCRN;
30 #ifdef CRN_USING_GTKMM3
31 # define get_red_p get_red
32 # define get_green_p get_green
33 # define get_blue_p get_blue
36 int Image::selection_margin(5);
40 #ifndef CRN_USING_GTKMM3
45 need_recompute(
false),
49 #ifdef CRN_USING_GTKMM3
50 image_actions(Gio::SimpleActionGroup::create()),
52 image_actions(Gtk::ActionGroup::create(
"image")),
55 scroll_cursor(Gdk::FLEUR),
56 select_cursor(Gdk::CROSS),
57 move_cursor(Gdk::HAND1),
58 move_1_cursor(Gdk::FLEUR),
59 drag_left_cursor(Gdk::LEFT_SIDE),
60 drag_bottom_left_cursor(Gdk::BOTTOM_LEFT_CORNER),
61 drag_bottom_cursor(Gdk::BOTTOM_SIDE),
62 drag_bottom_right_cursor(Gdk::BOTTOM_RIGHT_CORNER),
63 drag_right_cursor(Gdk::RIGHT_SIDE),
64 drag_top_right_cursor(Gdk::TOP_RIGHT_CORNER),
65 drag_top_cursor(Gdk::TOP_SIDE),
66 drag_top_left_cursor(Gdk::TOP_LEFT_CORNER),
67 user_cursor(Gdk::TARGET)
69 #ifndef CRN_USING_GTKMM3
70 attach(hruler, 1, 2, 0, 1, Gtk::FILL, Gtk::FILL, 0, 0);
73 attach(vruler, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL, 0, 0);
78 #ifdef CRN_USING_GTKMM3
79 attach(da, 1, 1, 1, 1);
83 attach(da, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND | Gtk::SHRINK, Gtk::FILL | Gtk::EXPAND | Gtk::SHRINK, 0, 0);
85 da.add_events(Gdk::EXPOSURE_MASK | Gdk::STRUCTURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK);
86 #ifdef CRN_USING_GTKMM3
87 da.signal_draw().connect(sigc::mem_fun(
this, &Image::expose));
89 da.signal_expose_event().connect(sigc::mem_fun(
this, &Image::expose));
91 da.signal_configure_event().connect(sigc::mem_fun(
this, &Image::configure));
92 da.signal_motion_notify_event().connect(sigc::mem_fun(
this, &Image::mouse_motion));
93 da.signal_button_press_event().connect(sigc::mem_fun(
this, &Image::button_clicked));
94 da.signal_button_release_event().connect(sigc::mem_fun(
this, &Image::button_clicked));
95 da.signal_scroll_event().connect(sigc::mem_fun(
this, &Image::mouse_wheel));
98 hscrollbar.get_adjustment()->set_lower(0);
99 hscrollbar.get_adjustment()->set_step_increment(10);
100 hscrollbar.get_adjustment()->set_page_increment(100);
101 #ifdef CRN_USING_GTKMM3
102 attach(hscrollbar, 1, 2, 1, 1);
103 hscrollbar.set_hexpand(
true);
104 hscrollbar.set_vexpand(
false);
105 hscrollbar.set_orientation(Gtk::ORIENTATION_HORIZONTAL),
107 attach(hscrollbar, 1, 2, 2, 3, Gtk::FILL, Gtk::FILL, 0, 0);
109 hscrollbar.signal_value_changed().connect(sigc::mem_fun(
this, &Image::scrolled));
113 vscrollbar.get_adjustment()->set_lower(0);
114 vscrollbar.get_adjustment()->set_step_increment(10);
115 vscrollbar.get_adjustment()->set_page_increment(100);
116 #ifdef CRN_USING_GTKMM3
117 attach(vscrollbar, 2, 1, 1, 1);
118 vscrollbar.set_hexpand(
false);
119 vscrollbar.set_vexpand(
true);
120 vscrollbar.set_orientation(Gtk::ORIENTATION_VERTICAL),
122 attach(vscrollbar, 2, 3, 1, 2, Gtk::FILL, Gtk::FILL, 0, 0);
124 vscrollbar.signal_value_changed().connect(sigc::mem_fun(
this, &Image::scrolled));
128 set_sensitive(
false);
129 refresher = Glib::signal_timeout().connect(sigc::mem_fun(
this, &Image::refresh), 100);
132 #ifdef CRN_USING_GTKMM3
133 image_actions->add_action(
"zoom-in", sigc::mem_fun(
this, &
Image::zoom_in));
134 image_actions->add_action(
"zoom-out", sigc::mem_fun(
this, &
Image::zoom_out));
135 image_actions->add_action(
"zoom-100", sigc::mem_fun(
this, &
Image::zoom_100));
136 image_actions->add_action(
"zoom-fit", sigc::mem_fun(
this, &
Image::zoom_fit));
139 image_actions->add(Gtk::Action::create(
"image-zoom-in", Gtk::Stock::ZOOM_IN), sigc::mem_fun(
this, &
Image::zoom_in));
140 image_actions->add(Gtk::Action::create(
"image-zoom-out", Gtk::Stock::ZOOM_OUT), sigc::mem_fun(
this, &
Image::zoom_out));
141 image_actions->add(Gtk::Action::create(
"image-zoom-100", Gtk::Stock::ZOOM_100), sigc::mem_fun(
this, &
Image::zoom_100));
142 image_actions->add(Gtk::Action::create(
"image-zoom-fit", Gtk::Stock::ZOOM_FIT), sigc::mem_fun(
this, &
Image::zoom_fit));
143 image_actions->add(Gtk::Action::create(
"image-clear-user-selection", Gtk::Stock::CLEAR,
_(
"_Clear User Selection"),
_(
"Clear User Selection")), sigc::mem_fun(
this, &
Image::clear_selection));
152 refresher.disconnect();
155 #ifndef CRN_USING_GTKMM3
186 set_sensitive(
false);
191 hscrollbar.get_adjustment()->set_upper(image->get_width());
192 vscrollbar.get_adjustment()->set_upper(image->get_height());
193 image_bounds =
crn::Rect(0, 0, image->get_width() - 1, image->get_height() - 1);
194 need_recompute =
true;
209 throw Glib::OptionError(Glib::OptionError::BAD_VALUE, Glib::ustring(
"void Image::set_zoom(double z): ") +
_(
"null or negative zoom value."));
211 need_recompute =
true;
213 scrolled_event.emit(
int(hscrollbar.get_value()),
int(vscrollbar.get_value()));
222 need_recompute =
true;
224 scrolled_event.emit(
int(hscrollbar.get_value()),
int(vscrollbar.get_value()));
235 need_recompute =
true;
237 scrolled_event.emit(
int(hscrollbar.get_value()),
int(vscrollbar.get_value()));
246 need_recompute =
true;
248 scrolled_event.emit(
int(hscrollbar.get_value()),
int(vscrollbar.get_value()));
260 need_recompute =
true;
262 scrolled_event.emit(
int(hscrollbar.get_value()),
int(vscrollbar.get_value()));
277 if (image_bounds.
GetTop() > y) y = image_bounds.
GetTop();
279 pos.
X = x - int(dispw / zoom / 2.0);
280 hscrollbar.set_value(pos.
X);
281 pos.
Y = y - int(disph / zoom / 2.0);
282 vscrollbar.set_value(pos.
Y);
283 need_recompute =
true;
290 #ifdef CRN_USING_GTKMM3
300 void Image::scrolled()
302 need_recompute =
true;
303 scrolled_event.emit(
int(hscrollbar.get_value()),
int(vscrollbar.get_value()));
312 #ifdef CRN_USING_GTKMM3
313 bool Image::expose(
const Cairo::RefPtr<Cairo::Context> &cc)
315 bool Image::expose(GdkEventExpose *ev)
326 bool Image::configure(GdkEventConfigure *ev)
330 need_recompute =
true;
338 bool Image::mouse_motion(GdkEventMotion* ev)
341 #ifndef CRN_USING_GTKMM3
342 hruler.set_range(pos.
X, pos.
X +
int(dispw / zoom), pos.
X +
int(ev->x / zoom), pos.
X +
int(dispw / zoom));
343 vruler.set_range(pos.
Y, pos.
Y +
int(disph / zoom), pos.
Y +
int(ev->y / zoom), pos.
Y +
int(disph / zoom));
352 MouseMode mode = find_selection_at(ev->x, ev->y, s1, s2);
353 set_cursor_from_mode(mode);
358 double dx = (click_ref.
X - ev->x) / zoom;
359 double dy = (click_ref.
Y - ev->y) / zoom;
360 hscrollbar.set_value(hscrollbar.get_value() + dx);
361 vscrollbar.set_value(vscrollbar.get_value() + dy);
367 switch (selection_type)
372 int(
crn::Min(click_ref.
X, ev->x) / zoom) + pos.
X,
373 int(
crn::Min(click_ref.
Y, ev->y) / zoom) + pos.
Y,
374 int(
crn::Max(click_ref.
X, ev->x) / zoom) + pos.
X,
375 int(
crn::Max(click_ref.
Y, ev->y) / zoom) + pos.
Y);
377 newsel &= image_bounds;
388 int x = int(ev->x / zoom + pos.
X);
389 int y = int(ev->y / zoom + pos.
Y);
408 int x = int(ev->x / zoom + pos.
X);
409 int y = int(ev->y / zoom + pos.
Y);
431 double dx = (ev->x - click_ref.
X) / zoom;
432 double dy = (ev->y - click_ref.
Y) / zoom;
436 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
438 Line* li =
dynamic_cast<Line*
>(item.get());
441 if (!overlays[selected_overlay].config.can_jut_out)
459 Rectangle* rec=
dynamic_cast<Rectangle*
>(item.get());
462 if (!overlays[selected_overlay].config.can_jut_out)
467 ox =
crn::Max(-
crn::Min(rec->rect.GetTopLeft().X, rec->rect.GetBottomRight().X), ox);
471 oy =
crn::Max(-
crn::Min(rec->rect.GetTopLeft().Y, rec->rect.GetBottomRight().Y), oy);
473 rec->rect.SetLeft(rec->rect.GetTopLeft().X + ox);
474 rec->rect.SetTop(rec->rect.GetTopLeft().Y + oy);
475 rec->rect.SetRight(rec->rect.GetBottomRight().X + ox);
476 rec->rect.SetBottom(rec->rect.GetBottomRight().Y + oy);
478 Polygon* pol=
dynamic_cast<Polygon*
>(item.get());
481 if (!overlays[selected_overlay].config.can_jut_out)
483 int x_maximum=pol->points[0].X;
484 int y_maximum=pol->points[0].Y;
485 int x_minimum=pol->points[0].X;
486 int y_minimum=pol->points[0].Y;
487 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
489 if(x_maximum < pol->points[nb].X)
490 x_maximum = pol->points[nb].X;
491 if(y_maximum < pol->points[nb].Y)
492 y_maximum = pol->points[nb].Y;
493 if(x_minimum > pol->points[nb].X)
494 x_minimum = pol->points[nb].X;
495 if(y_minimum > pol->points[nb].Y)
496 y_minimum = pol->points[nb].Y;
507 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
509 pol->points[nb].X += ox;
510 pol->points[nb].Y += oy;
514 click_ref.
X = ev->x + (ox - dx) * zoom;
515 click_ref.
Y = ev->y + (oy - dy) * zoom;
523 double dx = (ev->x - click_ref.
X) / zoom;
524 double dy = (ev->y - click_ref.
Y) / zoom;
527 if(movePoint !=
nullptr)
530 std:: unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
531 Line* li =
dynamic_cast<Line*
>(item.get());
534 if (!overlays[selected_overlay].config.can_jut_out)
545 movePoint->
X += int(ox * zoom);
546 movePoint->
Y += int(oy * zoom);
548 Point* po =
dynamic_cast<Point*
>(item.get());
551 if (!overlays[selected_overlay].config.can_jut_out)
562 movePoint->
X += int(ox * zoom);
563 movePoint->
Y += int(oy * zoom);
565 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
568 if (!overlays[selected_overlay].config.can_jut_out)
570 int x_maximum=pol->points[0].X;
571 int y_maximum=pol->points[0].Y;
572 int x_minimum=pol->points[0].X;
573 int y_minimum=pol->points[0].Y;
574 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
576 if(x_maximum < pol->points[nb].X)
577 x_maximum = pol->points[nb].X;
578 if(y_maximum < pol->points[nb].Y)
579 y_maximum = pol->points[nb].Y;
580 if(x_minimum > pol->points[nb].X)
581 x_minimum = pol->points[nb].X;
582 if(y_minimum > pol->points[nb].Y)
583 y_minimum = pol->points[nb].Y;
598 if(ev->type == GDK_BUTTON_RELEASE)
602 click_ref.
X = ev->x + (ox - dx) * zoom;
603 click_ref.
Y = ev->y + (oy - dy) * zoom;
610 int x = pos.
X + int(ev->x / zoom);
613 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
615 Line* li =
dynamic_cast<Line*
>(item.get());
620 if (!overlays[selected_overlay].config.can_jut_out)
627 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
630 if (x < rec->rect.GetRight())
632 if (!overlays[selected_overlay].config.can_jut_out)
634 rec->rect.SetLeft(x);
639 Point* po =
dynamic_cast<Point*
>(item.get());
642 if (!overlays[selected_overlay].config.can_jut_out)
649 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
652 int x_maximum=pol->points[0].X;
653 int x_minimum=pol->points[0].X;
654 size_t id_minimim = 0;
655 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
657 if(x_maximum < pol->points[nb].X)
658 x_maximum = pol->points[nb].X;
659 if(x_minimum > pol->points[nb].X)
661 x_minimum = pol->points[nb].X;
668 if (!overlays[selected_overlay].config.can_jut_out)
670 pol->points[id_minimim].X = x;
679 int x = pos.
X + int(ev->x / zoom);
681 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
683 Line* li =
dynamic_cast<Line*
>(item.get());
688 if (!overlays[selected_overlay].config.can_jut_out)
695 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
699 if (x > rec->rect.GetLeft())
701 if (!overlays[selected_overlay].config.can_jut_out)
703 rec->rect.SetRight(x);
708 Point* po =
dynamic_cast<Point*
>(item.get());
711 if (!overlays[selected_overlay].config.can_jut_out)
718 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
722 int x_minimum=pol->points[0].X;
723 int x_maximum=pol->points[0].X;
724 size_t id_maximum = 0;
725 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
727 if(x_minimum > pol->points[nb].X)
728 x_minimum = pol->points[nb].X;
729 if(x_maximum < pol->points[nb].X)
731 x_maximum = pol->points[nb].X;
738 if (!overlays[selected_overlay].config.can_jut_out)
740 pol->points[id_maximum].X = x;
749 int y = pos.
Y + int(ev->y / zoom);
750 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
752 Line* li =
dynamic_cast<Line*
>(item.get());
758 if (!overlays[selected_overlay].config.can_jut_out)
765 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
769 if (y < rec->rect.GetBottom())
771 if (!overlays[selected_overlay].config.can_jut_out)
778 Point* po =
dynamic_cast<Point*
>(item.get());
781 if (!overlays[selected_overlay].config.can_jut_out)
788 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
791 int y_maximum=pol->points[0].Y;
792 int y_minimum=pol->points[0].Y;
793 size_t id_minimim = 0;
794 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
796 if(y_maximum < pol->points[nb].Y)
797 y_maximum = pol->points[nb].Y;
798 if(y_minimum > pol->points[nb].Y)
800 y_minimum = pol->points[nb].Y;
807 if (!overlays[selected_overlay].config.can_jut_out)
809 pol->points[id_minimim].Y = y;
818 int y = pos.
Y + int(ev->y / zoom);
819 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
821 Line* li =
dynamic_cast<Line*
>(item.get());
826 if (!overlays[selected_overlay].config.can_jut_out)
833 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
836 if (y > rec->rect.GetTop())
838 if (!overlays[selected_overlay].config.can_jut_out)
840 rec->rect.SetBottom(y);
845 Point* po =
dynamic_cast<Point*
>(item.get());
848 if (!overlays[selected_overlay].config.can_jut_out)
855 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
858 int y_minimum = pol->points[0].Y;
859 int y_maximum = pol->points[0].Y;
860 size_t id_maximum = 0;
861 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
863 if (y_minimum > pol->points[nb].Y)
864 y_minimum = pol->points[nb].Y;
865 if (y_maximum < pol->points[nb].Y)
867 y_maximum = pol->points[nb].Y;
874 if (!overlays[selected_overlay].config.can_jut_out)
876 pol->points[id_maximum].Y = y;
885 int x = pos.
X + int(ev->x / zoom);
887 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
889 Line* li =
dynamic_cast<Line*
>(item.get());
895 if (!overlays[selected_overlay].config.can_jut_out)
902 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
906 if (x < rec->rect.GetRight())
908 if (!overlays[selected_overlay].config.can_jut_out)
910 rec->rect.SetLeft(x);
915 Point* po =
dynamic_cast<Point*
>(item.get());
918 if (!overlays[selected_overlay].config.can_jut_out)
925 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
928 int x_maximum=pol->points[0].X;
929 int x_minimum=pol->points[0].X;
930 size_t id_minimim = 0;
931 for(
size_t nb = 0; nb < pol->points.size(); ++nb)
933 if(x_maximum < pol->points[nb].X)
934 x_maximum = pol->points[nb].X;
935 if(x_minimum > pol->points[nb].X)
937 x_minimum = pol->points[nb].X;
944 if (!overlays[selected_overlay].config.can_jut_out)
946 pol->points[id_minimim].X = x;
951 int y = pos.
Y + int(ev->y / zoom);
958 if (!overlays[selected_overlay].config.can_jut_out)
968 if (y < rec->rect.GetBottom())
970 if (!overlays[selected_overlay].config.can_jut_out)
979 if (!overlays[selected_overlay].config.can_jut_out)
989 int y_maximum = pol->points[0].Y;
990 int y_minimum = pol->points[0].Y;
991 size_t id_minimim = 0;
992 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
994 if (y_maximum < pol->points[nb].Y)
995 y_maximum = pol->points[nb].Y;
996 if (y_minimum > pol->points[nb].Y)
998 y_minimum = pol->points[nb].Y;
1004 if (!overlays[selected_overlay].config.can_jut_out)
1006 pol->points[id_minimim].Y = y;
1014 int x = pos.
X + int(ev->x / zoom);
1016 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
1018 Line* li =
dynamic_cast<Line*
>(item.get());
1023 if (!overlays[selected_overlay].config.can_jut_out)
1030 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
1034 if (x > rec->rect.GetLeft())
1036 if (!overlays[selected_overlay].config.can_jut_out)
1038 rec->rect.SetRight(x);
1043 Point* po =
dynamic_cast<Point*
>(item.get());
1046 if (!overlays[selected_overlay].config.can_jut_out)
1053 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
1056 int x_minimum = pol->points[0].X;
1057 int x_maximum = pol->points[0].X;
1058 size_t id_maximum = 0;
1059 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
1061 if (x_minimum > pol->points[nb].X)
1062 x_minimum = pol->points[nb].X;
1063 if (x_maximum < pol->points[nb].X)
1065 x_maximum = pol->points[nb].X;
1072 if (!overlays[selected_overlay].config.can_jut_out)
1074 pol->points[id_maximum].X = x;
1079 int y = pos.
Y + int(ev->y / zoom);
1086 if (!overlays[selected_overlay].config.can_jut_out)
1096 if (y < rec->rect.GetBottom())
1098 if (!overlays[selected_overlay].config.can_jut_out)
1100 rec->rect.SetTop(y);
1107 if (!overlays[selected_overlay].config.can_jut_out)
1116 int y_maximum = pol->points[0].Y;
1117 int y_minimum = pol->points[0].Y;
1118 size_t id_minimim = 0;
1119 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
1121 if (y_maximum < pol->points[nb].Y)
1122 y_maximum = pol->points[nb].Y;
1123 if (y_minimum > pol->points[nb].Y)
1125 y_minimum = pol->points[nb].Y;
1132 if (!overlays[selected_overlay].config.can_jut_out)
1134 pol->points[id_minimim].Y = y;
1142 int x = pos.
X + int(ev->x / zoom);
1144 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
1146 Line* li =
dynamic_cast<Line*
>(item.get());
1152 if (!overlays[selected_overlay].config.can_jut_out)
1158 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
1162 if (x < rec->rect.GetRight())
1164 if (!overlays[selected_overlay].config.can_jut_out)
1166 rec->rect.SetLeft(x);
1170 Point* po =
dynamic_cast<Point*
>(item.get());
1173 if (!overlays[selected_overlay].config.can_jut_out)
1178 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
1181 int x_maximum = pol->points[0].X;
1182 int x_minimum = pol->points[0].X;
1183 size_t id_minimim = 0;
1184 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
1186 if (x_maximum < pol->points[nb].X)
1187 x_maximum = pol->points[nb].X;
1188 if (x_minimum > pol->points[nb].X)
1190 x_minimum = pol->points[nb].X;
1197 if (!overlays[selected_overlay].config.can_jut_out)
1199 pol->points[id_minimim].X = x;
1204 int y = pos.
Y + int(ev->y / zoom);
1209 if (!overlays[selected_overlay].config.can_jut_out)
1218 if (y > rec->rect.GetTop())
1220 if (!overlays[selected_overlay].config.can_jut_out)
1222 rec->rect.SetBottom(y);
1229 if (!overlays[selected_overlay].config.can_jut_out)
1238 int y_minimum = pol->points[0].Y;
1239 int y_maximum = pol->points[0].Y;
1240 size_t id_maximum = 0;
1241 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
1243 if (y_minimum > pol->points[nb].Y)
1244 y_minimum = pol->points[nb].Y;
1245 if (y_maximum < pol->points[nb].Y)
1247 y_maximum = pol->points[nb].Y;
1254 if (!overlays[selected_overlay].config.can_jut_out)
1256 pol->points[id_maximum].Y = y;
1265 int x = pos.
X + int(ev->x / zoom);
1267 std::unique_ptr<OverlayItem> &item(overlays[selected_overlay].items[selected_overlay_item]);
1269 Line* li =
dynamic_cast<Line*
>(item.get());
1274 if (!overlays[selected_overlay].config.can_jut_out)
1281 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
1284 if (x > rec->rect.GetLeft())
1286 if (!overlays[selected_overlay].config.can_jut_out)
1288 rec->rect.SetRight(x);
1293 Point* po =
dynamic_cast<Point*
>(item.get());
1296 if (!overlays[selected_overlay].config.can_jut_out)
1303 Polygon* pol =
dynamic_cast<Polygon*
>(item.get());
1306 int x_minimum = pol->points[0].X;
1307 int x_maximum = pol->points[0].X;
1308 size_t id_maximum = 0;
1309 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
1311 if(x_minimum > pol->points[nb].X)
1312 x_minimum = pol->points[nb].X;
1313 if(x_maximum < pol->points[nb].X)
1315 x_maximum = pol->points[nb].X;
1322 if (!overlays[selected_overlay].config.can_jut_out)
1324 pol->points[id_maximum].X = x;
1329 int y = pos.
Y + int(ev->y / zoom);
1334 if (!overlays[selected_overlay].config.can_jut_out)
1343 if (y > rec->rect.GetTop())
1345 if (!overlays[selected_overlay].config.can_jut_out)
1347 rec->rect.SetBottom(y);
1354 if (!overlays[selected_overlay].config.can_jut_out)
1363 int y_minimum = pol->points[0].Y;
1364 int y_maximum = pol->points[0].Y;
1365 size_t id_maximum = 0;
1366 for (
size_t nb = 0; nb < pol->points.size(); ++nb)
1368 if (y_minimum > pol->points[nb].Y)
1369 y_minimum = pol->points[nb].Y;
1370 if (y_maximum < pol->points[nb].Y)
1372 y_maximum = pol->points[nb].Y;
1379 if (!overlays[selected_overlay].config.can_jut_out)
1381 pol->points[id_maximum].Y = y;
1390 int x = int(ev->x / zoom) + pos.
X;
1391 int y = int(ev->y / zoom) + pos.
Y;
1392 user_mouse.emit(x, y);
1403 bool Image::button_clicked(GdkEventButton *ev)
1408 if (ev->type == GDK_BUTTON_PRESS)
1416 int x = int(ev->x / zoom) + pos.
X;
1417 int y = int(ev->y / zoom) + pos.
Y;
1421 user_mouse.emit(x, y);
1424 MouseMode mode = find_selection_at(ev->x, ev->y, selected_overlay, selected_overlay_item);
1425 click_ref.
X = ev->x;
1426 click_ref.
Y = ev->y;
1434 switch (selection_type)
1467 click_ref.
X = ev->x;
1468 click_ref.
Y = ev->y;
1474 const auto realx = int(ev->x / zoom) + pos.
X;
1475 const auto realy = int(ev->y / zoom) + pos.
Y;
1476 const auto selection_margin_zoom = int(selection_margin / zoom);
1478 std::vector<std::pair<crn::String, crn::String> > res;
1479 for (std::map<crn::String, Overlay_internal>::const_iterator lit = overlays.begin(); lit != overlays.end(); ++lit)
1481 if (!lit->second.config.show)
1483 for (
const auto &overlay : lit->second.items)
1485 const std::unique_ptr<OverlayItem>& item(overlay.second);
1486 Line* li =
dynamic_cast<Line*
>(item.get());
1489 crn::Rect r(li->p1.X - selection_margin_zoom, li->p1.Y - selection_margin_zoom, li->p2.X + selection_margin_zoom, li->p2.Y + selection_margin_zoom);
1490 if (r.Contains(realx, realy))
1492 double s = (li->p1.Y - li->p2.Y) * (realx - li->p1.X) + (li->p2.X - li->p1.X) * (realy - li->p1.Y);
1493 s /= sqrt(
double(
crn::Sqr(li->p1.X - li->p2.X) +
crn::Sqr(li->p1.Y - li->p2.Y)));
1494 if (
crn::Abs(s) < selection_margin_zoom)
1495 res.push_back(std::make_pair(lit->first, overlay.first));
1499 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
1504 res.push_back(std::make_pair(lit->first, overlay.first));
1506 Point* p =
dynamic_cast<Point*
>(item.get());
1510 crn::Rect r(p->point.X - selection_margin_zoom, p->point.Y - selection_margin_zoom, p->point.X + selection_margin_zoom, p->point.Y + selection_margin_zoom);
1512 res.push_back(std::make_pair(lit->first, overlay.first));
1515 Polygon* poly =
dynamic_cast<Polygon*
>(item.get());
1516 if ((poly !=
nullptr) && !poly->points.empty())
1518 int max_x = poly->points[0].X;
1519 int min_x = poly->points[0].X;
1520 int max_y = poly->points[0].Y;
1521 int min_y = poly->points[0].Y;
1522 for (
size_t i = 1; i< poly->points.size(); ++i)
1524 int x1 = poly->points[i].X;
1525 int y1 = poly->points[i].Y;
1535 crn::Rect rec(min_x - selection_margin_zoom, min_y - selection_margin_zoom, max_x + selection_margin_zoom, max_y + selection_margin_zoom);
1537 if (rec.Contains(realx, realy))
1538 res.push_back(std::make_pair(lit->first, overlay.first));
1543 rmb_clicked.emit(ev->button, ev->time, res, realx, realy);
1548 else if (ev->type == GDK_BUTTON_RELEASE)
1559 if ((ev->type == GDK_BUTTON_RELEASE) && (ev->button == 2))
1565 if ((ev->type == GDK_BUTTON_RELEASE) && (ev->button == 1))
1571 if ((ev->type == GDK_BUTTON_RELEASE) && (ev->button == 1))
1573 overlay_changed.emit(selected_overlay, selected_overlay_item, mouse_mode);
1578 set_cursor_from_mode(mouse_mode);
1586 bool Image::mouse_wheel(GdkEventScroll *ev)
1588 switch (ev->direction)
1591 if (ev->state & GDK_CONTROL_MASK)
1597 pos.
Y -= int(vscrollbar.get_adjustment()->get_page_increment());
1598 if (pos.
Y < 0) pos.
Y = 0;
1599 vscrollbar.set_value(pos.
Y);
1602 case GDK_SCROLL_DOWN:
1603 if (ev->state & GDK_CONTROL_MASK)
1609 pos.
Y += int(vscrollbar.get_adjustment()->get_page_increment());
1610 if (pos.
Y + disph / zoom > image_bounds.
GetHeight())
1612 vscrollbar.set_value(pos.
Y);
1615 case GDK_SCROLL_LEFT:
1616 pos.
X -= int(hscrollbar.get_adjustment()->get_page_increment());
1617 if (pos.
X < 0) pos.
X = 0;
1618 hscrollbar.set_value(pos.
X);
1620 case GDK_SCROLL_RIGHT:
1621 pos.
X += int(hscrollbar.get_adjustment()->get_page_increment());
1622 if (pos.
X + dispw / zoom > image_bounds.
GetWidth())
1624 hscrollbar.set_value(pos.
X);
1640 int x = int(pos.
X * zoom + mouse_x);
1641 int y = int(pos.
Y * zoom + mouse_y);
1643 for (std::map<crn::String, Overlay_internal>::const_iterator lit = overlays.begin(); lit != overlays.end(); ++lit)
1645 if (!lit->second.config.show)
1648 for (
const auto &overlay : lit->second.items)
1650 const std::unique_ptr<OverlayItem>& item(overlay.second);
1651 Rectangle* rec =
dynamic_cast<Rectangle*
>(item.get());
1654 if (!rec->rect.IsValid())
1656 int x1 = int(rec->rect.GetLeft() * zoom);
1657 int y1 = int(rec->rect.GetTop() * zoom);
1658 int x2 = int(rec->rect.GetRight() * zoom);
1659 int y2 = int(rec->rect.GetBottom() * zoom);
1660 crn::Rect r(x1 - selection_margin, y1 - selection_margin, x2 + selection_margin, y2 + selection_margin);
1663 overlay_id = lit->first;
1664 overlay_item_id = overlay.first;
1665 if (lit->second.config.editable)
1668 r =
crn::Rect(
crn::Max(x1, x2 - selection_margin),
crn::Max(y1, y2 - selection_margin), x2 + selection_margin, y2 + selection_margin);
1672 r =
crn::Rect(x1 - selection_margin, y1 - selection_margin,
crn::Min(x2, x1 + selection_margin),
crn::Min(y2, y1 + selection_margin));
1676 r =
crn::Rect(x1 - selection_margin,
crn::Max(y1, y2 - selection_margin),
crn::Min(x2, x1 + selection_margin), y2 + selection_margin);
1680 r =
crn::Rect(
crn::Max(x1, x2 - selection_margin), y1 - selection_margin, x2 + selection_margin,
crn::Min(y2, y1 + selection_margin));
1684 r =
crn::Rect(
crn::Max(x1, x2 - selection_margin), y1, x2 + selection_margin, y2);
1688 r =
crn::Rect(x1,
crn::Max(y1, y2 - selection_margin), x2, y2 + selection_margin);
1692 r =
crn::Rect(x1 - selection_margin, y1,
crn::Min(x2, x1 + selection_margin), y2);
1696 r =
crn::Rect(x1, y1 - selection_margin, x2,
crn::Min(y2, y1 + selection_margin));
1700 if (lit->second.config.moveable)
1707 Point* p=
dynamic_cast<Point*
>(item.get());
1710 int x1 = int(p->point.X * zoom);
1711 int y1 = int(p->point.Y * zoom);
1712 crn::Rect r(x1 - selection_margin, y1 - selection_margin, x1 + selection_margin, y1 + selection_margin);
1715 overlay_id = lit->first;
1716 overlay_item_id = overlay.first;
1717 movePoint = &(p->point);
1718 if (lit->second.config.moveable)
1725 Text* t=
dynamic_cast<Text*
>(item.get());
1728 int x1 = int(t->pos.X * zoom);
1729 int y1 = int(t->pos.Y * zoom);
1730 crn::Rect r(x1 - selection_margin, y1 - selection_margin, x1 + selection_margin, y1 + selection_margin);
1733 overlay_id = lit->first;
1734 overlay_item_id = overlay.first;
1735 movePoint = &(t->pos);
1736 if (lit->second.config.moveable)
1743 Line* li =
dynamic_cast<Line*
>(item.get());
1746 int x1 = int(li->p1.X * zoom);
1747 int y1 = int(li->p1.Y * zoom);
1748 int x2 = int(li->p2.X * zoom);
1749 int y2 = int(li->p2.Y * zoom);
1753 if (lit->second.config.editable)
1756 r =
crn::Rect (x1 - selection_margin, y1 - selection_margin, x1 + selection_margin, y1 + selection_margin);
1759 movePoint=&(li->p1);
1760 overlay_id = lit->first;
1761 overlay_item_id = overlay.first;
1765 r =
crn::Rect (x2 - selection_margin, y2 - selection_margin, x2 + selection_margin, y2 + selection_margin);
1768 movePoint=&(li->p2);
1769 overlay_id = lit->first;
1770 overlay_item_id = overlay.first;
1775 double s = (y1 - y2) * (x - x1) + (x2 - x1) * (y - y1);
1777 if (
crn::Abs(s) < selection_margin)
1779 overlay_id = lit->first;
1780 overlay_item_id = overlay.first;
1781 if (lit->second.config.moveable)
1789 Polygon* poly =
dynamic_cast<Polygon*
>(item.get());
1792 if (lit->second.config.editable)
1794 for (
size_t j = 0; j < poly->points.size(); ++j)
1796 int x1 = int(poly->points[j].X * zoom);
1797 int y1 = int(poly->points[j].Y * zoom);
1799 crn::Rect r(x1 - selection_margin, y1 - selection_margin, x1 + selection_margin, y1 + selection_margin);
1802 movePoint=&(poly->points[j]);
1803 overlay_id = lit->first;
1804 overlay_item_id = overlay.first;
1809 if (lit->second.config.moveable)
1810 for (
size_t i = 0; i < poly->points.size(); ++i)
1812 int x1 = int(poly->points[i].X * zoom);
1813 int y1 = int(poly->points[i].Y * zoom);
1816 if(i == poly->points.size()-1)
1818 if( !lit->second.config.closed_polygons)
1822 x2 = int(poly->points[0].X * zoom);
1823 y2 = int(poly->points[0].Y * zoom);
1828 x2 = int(poly->points[i+1].X * zoom);
1829 y2 = int(poly->points[i+1].Y * zoom);
1834 double s = (y1 - y2) * (x - x1) + (x2 - x1) * (y - y1);
1836 if (
crn::Abs(s) < selection_margin)
1838 overlay_id = lit->first;
1839 overlay_item_id = overlay.first;
1861 #ifdef CRN_USING_GTKMM3
1865 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), scroll_cursor));
1868 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), select_cursor));
1871 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), move_cursor));
1874 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), move_1_cursor));
1877 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_left_cursor));
1880 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_bottom_left_cursor));
1883 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_bottom_cursor));
1886 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_bottom_right_cursor));
1889 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_right_cursor));
1892 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_top_right_cursor));
1895 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_top_cursor));
1898 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), drag_top_left_cursor));
1901 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), user_cursor));
1906 da.get_window()->set_cursor(Gdk::Cursor::create(get_display(), user_cursor));
1908 da.get_window()->set_cursor();
1914 da.get_window()->set_cursor(scroll_cursor);
1917 da.get_window()->set_cursor(select_cursor);
1920 da.get_window()->set_cursor(move_cursor);
1923 da.get_window()->set_cursor(move_1_cursor);
1926 da.get_window()->set_cursor(drag_left_cursor);
1929 da.get_window()->set_cursor(drag_bottom_left_cursor);
1932 da.get_window()->set_cursor(drag_bottom_cursor);
1935 da.get_window()->set_cursor(drag_bottom_right_cursor);
1938 da.get_window()->set_cursor(drag_right_cursor);
1941 da.get_window()->set_cursor(drag_top_right_cursor);
1944 da.get_window()->set_cursor(drag_top_cursor);
1947 da.get_window()->set_cursor(drag_top_left_cursor);
1950 da.get_window()->set_cursor(user_cursor);
1955 da.get_window()->set_cursor(user_cursor);
1957 da.get_window()->set_cursor();
1967 text_color(
"black"),
1978 absolute_text_size(
true),
1979 font_family(
"sans"),
1980 closed_polygons(
false),
1994 selection_type = typ;
2009 overlay_changed.emit(selected_overlay, selected_overlay_item, mouse_mode);
2025 overlays[overlay_id].items[item_id].reset(
new Rectangle(r, label));
2027 movePoint =
nullptr;
2038 overlays[overlay_id].items[item_id].reset(
new Point(point,label));
2040 movePoint =
nullptr;
2052 overlays[overlay_id].items[item_id].reset(
new Line(p1,p2,label));
2054 movePoint =
nullptr;
2064 overlays[overlay_id].items[item_id].reset(
new Text(position,label));
2066 movePoint =
nullptr;
2082 overlays[overlay_id].items[item_id].reset(
new Polygon(p,label));
2084 movePoint =
nullptr;
2100 overlays[overlay_id].items[item_id].reset(
new Polygon(std::move(p),label));
2102 movePoint =
nullptr;
2114 std::map<crn::String, Overlay_internal>::iterator lit(overlays.find(overlay_id));
2115 if (lit == overlays.end())
2117 std::map<crn::String, std::unique_ptr<OverlayItem>>::iterator it(lit->second.items.find(item_id));
2118 if (it == lit->second.items.end())
2132 std::map<crn::String, Overlay_internal>::const_iterator lit(overlays.find(overlay_id));
2133 if (lit == overlays.end())
2135 std::map<crn::String, std::unique_ptr<OverlayItem>>
::const_iterator it(lit->second.items.find(item_id));
2136 if (it == lit->second.items.end())
2149 std::map<crn::String, Overlay_internal>::iterator lit(overlays.find(overlay_id));
2150 if (lit == overlays.end())
2152 std::map<crn::String, std::unique_ptr<OverlayItem>>::iterator it(lit->second.items.find(item_id));
2153 if (it == lit->second.items.end())
2155 lit->second.items.erase(it);
2157 if (selected_overlay == overlay_id)
2159 if (selected_overlay_item == item_id)
2160 selected_overlay_item =
"";
2163 movePoint =
nullptr;
2169 for (std::map<crn::String, Overlay_internal>::iterator it = overlays.begin(); it != overlays.end(); ++it)
2172 movePoint =
nullptr;
2180 overlays[id].items.clear();
2182 if (selected_overlay ==
id)
2184 selected_overlay_item =
"";
2194 std::map<crn::String, Overlay_internal>::const_iterator it(overlays.find(
selection_overlay()));
2195 if (it != overlays.end())
2196 return !it->second.items.empty();
2220 std::map<crn::String, Overlay_internal>::const_iterator lit(overlays.find(
selection_overlay()));
2221 if (lit == overlays.end())
2224 if (it == lit->second.items.end())
2226 const std::unique_ptr<OverlayItem>& item(it->second);
2242 std::map<crn::String, Overlay_internal>::const_iterator lit(overlays.find(
selection_overlay()));
2243 if (lit == overlays.end())
2246 if (it == lit->second.items.end())
2248 const std::unique_ptr<OverlayItem>& item(it->second);
2264 std::map<crn::String, Overlay_internal>::const_iterator lit(overlays.find(
selection_overlay()));
2265 if (lit == overlays.end())
2268 if (it == lit->second.items.end())
2270 const std::unique_ptr<OverlayItem>& item(it->second);
2272 Line* li=
dynamic_cast<Line*
>(item.get());
2274 return std::make_pair(li->
p1, li->
p2);
2304 Point * po =
dynamic_cast<Point*
>(item.get());
2322 Line * li =
dynamic_cast<Line*
>(item.get());
2340 overlays[id].config.show = visible;
2348 bool Image::refresh()
2353 Glib::RefPtr<Gdk::Window> win = da.get_window();
2357 if (need_recompute && dispw && disph)
2362 hscrollbar.get_adjustment()->set_page_size(dispw / zoom);
2363 vscrollbar.get_adjustment()->set_page_size(disph / zoom);
2364 pos.
X = int(hscrollbar.get_value());
2365 pos.
Y = int(vscrollbar.get_value());
2366 if (pos.
X + dispw / zoom > image_bounds.
GetWidth())
2368 hscrollbar.set_value(
crn::Max(0.0, image_bounds.
GetWidth() - dispw / zoom));
2369 pos.
X = int(hscrollbar.get_value());
2371 if (pos.
Y + disph / zoom > image_bounds.
GetHeight())
2374 pos.
Y = int(vscrollbar.get_value());
2378 int srcw =
crn::Min(
int(dispw / zoom), image->get_width() - pos.
X);
2379 int srch =
crn::Min(
int(disph / zoom), image->get_height() - pos.
Y);
2380 Glib::RefPtr<Gdk::Pixbuf> crop = Gdk::Pixbuf::create_subpixbuf(image, pos.
X, pos.
Y, srcw, srch);
2383 buffer = crop->scale_simple(
int(crop->get_width() * zoom),
int(crop->get_height() * zoom), Gdk::INTERP_BILINEAR);
2385 drawing.emit(buffer);
2387 #ifndef CRN_USING_GTKMM3
2389 hruler.set_range(pos.
X, pos.
X +
int(dispw / zoom), pos.
X, pos.
X +
int(dispw / zoom));
2390 vruler.set_range(pos.
Y, pos.
Y +
int(disph / zoom), pos.
Y, pos.
Y +
int(disph / zoom));
2393 da_gc = Gdk::GC::create(win);
2394 da_gc->set_rgb_fg_color(Gdk::Color(
"white"));
2397 need_recompute =
false;
2404 #ifndef CRN_USING_GTKMM3
2405 Glib::RefPtr<Gdk::Pixmap> pm = Gdk::Pixmap::create(win, dispw, disph);
2406 pm->draw_rectangle(da_gc,
true, 0, 0, dispw, disph);
2407 pm->draw_pixbuf(da_gc, buffer, 0, 0, 0, 0, buffer->get_width(), buffer->get_height(), Gdk::RGB_DITHER_NONE, 0, 0);
2411 #ifdef CRN_USING_GTKMM3
2413 auto cc = win->create_cairo_context();
2414 cc->set_source_rgb(1, 1, 1);
2416 Gdk::Cairo::set_source_pixbuf(cc, buffer);
2419 Cairo::RefPtr<Cairo::Context> cc = pm->create_cairo_context();
2422 std::cerr <<
"cannot create cairo context to refresh image" << std::endl;
2427 if (!screen.IsValid())
2430 for (std::map<crn::String, Overlay_internal>::reverse_iterator lit = overlays.rbegin(); lit != overlays.rend(); ++lit)
2432 if (!lit->second.config.show)
2434 double fontsize = lit->second.config.text_size * (lit->second.config.absolute_text_size ? 1.0 : zoom);
2435 Pango::FontDescription fdesc;
2436 fdesc.set_family(lit->second.config.font_family);
2437 fdesc.set_absolute_size(fontsize * Pango::SCALE);
2438 for (std::map<
crn::String, std::unique_ptr<OverlayItem>>::
const_iterator it = lit->second.items.begin(); it != lit->second.items.end(); ++it)
2440 const std::unique_ptr<OverlayItem>& item(it->second);
2441 const Point* p =
dynamic_cast<const Point*
>(item.get());
2444 int x = int((p->point.X - pos.
X) * zoom);
2445 int y = int((p->point.Y - pos.
Y) * zoom);
2446 if (!screen.Contains(x, y))
2448 cc->set_source_rgb(lit->second.config.color2.get_red_p(), lit->second.config.color2.get_green_p(), lit->second.config.color2.get_blue_p());
2449 cc->rectangle(x - 1, y - 1, 2, 2);
2451 cc->set_source_rgb(lit->second.config.color1.get_red_p(), lit->second.config.color1.get_green_p(), lit->second.config.color1.get_blue_p());
2452 cc->move_to(x - lit->second.config.cross_size / 2, y);
2453 cc->line_to(x + lit->second.config.cross_size / 2, y);
2454 cc->move_to(x, y - lit->second.config.cross_size / 2);
2455 cc->line_to(x, y + lit->second.config.cross_size / 2);
2457 if (lit->second.config.show_labels && it->second->label.IsNotEmpty())
2459 Glib::RefPtr<Pango::Layout> pl(Pango::Layout::create(cc));
2460 pl->set_font_description(fdesc);
2461 pl->set_text(p->label.Std());
2463 cc->set_source_rgb(lit->second.config.text_color.get_red_p(), lit->second.config.text_color.get_green_p(), lit->second.config.text_color.get_blue_p());
2464 pl->show_in_cairo_context(cc);
2468 Rectangle* rec=
dynamic_cast<Rectangle*
> (item.get());
2476 if (!(screen & z).IsValid())
2478 cc->rectangle(z.GetLeft(), z.GetTop(), z.GetWidth(), z.GetHeight());
2479 cc->set_source_rgb(lit->second.config.color1.get_red_p(), lit->second.config.color1.get_green_p(), lit->second.config.color1.get_blue_p());
2480 if (lit->second.config.fill)
2482 cc->stroke_preserve();
2483 cc->set_source_rgba(lit->second.config.color2.get_red_p(), lit->second.config.color2.get_green_p(), lit->second.config.color2.get_blue_p(), lit->second.config.fill_alpha);
2490 cc->rectangle(z.GetLeft(), z.GetTop(), z.GetWidth(), z.GetHeight());
2491 cc->set_source_rgb(lit->second.config.color2.get_red_p(), lit->second.config.color2.get_green_p(), lit->second.config.color2.get_blue_p());
2494 if (lit->second.config.show_labels && it->second->label.IsNotEmpty())
2496 Glib::RefPtr<Pango::Layout> pl(Pango::Layout::create(cc));
2497 pl->set_font_description(fdesc);
2498 pl->set_text(it->second->label.Std());
2502 pl->get_pixel_size(w, h);
2503 auto posy = z.GetTop();
2504 if (h > z.GetHeight())
2505 posy = z.GetBottom() - h;
2506 cc->move_to(z.GetLeft(), posy);
2508 cc->set_source_rgb(lit->second.config.text_color.get_red_p(), lit->second.config.text_color.get_green_p(), lit->second.config.text_color.get_blue_p());
2509 pl->show_in_cairo_context(cc);
2513 Line* li=
dynamic_cast<Line*
> (item.get());
2516 int x1 = int((li->p1.X - pos.
X) * zoom);
2517 int y1 = int((li->p1.Y - pos.
Y) * zoom);
2518 int x2 = int((li->p2.X - pos.
X) * zoom);
2519 int y2 = int((li->p2.Y - pos.
Y) * zoom);
2522 cc->set_source_rgb(lit->second.config.color2.get_red_p(), lit->second.config.color2.get_green_p(), lit->second.config.color2.get_blue_p());
2523 cc->rectangle(x1 - 1, y1 - 1, 2, 2);
2524 cc->rectangle(x2 - 1, y2 - 1, 2, 2);
2526 cc->set_source_rgb(lit->second.config.color1.get_red_p(), lit->second.config.color1.get_green_p(), lit->second.config.color1.get_blue_p());
2527 cc->move_to(x1, y1);
2528 cc->line_to(x2, y2);
2531 double l = sqrt(
double(w * w + h * h));
2532 if (lit->second.config.draw_arrows)
2534 double l2 = l - lit->second.config.arrow_size;
2535 int w2 = int(w * l2 / l);
2536 int h2 = int(h * l2 / l);
2539 cc->move_to(x1 + w2 - dy / 2, y1 + h2 + dx /2);
2540 cc->line_to(x2, y2);
2541 cc->move_to(x1 + w2 + dy / 2, y1 + h2 - dx /2);
2542 cc->line_to(x2, y2);
2545 if (lit->second.config.show_labels && it->second->label.IsNotEmpty())
2547 Glib::RefPtr<Pango::Layout> pl(Pango::Layout::create(cc));
2548 pl->set_font_description(fdesc);
2550 pl->set_text(it->second->label.Std());
2551 pl->set_alignment(Pango::ALIGN_CENTER);
2552 pl->set_width(
int(l));
2553 if ((a.value > 90) && (a.value < 270))
2557 cc->move_to(x1 + w / 2, y1 + h / 2);
2558 cc->rotate_degrees(a.value);
2559 cc->set_source_rgb(lit->second.config.text_color.get_red_p(), lit->second.config.text_color.get_green_p(), lit->second.config.text_color.get_blue_p());
2560 pl->show_in_cairo_context(cc);
2561 cc->rotate_degrees(-a.value);
2565 Text* te =
dynamic_cast<Text*
> (item.get());
2568 Glib::RefPtr<Pango::Layout> pl(Pango::Layout::create(cc));
2569 pl->set_font_description(fdesc);
2570 pl->set_text(it->second->label.Std());
2571 int x = int((te->pos.X - pos.
X) * zoom);
2572 int y = int((te->pos.Y - pos.
Y) * zoom);
2573 if (!screen.Contains(x, y))
2576 cc->set_source_rgb(lit->second.config.text_color.get_red_p(), lit->second.config.text_color.get_green_p(), lit->second.config.text_color.get_blue_p());
2577 pl->show_in_cairo_context(cc);
2580 Polygon * po =
dynamic_cast<Polygon*
> (item.get());
2583 double x_centre = po->points[0].X;
2584 double y_centre = po->points[0].Y;
2585 int x_big = po->points[0].X;
2586 int x_small = po->points[0].X;
2587 int y_big = po->points[0].Y;
2588 int y_small = po->points[0].Y;
2591 for (
size_t i = 1; i < po->points.size(); ++ i)
2593 x_centre += po->points[i].X;
2594 y_centre += po->points[i].Y;
2596 if(po->points[i].X > x_big)
2597 x_big = po->points[i].X;
2598 if(po->points[i].X < x_small)
2599 x_small = po->points[i].X;
2601 if(po->points[i].Y > y_big)
2602 y_big = po->points[i].Y;
2603 if(po->points[i].Y < y_small)
2604 y_small = po->points[i].Y;
2607 if (!(screen &
crn::Rect(
int((x_small- pos.
X) * zoom),
int((y_small- pos.
Y) * zoom),
int((x_big- pos.
X) * zoom),
int((y_big- pos.
Y) * zoom))).IsValid())
2610 cc->set_source_rgb(lit->second.config.color1.get_red_p(), lit->second.config.color1.get_green_p(), lit->second.config.color1.get_blue_p());
2611 cc->move_to(
int(po->points[0].X - pos.
X) * zoom,
int( po->points[0].Y - pos.
Y) * zoom);
2613 for (
size_t i = 1; i < po->points.size(); ++ i)
2615 int x1 = int((po->points[i].X - pos.
X) * zoom);
2616 int y1 = int((po->points[i].Y - pos.
Y) * zoom);
2617 cc->line_to(x1, y1);
2621 if(lit->second.config.closed_polygons)
2623 cc->line_to(
int((po->points[0].X - pos.
X) * zoom),
int(( po->points[0].Y - pos.
Y) * zoom));
2625 if (lit->second.config.closed_polygons && lit->second.config.fill)
2627 cc->stroke_preserve();
2628 cc->set_source_rgba(lit->second.config.color2.get_red_p(), lit->second.config.color2.get_green_p(), lit->second.config.color2.get_blue_p(), lit->second.config.fill_alpha);
2635 for (
size_t i = 0; i < po->points.size(); ++ i)
2637 int x1 = int((po->points[i].X - pos.
X) * zoom);
2638 int y1 = int((po->points[i].Y - pos.
Y) * zoom);
2639 cc->set_source_rgb(lit->second.config.color2.get_red_p(), lit->second.config.color2.get_green_p(), lit->second.config.color2.get_blue_p());
2640 cc->rectangle(x1 - 1, y1 - 1, 2, 2);
2643 if (lit->second.config.show_labels && it->second->label.IsNotEmpty())
2645 int h = int((y_big - y_small) * zoom);
2646 int w = int ((x_big - x_small)* zoom);
2648 double l = sqrt(
double(w * w + h * h));
2650 Glib::RefPtr<Pango::Layout> pl(Pango::Layout::create(cc));
2651 pl->set_font_description(fdesc);
2652 pl->set_text(it->second->label.Std());
2654 pl->set_alignment(Pango::ALIGN_CENTER);
2655 pl->set_width(
int(l));
2657 cc->move_to((x_centre/
int(po->points.size()))*zoom, (y_centre/int(po->points.size()))*zoom);
2658 cc->set_source_rgb(lit->second.config.text_color.get_red_p(), lit->second.config.text_color.get_green_p(), lit->second.config.text_color.get_blue_p());
2659 pl->show_in_cairo_context(cc);
2667 #ifndef CRN_USING_GTKMM3
2668 win->draw_drawable(da_gc, pm, 0, 0, 0, 0);
2672 need_redraw =
false;
void clear_overlays()
Clears all overlays.
OverlayConfig()
Default constructor.
void set_overlay_visible(const crn::String &id, bool visible)
Shows or hides an overlay.
void set_user_cursor(const Gdk::Cursor &cur)
Sets the cursor in user mouse mode.
const T & Cap(const T &v, const T &min, const T &max)
Bounds a value to an interval.
void zoom_in()
Increments the zoom level by 10%.
const T & Max(const T &a, const T &b)
Returns the max of two values.
int GetBottom() const
Returns the bottommost coordinate.
const crn::Rect & get_selection_as_rect() const
Gets the mouse selection as a rectangle.
int GetTop() const
Returns the topmost coordinate.
int GetLeft() const
Returns the leftmost coordinate.
A convenience class for angles units.
void zoom_out()
Decrements the zoom level by 10%.
A UTF32 character string class.
const crn::Point2DInt & get_selection_as_point() const
Gets the mouse selection as a point.
void zoom_100()
Sets the zoom level to 100%.
void set_selection_type(Overlay typ)
Sets the mouse selection type.
void clear_overlay(const crn::String &id)
Clears an overlay.
std::pair< crn::Point2DInt, crn::Point2DInt > get_selection_as_line() const
Gets the mouse selection as a line.
bool Contains(int x, int y) const noexcept
Checks if the rectangle contains a point.
constexpr SumType< T > Sqr(const T &v) noexcept(noexcept(v *v))
Returns the square of a value.
bool has_selection() const
Is there a mouse selection?
bool IsValid() const noexcept
Returns whether the rect is valid.
virtual ~Image() override
Destructor.
void focus_on(int x, int y)
Focus the image on a point.
void add_overlay_item(const crn::String &overlay_id, const crn::String &item_id, const crn::Rect &r, const crn::StringUTF8 &label="")
Adds a rectangle to an overlay.
void Translate(int x, int y)
Translates the rectangle.
int GetHeight() const
Returns the height of the rectangle.
void Abs(Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr) noexcept
Replaces each pixel by its absolute value.
const T & Min(const T &a, const T &b)
Returns the min of two values.
void set_rulers_visible(bool is_visible)
Are the rulers visible?
static const crn::String & selection_overlay()
Returns the name of the mouse selection overlay.
void set_zoom(double z)
Sets the zoom level.
int GetWidth() const
Returns the width of the rectangle.
MouseMode
State of the mouse activity.
void set_pixbuf(Glib::RefPtr< Gdk::Pixbuf > pb)
Sets the new image to display.
void clear_selection()
Clears the mouse selection.
A character string class.
void zoom_fit()
Sets the zoom level to fit the image's size.
OverlayItem & get_overlay_item(const crn::String &overlay_id, const crn::String &item_id)
Gets an overlay item.
int GetRight() const
Returns the rightmost coordinate.
void remove_overlay_item(const crn::String &overlay_id, const crn::String &item_id)
Removes an overlay item.
Invalid argument error (e.g.: nullptr pointer)
Overlay
Overlay types and mouse selection modes.
An item was not found in a container.
void set_selection(const crn::Rect &r)
Sets the mouse selection.