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

merged

parents 2c1332b3 61d16f22
......@@ -2189,7 +2189,7 @@ namespace dlib
virtual ~zoomable_region (
)= 0;
void set_pos (
virtual void set_pos (
long x,
long y
);
......@@ -2231,7 +2231,7 @@ namespace dlib
double max_zoom_scale (
) const;
void set_size (
virtual void set_size (
unsigned long width,
unsigned long height
);
......@@ -2436,7 +2436,7 @@ namespace dlib
long order
);
void set_size (
virtual void set_size (
unsigned long width,
unsigned long height
);
......@@ -2483,7 +2483,7 @@ namespace dlib
long pos
);
void set_pos (
virtual void set_pos (
long x,
long y
);
......
......@@ -1843,7 +1843,7 @@ namespace dlib
(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 height
);
......@@ -2039,7 +2039,7 @@ namespace dlib
style
!*/
void set_size (
virtual void set_size (
unsigned long width,
unsigned long height
);
......
......@@ -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(
drawable_window& w
......@@ -5668,7 +5687,9 @@ namespace dlib
drawing_rect(true),
rect_is_selected(false),
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();
......@@ -5677,9 +5698,42 @@ namespace dlib
set_horizontal_mouse_wheel_scroll_increment(30);
set_vertical_mouse_wheel_scroll_increment(30);
parts_menu.disable();
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::
......@@ -5787,6 +5841,41 @@ namespace dlib
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::
......@@ -5816,35 +5905,39 @@ namespace dlib
// now draw all the overlay rectangles
for (unsigned long i = 0; i < overlay_rects.size(); ++i)
{
rectangle orect = overlay_rects[i].rect;
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;
}
const rectangle orect = get_rect_on_screen(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
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)
{
// make a rectangle that is at the spot we want to draw our string
rectangle r(orect.br_corner(),
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,
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
......@@ -5875,7 +5968,11 @@ namespace dlib
(key == base_window::KEY_BACKSPACE || key == base_window::KEY_DELETE))
{
rect_is_selected = false;
parts_menu.disable();
if (selected_part_name.size() == 0)
overlay_rects.erase(overlay_rects.begin() + selected_rect);
else
overlay_rects[selected_rect].parts.erase(selected_part_name);
parent.invalidate_rectangle(rect);
if (event_handler.is_set())
......@@ -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::
......@@ -5899,6 +6023,13 @@ namespace dlib
if (rect.contains(x,y) == false || hidden || !enabled)
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))
{
drawing_rect = true;
......@@ -5907,13 +6038,17 @@ namespace dlib
if (rect_is_selected)
{
rect_is_selected = false;
parts_menu.disable();
parent.invalidate_rectangle(rect);
}
}
else if (drawing_rect)
{
if (rect_is_selected)
{
rect_is_selected = false;
parts_menu.disable();
}
drawing_rect = false;
parent.invalidate_rectangle(rect);
......@@ -5923,29 +6058,16 @@ namespace dlib
const point origin(total_rect().tl_corner());
const bool rect_was_selected = rect_is_selected;
rect_is_selected = false;
parts_menu.disable();
long best_dist = std::numeric_limits<long>::max();
long best_idx = 0;
std::string best_part;
// check if this click landed on any of the overlay rectangles
for (unsigned long i = 0; i < overlay_rects.size(); ++i)
{
rectangle orect = overlay_rects[i].rect;
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 rectangle orect = get_rect_on_screen(i);
const long dist = distance_to_rect_edge(orect, point(x,y));
......@@ -5953,6 +6075,23 @@ namespace dlib
{
best_dist = dist;
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
if (best_dist < 13)
{
rect_is_selected = true;
if (part_names.size() != 0)
parts_menu.enable();
selected_rect = best_idx;
selected_part_name = best_part;
if (orect_selected_event_handler.is_set())
orect_selected_event_handler(overlay_rects[best_idx]);
}
......@@ -5971,6 +6113,7 @@ namespace dlib
else if (rect_is_selected)
{
rect_is_selected = false;
parts_menu.disable();
parent.invalidate_rectangle(rect);
}
}
......
......@@ -26,6 +26,7 @@
#include <cctype>
#include <vector>
#include "../any.h"
#include <set>
#ifdef _MSC_VER
// This #pragma directive is also located in the algs.h file but for whatever
......@@ -3218,6 +3219,17 @@ namespace dlib
- if (rect_is_selected) then
- selected_rect == the index in overlay_rects of the user selected
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:
......@@ -3256,6 +3268,26 @@ namespace dlib
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
{
overlay_rect() { assign_pixel(color, 0);}
......@@ -3268,9 +3300,14 @@ namespace dlib
overlay_rect(const rectangle& r, pixel_type p, const std::string& l)
: 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;
rgb_alpha_pixel color;
std::string label;
std::map<std::string,point> parts;
};
struct overlay_line
......@@ -3365,6 +3402,12 @@ namespace dlib
orect_selected_event_handler = event_handler_;
}
void add_labelable_part_name (
const std::string& name
);
void clear_labelable_part_names (
);
private:
......@@ -3407,6 +3450,18 @@ namespace dlib
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
{ return rgb_alpha_pixel(255-p.red, 255-p.green, 255-p.blue, p.alpha); }
......@@ -3422,11 +3477,16 @@ namespace dlib
point rect_anchor;
rectangle rect_to_draw;
bool rect_is_selected;
std::string selected_part_name;
unsigned long selected_rect;
rgb_alpha_pixel default_rect_color;
std::string default_rect_label;
any_function<void()> 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
image_display(image_display&); // copy constructor
......
......@@ -10,6 +10,7 @@
#include "../gui_core.h"
#include <string>
#include <map>
#include "../interfaces/enumerable.h"
#include "style_abstract.h"
......@@ -2321,6 +2322,7 @@ namespace dlib
- get_overlay_rects().size() == 0
- get_default_overlay_rect_label() == ""
- 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
This object represents an image inside a scrollable region.
......@@ -2330,8 +2332,11 @@ namespace dlib
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,
and dragging the mouse. Finally, you can delete an overlay rectangle
by double clicking on it and hitting delete or backspace.
and dragging the mouse. Additionally, you can delete an overlay rectangle
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:
......@@ -2383,11 +2388,16 @@ namespace dlib
image shown by this object. Each rectangle is represented by
a rectangle object as well as a color and text label. The label
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;
rgb_alpha_pixel color;
std::string label;
std::map<std::string,point> parts;
overlay_rect(
);
......@@ -2420,7 +2430,22 @@ namespace dlib
ensures
- #rect == r
- 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
(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 (
) 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