Commit 5d88a2e4 authored by Davis King's avatar Davis King

merged

parents 2c1332b3 61d16f22
...@@ -2189,7 +2189,7 @@ namespace dlib ...@@ -2189,7 +2189,7 @@ namespace dlib
virtual ~zoomable_region ( virtual ~zoomable_region (
)= 0; )= 0;
void set_pos ( virtual void set_pos (
long x, long x,
long y long y
); );
...@@ -2231,7 +2231,7 @@ namespace dlib ...@@ -2231,7 +2231,7 @@ namespace dlib
double max_zoom_scale ( double max_zoom_scale (
) const; ) const;
void set_size ( virtual void set_size (
unsigned long width, unsigned long width,
unsigned long height unsigned long height
); );
...@@ -2436,7 +2436,7 @@ namespace dlib ...@@ -2436,7 +2436,7 @@ namespace dlib
long order long order
); );
void set_size ( virtual void set_size (
unsigned long width, unsigned long width,
unsigned long height unsigned long height
); );
...@@ -2483,7 +2483,7 @@ namespace dlib ...@@ -2483,7 +2483,7 @@ namespace dlib
long pos long pos
); );
void set_pos ( virtual void set_pos (
long x, long x,
long y long y
); );
......
...@@ -1843,7 +1843,7 @@ namespace dlib ...@@ -1843,7 +1843,7 @@ namespace dlib
(i.e. this is the number that determines how far in the user is allowed to zoom) (i.e. this is the number that determines how far in the user is allowed to zoom)
!*/ !*/
void set_size ( virtual void set_size (
unsigned long width, unsigned long width,
unsigned long height unsigned long height
); );
...@@ -2039,7 +2039,7 @@ namespace dlib ...@@ -2039,7 +2039,7 @@ namespace dlib
style style
!*/ !*/
void set_size ( virtual void set_size (
unsigned long width, unsigned long width,
unsigned long height unsigned long height
); );
......
...@@ -5658,6 +5658,25 @@ namespace dlib ...@@ -5658,6 +5658,25 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
namespace impl
{
class image_display_functor
{
const std::string str;
const member_function_pointer<const std::string&>::kernel_1a mfp;
public:
image_display_functor (
const std::string& str_,
const member_function_pointer<const std::string&>::kernel_1a& mfp_
) : str(str_),
mfp(mfp_)
{}
void operator() (
) const { mfp(str); }
};
}
image_display:: image_display::
image_display( image_display(
drawable_window& w drawable_window& w
...@@ -5668,7 +5687,9 @@ namespace dlib ...@@ -5668,7 +5687,9 @@ namespace dlib
drawing_rect(true), drawing_rect(true),
rect_is_selected(false), rect_is_selected(false),
selected_rect(0), selected_rect(0),
default_rect_color(255,0,0,255) default_rect_color(255,0,0,255),
parts_menu(w),
part_width(15) // width part circles are drawn on the screen
{ {
enable_mouse_drag(); enable_mouse_drag();
...@@ -5677,9 +5698,42 @@ namespace dlib ...@@ -5677,9 +5698,42 @@ namespace dlib
set_horizontal_mouse_wheel_scroll_increment(30); set_horizontal_mouse_wheel_scroll_increment(30);
set_vertical_mouse_wheel_scroll_increment(30); set_vertical_mouse_wheel_scroll_increment(30);
parts_menu.disable();
enable_events(); enable_events();
} }
// ----------------------------------------------------------------------------------------
void image_display::
on_part_add (
const std::string& part_name
)
{
if (!rect_is_selected)
return;
const rectangle valid_area = get_rect_on_screen(selected_rect);
const point loc = nearest_point(valid_area,last_right_click_pos);
// Transform loc from gui window space into the space used by the overlay
// rectangles (i.e. relative to the raw image)
const point origin(total_rect().tl_corner());
point c1 = loc - origin;
if (zoom_in_scale != 1)
{
c1 = c1/(double)zoom_in_scale;
}
else if (zoom_out_scale != 1)
{
c1 = c1*(double)zoom_out_scale;
}
overlay_rects[selected_rect].parts[part_name] = c1;
parent.invalidate_rectangle(rect);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
image_display:: image_display::
...@@ -5787,6 +5841,41 @@ namespace dlib ...@@ -5787,6 +5841,41 @@ namespace dlib
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
} }
// ----------------------------------------------------------------------------------------
rectangle image_display::
get_rect_on_screen (
rectangle orect
) const
{
const point origin(total_rect().tl_corner());
orect.left() = orect.left()*zoom_in_scale/zoom_out_scale;
orect.top() = orect.top()*zoom_in_scale/zoom_out_scale;
if (zoom_in_scale != 1)
{
// make it so the box surrounds the pixels when we zoom in.
orect.right() = (orect.right()+1)*zoom_in_scale/zoom_out_scale;
orect.bottom() = (orect.bottom()+1)*zoom_in_scale/zoom_out_scale;
}
else
{
orect.right() = orect.right()*zoom_in_scale/zoom_out_scale;
orect.bottom() = orect.bottom()*zoom_in_scale/zoom_out_scale;
}
return translate_rect(orect, origin);
}
// ----------------------------------------------------------------------------------------
rectangle image_display::
get_rect_on_screen (
unsigned long idx
) const
{
return get_rect_on_screen(overlay_rects[idx].rect);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void image_display:: void image_display::
...@@ -5816,35 +5905,39 @@ namespace dlib ...@@ -5816,35 +5905,39 @@ namespace dlib
// now draw all the overlay rectangles // now draw all the overlay rectangles
for (unsigned long i = 0; i < overlay_rects.size(); ++i) for (unsigned long i = 0; i < overlay_rects.size(); ++i)
{ {
rectangle orect = overlay_rects[i].rect; const rectangle orect = get_rect_on_screen(i);
orect.left() = orect.left()*zoom_in_scale/zoom_out_scale;
orect.top() = orect.top()*zoom_in_scale/zoom_out_scale;
if (zoom_in_scale != 1)
{
// make it so the box surrounds the pixels when we zoom in.
orect.right() = (orect.right()+1)*zoom_in_scale/zoom_out_scale;
orect.bottom() = (orect.bottom()+1)*zoom_in_scale/zoom_out_scale;
}
else
{
orect.right() = orect.right()*zoom_in_scale/zoom_out_scale;
orect.bottom() = orect.bottom()*zoom_in_scale/zoom_out_scale;
}
if (rect_is_selected && selected_rect == i) if (rect_is_selected && selected_rect == i)
draw_rectangle(c, translate_rect(orect, origin), invert_pixel(overlay_rects[i].color), area); draw_rectangle(c, orect, invert_pixel(overlay_rects[i].color), area);
else else
draw_rectangle(c, translate_rect(orect, origin), overlay_rects[i].color, area); draw_rectangle(c, orect, overlay_rects[i].color, area);
if (overlay_rects[i].label.size() != 0) if (overlay_rects[i].label.size() != 0)
{ {
// make a rectangle that is at the spot we want to draw our string // make a rectangle that is at the spot we want to draw our string
rectangle r(orect.br_corner(), rectangle r(orect.br_corner(),
orect.br_corner() + point(10000,10000)); orect.br_corner() + point(10000,10000));
r = translate_rect(r, origin);
mfont->draw_string(c, r, overlay_rects[i].label, overlay_rects[i].color, 0, mfont->draw_string(c, r, overlay_rects[i].label, overlay_rects[i].color, 0,
std::string::npos, area); std::string::npos, area);
} }
std::map<std::string,point>::const_iterator itr;
for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)
{
rectangle temp = get_rect_on_screen(centered_rect(itr->second,part_width,part_width));
if (rect_is_selected && selected_part_name.size() != 0 && selected_part_name == itr->first)
draw_circle(c, center(temp), temp.width()/2, invert_pixel(overlay_rects[i].color), area);
else
draw_circle(c, center(temp), temp.width()/2, overlay_rects[i].color, area);
// make a rectangle that is at the spot we want to draw our string
rectangle r((temp.br_corner() + temp.bl_corner())/2,
temp.br_corner() + point(10000,10000));
mfont->draw_string(c, r, itr->first, overlay_rects[i].color, 0,
std::string::npos, area);
}
} }
// now draw all the overlay lines // now draw all the overlay lines
...@@ -5875,7 +5968,11 @@ namespace dlib ...@@ -5875,7 +5968,11 @@ namespace dlib
(key == base_window::KEY_BACKSPACE || key == base_window::KEY_DELETE)) (key == base_window::KEY_BACKSPACE || key == base_window::KEY_DELETE))
{ {
rect_is_selected = false; rect_is_selected = false;
parts_menu.disable();
if (selected_part_name.size() == 0)
overlay_rects.erase(overlay_rects.begin() + selected_rect); overlay_rects.erase(overlay_rects.begin() + selected_rect);
else
overlay_rects[selected_rect].parts.erase(selected_part_name);
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
if (event_handler.is_set()) if (event_handler.is_set())
...@@ -5883,6 +5980,33 @@ namespace dlib ...@@ -5883,6 +5980,33 @@ namespace dlib
} }
} }
// ----------------------------------------------------------------------------------------
void image_display::
add_labelable_part_name (
const std::string& name
)
{
auto_mutex lock(m);
if (part_names.insert(name).second)
{
member_function_pointer<const std::string&>::kernel_1a mfp;
mfp.set(*this,&image_display::on_part_add);
parts_menu.menu().add_menu_item(menu_item_text("Add " + name,impl::image_display_functor(name,mfp)));
}
}
// ----------------------------------------------------------------------------------------
void image_display::
clear_labelable_part_names (
)
{
auto_mutex lock(m);
part_names.clear();
parts_menu.menu().clear();
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void image_display:: void image_display::
...@@ -5899,6 +6023,13 @@ namespace dlib ...@@ -5899,6 +6023,13 @@ namespace dlib
if (rect.contains(x,y) == false || hidden || !enabled) if (rect.contains(x,y) == false || hidden || !enabled)
return; return;
if (btn == base_window::RIGHT && rect_is_selected)
{
last_right_click_pos = point(x,y);
parts_menu.set_rect(get_rect_on_screen(selected_rect));
return;
}
if (!is_double_click && btn == base_window::LEFT && (state&base_window::SHIFT)) if (!is_double_click && btn == base_window::LEFT && (state&base_window::SHIFT))
{ {
drawing_rect = true; drawing_rect = true;
...@@ -5907,13 +6038,17 @@ namespace dlib ...@@ -5907,13 +6038,17 @@ namespace dlib
if (rect_is_selected) if (rect_is_selected)
{ {
rect_is_selected = false; rect_is_selected = false;
parts_menu.disable();
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
} }
} }
else if (drawing_rect) else if (drawing_rect)
{ {
if (rect_is_selected) if (rect_is_selected)
{
rect_is_selected = false; rect_is_selected = false;
parts_menu.disable();
}
drawing_rect = false; drawing_rect = false;
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
...@@ -5923,29 +6058,16 @@ namespace dlib ...@@ -5923,29 +6058,16 @@ namespace dlib
const point origin(total_rect().tl_corner()); const point origin(total_rect().tl_corner());
const bool rect_was_selected = rect_is_selected; const bool rect_was_selected = rect_is_selected;
rect_is_selected = false; rect_is_selected = false;
parts_menu.disable();
long best_dist = std::numeric_limits<long>::max(); long best_dist = std::numeric_limits<long>::max();
long best_idx = 0; long best_idx = 0;
std::string best_part;
// check if this click landed on any of the overlay rectangles // check if this click landed on any of the overlay rectangles
for (unsigned long i = 0; i < overlay_rects.size(); ++i) for (unsigned long i = 0; i < overlay_rects.size(); ++i)
{ {
rectangle orect = overlay_rects[i].rect; const rectangle orect = get_rect_on_screen(i);
orect.left() = orect.left()*zoom_in_scale/zoom_out_scale;
orect.top() = orect.top()*zoom_in_scale/zoom_out_scale;
if (zoom_in_scale != 1)
{
// make it so the box surrounds the pixels when we zoom in.
orect.right() = (orect.right()+1)*zoom_in_scale/zoom_out_scale;
orect.bottom() = (orect.bottom()+1)*zoom_in_scale/zoom_out_scale;
}
else
{
orect.right() = orect.right()*zoom_in_scale/zoom_out_scale;
orect.bottom() = orect.bottom()*zoom_in_scale/zoom_out_scale;
}
orect = translate_rect(orect, origin);
const long dist = distance_to_rect_edge(orect, point(x,y)); const long dist = distance_to_rect_edge(orect, point(x,y));
...@@ -5953,6 +6075,23 @@ namespace dlib ...@@ -5953,6 +6075,23 @@ namespace dlib
{ {
best_dist = dist; best_dist = dist;
best_idx = i; best_idx = i;
best_part.clear();
}
std::map<std::string,point>::const_iterator itr;
for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)
{
rectangle temp = get_rect_on_screen(centered_rect(itr->second,part_width,part_width));
point c = center(temp);
// distance from edge of part circle
const long dist = static_cast<long>(std::abs(length(c - point(x,y)) + 0.5 - temp.width()/2));
if (dist < best_dist)
{
best_idx = i;
best_dist = dist;
best_part = itr->first;
}
} }
} }
...@@ -5960,7 +6099,10 @@ namespace dlib ...@@ -5960,7 +6099,10 @@ namespace dlib
if (best_dist < 13) if (best_dist < 13)
{ {
rect_is_selected = true; rect_is_selected = true;
if (part_names.size() != 0)
parts_menu.enable();
selected_rect = best_idx; selected_rect = best_idx;
selected_part_name = best_part;
if (orect_selected_event_handler.is_set()) if (orect_selected_event_handler.is_set())
orect_selected_event_handler(overlay_rects[best_idx]); orect_selected_event_handler(overlay_rects[best_idx]);
} }
...@@ -5971,6 +6113,7 @@ namespace dlib ...@@ -5971,6 +6113,7 @@ namespace dlib
else if (rect_is_selected) else if (rect_is_selected)
{ {
rect_is_selected = false; rect_is_selected = false;
parts_menu.disable();
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
} }
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <cctype> #include <cctype>
#include <vector> #include <vector>
#include "../any.h" #include "../any.h"
#include <set>
#ifdef _MSC_VER #ifdef _MSC_VER
// This #pragma directive is also located in the algs.h file but for whatever // This #pragma directive is also located in the algs.h file but for whatever
...@@ -3218,6 +3219,17 @@ namespace dlib ...@@ -3218,6 +3219,17 @@ namespace dlib
- if (rect_is_selected) then - if (rect_is_selected) then
- selected_rect == the index in overlay_rects of the user selected - selected_rect == the index in overlay_rects of the user selected
rectangle. rectangle.
- last_right_click_pos == the last place we saw the user right click
the mouse.
- parts_menu.is_enabled() == true
- if (it is actually a part of this rect that is selected) then
- selected_part_name == the name of the part in overlay_rects[selected_rect].parts
that is selected.
- else
- selected_part_name.size() == 0
- else
- parts_menu.is_enabled() == false
- selected_part_name.size() == 0
!*/ !*/
public: public:
...@@ -3256,6 +3268,26 @@ namespace dlib ...@@ -3256,6 +3268,26 @@ namespace dlib
assign_image_scaled(img,new_img); assign_image_scaled(img,new_img);
} }
virtual void set_pos (
long x,
long y
)
{
auto_mutex lock(m);
scrollable_region::set_pos(x,y);
parts_menu.set_rect(rect);
}
virtual void set_size (
long width,
long height
)
{
auto_mutex lock(m);
scrollable_region::set_size(width,height);
parts_menu.set_rect(rect);
}
struct overlay_rect struct overlay_rect
{ {
overlay_rect() { assign_pixel(color, 0);} overlay_rect() { assign_pixel(color, 0);}
...@@ -3268,9 +3300,14 @@ namespace dlib ...@@ -3268,9 +3300,14 @@ namespace dlib
overlay_rect(const rectangle& r, pixel_type p, const std::string& l) overlay_rect(const rectangle& r, pixel_type p, const std::string& l)
: rect(r),label(l) { assign_pixel(color, p); } : rect(r),label(l) { assign_pixel(color, p); }
template <typename pixel_type>
overlay_rect(const rectangle& r, pixel_type p, const std::string& l, const std::map<std::string,point>& parts_)
: rect(r),label(l),parts(parts_) { assign_pixel(color, p); }
rectangle rect; rectangle rect;
rgb_alpha_pixel color; rgb_alpha_pixel color;
std::string label; std::string label;
std::map<std::string,point> parts;
}; };
struct overlay_line struct overlay_line
...@@ -3365,6 +3402,12 @@ namespace dlib ...@@ -3365,6 +3402,12 @@ namespace dlib
orect_selected_event_handler = event_handler_; orect_selected_event_handler = event_handler_;
} }
void add_labelable_part_name (
const std::string& name
);
void clear_labelable_part_names (
);
private: private:
...@@ -3407,6 +3450,18 @@ namespace dlib ...@@ -3407,6 +3450,18 @@ namespace dlib
unsigned long state unsigned long state
); );
void on_part_add (
const std::string& part_name
);
rectangle get_rect_on_screen (
unsigned long idx
) const;
rectangle get_rect_on_screen (
rectangle orect
) const;
rgb_alpha_pixel invert_pixel (const rgb_alpha_pixel& p) const rgb_alpha_pixel invert_pixel (const rgb_alpha_pixel& p) const
{ return rgb_alpha_pixel(255-p.red, 255-p.green, 255-p.blue, p.alpha); } { return rgb_alpha_pixel(255-p.red, 255-p.green, 255-p.blue, p.alpha); }
...@@ -3422,11 +3477,16 @@ namespace dlib ...@@ -3422,11 +3477,16 @@ namespace dlib
point rect_anchor; point rect_anchor;
rectangle rect_to_draw; rectangle rect_to_draw;
bool rect_is_selected; bool rect_is_selected;
std::string selected_part_name;
unsigned long selected_rect; unsigned long selected_rect;
rgb_alpha_pixel default_rect_color; rgb_alpha_pixel default_rect_color;
std::string default_rect_label; std::string default_rect_label;
any_function<void()> event_handler; any_function<void()> event_handler;
any_function<void(const overlay_rect& orect)> orect_selected_event_handler; any_function<void(const overlay_rect& orect)> orect_selected_event_handler;
popup_menu_region parts_menu;
point last_right_click_pos;
const int part_width;
std::set<std::string> part_names;
// restricted functions // restricted functions
image_display(image_display&); // copy constructor image_display(image_display&); // copy constructor
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "../gui_core.h" #include "../gui_core.h"
#include <string> #include <string>
#include <map>
#include "../interfaces/enumerable.h" #include "../interfaces/enumerable.h"
#include "style_abstract.h" #include "style_abstract.h"
...@@ -2321,6 +2322,7 @@ namespace dlib ...@@ -2321,6 +2322,7 @@ namespace dlib
- get_overlay_rects().size() == 0 - get_overlay_rects().size() == 0
- get_default_overlay_rect_label() == "" - get_default_overlay_rect_label() == ""
- get_default_overlay_rect_color() == rgb_alpha_pixel(255,0,0,255) (i.e. RED) - get_default_overlay_rect_color() == rgb_alpha_pixel(255,0,0,255) (i.e. RED)
- This object does not have any user labelable parts defined.
WHAT THIS OBJECT REPRESENTS WHAT THIS OBJECT REPRESENTS
This object represents an image inside a scrollable region. This object represents an image inside a scrollable region.
...@@ -2330,8 +2332,11 @@ namespace dlib ...@@ -2330,8 +2332,11 @@ namespace dlib
If you hold the Ctrl key you can zoom in and out using the mouse wheel. If you hold the Ctrl key you can zoom in and out using the mouse wheel.
You can also add new overlay rectangles by holding shift, left clicking, You can also add new overlay rectangles by holding shift, left clicking,
and dragging the mouse. Finally, you can delete an overlay rectangle and dragging the mouse. Additionally, you can delete an overlay rectangle
by double clicking on it and hitting delete or backspace. by double clicking on it and hitting delete or backspace. Finally, you
can also add part labels (if they have been defined by calling add_labelable_part_name())
by selecting an overlay rectangle with the mouse and then right clicking
on the part.
The image is drawn such that: The image is drawn such that:
...@@ -2383,11 +2388,16 @@ namespace dlib ...@@ -2383,11 +2388,16 @@ namespace dlib
image shown by this object. Each rectangle is represented by image shown by this object. Each rectangle is represented by
a rectangle object as well as a color and text label. The label a rectangle object as well as a color and text label. The label
is drawn below the lower right corner of the rectangle. is drawn below the lower right corner of the rectangle.
Moreover, the rectangle can have sub-parts. Each part is listed
in the parts member variable. This variable maps the name of the
part to its position.
!*/ !*/
rectangle rect; rectangle rect;
rgb_alpha_pixel color; rgb_alpha_pixel color;
std::string label; std::string label;
std::map<std::string,point> parts;
overlay_rect( overlay_rect(
); );
...@@ -2420,7 +2430,22 @@ namespace dlib ...@@ -2420,7 +2430,22 @@ namespace dlib
ensures ensures
- #rect == r - #rect == r
- performs assign_pixel(color, p) - performs assign_pixel(color, p)
- #label = l - #label == l
!*/
template <typename pixel_type>
overlay_rect(
const rectangle& r,
pixel_type p,
const std::string& l,
const std::map<std::string,point>& parts_
);
/*!
ensures
- #rect == r
- performs assign_pixel(color, p)
- #label == l
- #parts == parts_
!*/ !*/
}; };
...@@ -2545,6 +2570,30 @@ namespace dlib ...@@ -2545,6 +2570,30 @@ namespace dlib
(i.e. when the user holds shift and adds them with the mouse) (i.e. when the user holds shift and adds them with the mouse)
!*/ !*/
void add_labelable_part_name (
const std::string& name
);
/*!
ensures
- adds a user labelable part with the given name. If the name has
already been added then this function has no effect.
- These parts can be added by the user by selecting an overlay box
and then right clicking anywhere in it. A popup menu will appear
listing the parts. The user can then click a part name and it will
add it into the overlay_rect::parts variable and also show it on the
screen.
!*/
void clear_labelable_part_names (
);
/*!
ensures
- removes all use labelable parts. Calling this function undoes
all previous calls to add_labelable_part_name(). Therefore, the
user won't be able to label any parts after clear_labelable_part_names()
is called.
!*/
rectangle get_image_display_rect ( rectangle get_image_display_rect (
) const; ) const;
/*! /*!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment