AshanGimhana's picture
Upload folder using huggingface_hub
9375c9a verified
// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_WIDGETs_
#define DLIB_WIDGETs_
#include <cctype>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include "../algs.h"
#include "widgets_abstract.h"
#include "drawable.h"
#include "../gui_core.h"
#include "fonts.h"
#include "../timer.h"
#include "base_widgets.h"
#include "../member_function_pointer.h"
#include "../array.h"
#include "../array2d.h"
#include "../sequence.h"
#include "../dir_nav.h"
#include "../queue.h"
#include "style.h"
#include "../string.h"
#include "../misc_api.h"
#include "../any.h"
#include "../image_processing/full_object_detection.h"
#include "../geometry/line.h"
#ifdef _MSC_VER
// This #pragma directive is also located in the algs.h file but for whatever
// reason visual studio 9 just ignores it when it is only there.
// this is to disable the "'this' : used in base member initializer list"
// warning you get from some of the GUI objects since all the objects
// require that their parent class be passed into their constructor.
// In this case though it is totally safe so it is ok to disable this warning.
#pragma warning(disable : 4355)
#endif
namespace dlib
{
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class label
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class label : public drawable
{
public:
label(
drawable_window& w
) :
drawable(w),
text_color_(0,0,0)
{
enable_events();
}
~label()
{ disable_events(); parent.invalidate_rectangle(rect); }
void set_text (
const std::string& text
);
void set_text (
const std::wstring& text
);
void set_text (
const dlib::ustring& text
);
const std::string text (
) const;
const std::wstring wtext (
) const;
const dlib::ustring utext (
) const;
void set_text_color (
const rgb_pixel color
);
const rgb_pixel text_color (
) const;
void set_main_font (
const std::shared_ptr<font>& f
);
private:
dlib::ustring text_;
rgb_pixel text_color_;
// restricted functions
label(label&); // copy constructor
label& operator=(label&); // assignment operator
protected:
void draw (
const canvas& c
) const;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class toggle_button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class toggle_button : public button_action
{
/*!
INITIAL VALUE
- checked == false
CONVENTION
- is_checked() == checked
!*/
public:
toggle_button(
drawable_window& w
) :
button_action(w),
btn_tooltip(w),
checked(false)
{
style.reset(new toggle_button_style_default());
enable_events();
}
~toggle_button() { disable_events(); parent.invalidate_rectangle(rect); }
void set_name (
const std::string& name
);
void set_name (
const std::wstring& name
);
void set_name (
const dlib::ustring& name
);
void set_size (
unsigned long width_,
unsigned long height_
);
void set_tooltip_text (
const std::string& text
);
void set_tooltip_text (
const std::wstring& text
);
void set_tooltip_text (
const ustring& text
);
const std::string tooltip_text (
) const;
const std::wstring tooltip_wtext (
) const;
const dlib::ustring tooltip_utext (
) const;
bool is_checked (
) const;
const std::string name (
) const;
const std::wstring wname (
) const;
const dlib::ustring uname (
) const;
void set_checked (
);
void set_unchecked (
);
void show (
);
void hide (
);
void enable (
);
void disable (
);
void set_main_font (
const std::shared_ptr<font>& f
);
void set_pos (
long x,
long y
);
template <
typename style_type
>
void set_style (
const style_type& style_
)
{
auto_mutex M(m);
style.reset(new style_type(style_));
rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top());
parent.invalidate_rectangle(rect);
}
template <
typename T
>
void set_click_handler (
T& object,
void (T::*event_handler_)()
)
{
auto_mutex M(m);
event_handler = make_mfp(object,event_handler_);
event_handler_self.clear();
}
void set_click_handler (
const any_function<void()>& event_handler_
)
{
auto_mutex M(m);
event_handler = event_handler_;
event_handler_self.clear();
}
template <
typename T
>
void set_click_handler (
T& object,
void (T::*event_handler_)(toggle_button&)
)
{
auto_mutex M(m);
event_handler_self = make_mfp(object,event_handler_);
event_handler.clear();
}
void set_sourced_click_handler (
const any_function<void(toggle_button&)>& event_handler_
)
{
auto_mutex M(m);
event_handler_self = event_handler_;
event_handler.clear();
}
private:
// restricted functions
toggle_button(toggle_button&); // copy constructor
toggle_button& operator=(toggle_button&); // assignment operator
dlib::ustring name_;
tooltip btn_tooltip;
bool checked;
any_function<void()> event_handler;
any_function<void(toggle_button&)> event_handler_self;
std::unique_ptr<toggle_button_style> style;
protected:
void draw (
const canvas& c
) const { style->draw_toggle_button(c,rect,enabled,*mfont,lastx,lasty,name_,is_depressed(),checked); }
void on_button_up (
bool mouse_over
);
void on_mouse_over (
){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); }
void on_mouse_not_over (
){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); }
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class text_field
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class text_field : public drawable
{
/*!
INITIAL VALUE
text_color_ == rgb_pixel(0,0,0)
bg_color_ == rgb_pixel(255,255,255)
cursor_pos == 0
text_width == 0
text_ == ""
has_focus == false
cursor_visible == false
recent_movement == false
highlight_start == 0
highlight_end == -1
shift_pos == -1
text_pos == 0
CONVENTION
- cursor_pos == the position of the cursor in the string text_. The
cursor appears before the letter text_[cursor_pos]
- cursor_x == the x coordinate of the cursor relative to the left side
of rect. i.e. the number of pixels that separate the cursor from the
left side of the text_field.
- has_focus == true if this text field has keyboard input focus
- cursor_visible == true if the cursor should be painted
- text_ == text()
- text_pos == the index of the first letter in text_ that appears in
this text field.
- text_width == the width of text_[text_pos] though text_[text.size()-1]
- if (has_focus && the user has recently moved the cursor) then
- recent_movement == true
- else
- recent_movement == false
- if (highlight_start <= highlight_end) then
- text[highlight_start] though text[highlight_end] should be
highlighted
- if (shift_pos != -1) then
- has_focus == true
- the shift key is being held down or the left mouse button is
being held down.
- shift_pos == the position of the cursor when the shift or mouse key
was first pressed.
- text_color() == text_color_
- background_color() == bg_color_
!*/
public:
text_field(
drawable_window& w
) :
drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE | STRING_PUT),
text_color_(0,0,0),
bg_color_(255,255,255),
text_width(0),
text_pos(0),
recent_movement(false),
has_focus(false),
cursor_visible(false),
cursor_pos(0),
highlight_start(0),
highlight_end(-1),
shift_pos(-1),
t(*this,&text_field::timer_action),
right_click_menu(w)
{
style.reset(new text_field_style_default());
rect.set_bottom(mfont->height()+ (style->get_padding(*mfont))*2);
rect.set_right((style->get_padding(*mfont))*2);
cursor_x = style->get_padding(*mfont);
right_click_menu.menu().add_menu_item(menu_item_text("Cut",*this,&text_field::on_cut,'t'));
right_click_menu.menu().add_menu_item(menu_item_text("Copy",*this,&text_field::on_copy,'C'));
right_click_menu.menu().add_menu_item(menu_item_text("Paste",*this,&text_field::on_paste,'P'));
right_click_menu.menu().add_menu_item(menu_item_text("Delete",*this,&text_field::on_delete_selected,'D'));
right_click_menu.menu().add_menu_item(menu_item_separator());
right_click_menu.menu().add_menu_item(menu_item_text("Select All",*this,&text_field::on_select_all,'A'));
right_click_menu.set_rect(get_text_rect());
enable_events();
t.set_delay_time(500);
}
~text_field (
)
{
disable_events();
parent.invalidate_rectangle(rect);
t.stop_and_wait();
}
template <
typename style_type
>
void set_style (
const style_type& style_
)
{
auto_mutex M(m);
style.reset(new style_type(style_));
// call this just so that this widget redraws itself with the new style
set_main_font(mfont);
}
void set_text (
const std::string& text_
);
void set_text (
const std::wstring& text_
);
void give_input_focus (
);
bool has_input_focus (
) const;
void select_all_text (
);
void set_text (
const dlib::ustring& text_
);
const std::string text (
) const;
const std::wstring wtext (
) const;
const dlib::ustring utext (
) const;
void set_text_color (
const rgb_pixel color
);
const rgb_pixel text_color (
) const;
void set_background_color (
const rgb_pixel color
);
const rgb_pixel background_color (
) const;
void set_width (
unsigned long width
);
void set_pos (
long x,
long y
);
void set_main_font (
const std::shared_ptr<font>& f
);
int next_free_user_event_number (
) const
{
return drawable::next_free_user_event_number()+1;
}
void disable (
);
void enable (
);
void hide (
);
void show (
);
template <
typename T
>
void set_text_modified_handler (
T& object,
void (T::*event_handler)()
)
{
auto_mutex M(m);
text_modified_handler = make_mfp(object,event_handler);
}
template <
typename T
>
void set_enter_key_handler (
T& object,
void (T::*event_handler)()
)
{
auto_mutex M(m);
enter_key_handler = make_mfp(object,event_handler);
}
void set_text_modified_handler (
const any_function<void()>& event_handler
)
{
auto_mutex M(m);
text_modified_handler = event_handler;
}
void set_enter_key_handler (
const any_function<void()>& event_handler
)
{
auto_mutex M(m);
enter_key_handler = event_handler;
}
template <
typename T
>
void set_focus_lost_handler (
T& object,
void (T::*event_handler)()
)
{
auto_mutex M(m);
focus_lost_handler = make_mfp(object,event_handler);
}
void set_focus_lost_handler (
const any_function<void()>& event_handler
)
{
auto_mutex M(m);
focus_lost_handler = event_handler;
}
private:
void on_cut (
);
void on_copy (
);
void on_paste (
);
void on_select_all (
);
void on_delete_selected (
);
void on_text_is_selected (
);
void on_no_text_selected (
);
void on_user_event (
int num
)
{
// ignore this user event if it isn't for us
if (num != drawable::next_free_user_event_number())
return;
if (recent_movement == false)
{
cursor_visible = !cursor_visible;
parent.invalidate_rectangle(rect);
}
else
{
if (cursor_visible == false)
{
cursor_visible = true;
parent.invalidate_rectangle(rect);
}
recent_movement = false;
}
}
void timer_action (
) { parent.trigger_user_event(this,drawable::next_free_user_event_number()); }
/*!
ensures
- flips the state of cursor_visible
!*/
void move_cursor (
unsigned long pos
);
/*!
requires
- pos <= text_.size()
ensures
- moves the cursor to the position given by pos and moves the text
in the text box if necessary
- if the position changes then the parent window will be updated
!*/
rectangle get_text_rect (
) const;
/*!
ensures
- returns the rectangle that should contain the text in this widget
!*/
dlib::ustring text_;
rgb_pixel text_color_;
rgb_pixel bg_color_;
unsigned long text_width;
unsigned long text_pos;
bool recent_movement;
bool has_focus;
bool cursor_visible;
long cursor_pos;
unsigned long cursor_x;
// this tells you what part of the text is highlighted
long highlight_start;
long highlight_end;
long shift_pos;
any_function<void()> text_modified_handler;
any_function<void()> enter_key_handler;
any_function<void()> focus_lost_handler;
std::unique_ptr<text_field_style> style;
timer<text_field> t;
popup_menu_region right_click_menu;
// restricted functions
text_field(text_field&); // copy constructor
text_field& operator=(text_field&); // assignment operator
protected:
void draw (
const canvas& c
) const;
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void on_mouse_up (
unsigned long btn,
unsigned long state,
long x,
long y
);
void on_mouse_move (
unsigned long state,
long x,
long y
);
void on_keydown (
unsigned long key,
bool is_printable,
unsigned long state
);
void on_string_put (
const std::wstring &str
);
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class text_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class text_box : public scrollable_region
{
/*!
INITIAL VALUE
text_color_ == rgb_pixel(0,0,0)
bg_color_ == rgb_pixel(255,255,255)
cursor_pos == 0
text_ == ""
has_focus == false
cursor_visible == false
recent_movement == false
highlight_start == 0
highlight_end == -1
shift_pos == -1
CONVENTION
- cursor_pos == the position of the cursor in the string text_. The
cursor appears before the letter text_[cursor_pos]
- cursor_rect == The rectangle that should be drawn for the cursor.
The position is relative to total_rect().
- has_focus == true if this text field has keyboard input focus
- cursor_visible == true if the cursor should be painted
- text_ == text()
- if (has_focus && the user has recently moved the cursor) then
- recent_movement == true
- else
- recent_movement == false
- if (highlight_start <= highlight_end) then
- text[highlight_start] though text[highlight_end] should be
highlighted
- if (shift_pos != -1) then
- has_focus == true
- the shift key is being held down or the left mouse button is
being held down.
- shift_pos == the position of the cursor when the shift or mouse key
was first pressed.
- text_color() == text_color_
- background_color() == bg_color_
!*/
public:
text_box(
drawable_window& w
) :
scrollable_region(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE | STRING_PUT),
text_color_(0,0,0),
bg_color_(255,255,255),
recent_movement(false),
has_focus(false),
cursor_visible(false),
cursor_pos(0),
highlight_start(0),
highlight_end(-1),
shift_pos(-1),
t(*this,&text_box::timer_action),
right_click_menu(w)
{
style.reset(new text_box_style_default());
const long padding = static_cast<long>(style->get_padding(*mfont));
cursor_rect = mfont->compute_cursor_rect(rectangle(padding,padding,1000000,1000000), text_, 0);
adjust_total_rect();
set_vertical_mouse_wheel_scroll_increment(mfont->height());
set_horizontal_mouse_wheel_scroll_increment(mfont->height());
right_click_menu.menu().add_menu_item(menu_item_text("Cut",*this,&text_box::on_cut,'t'));
right_click_menu.menu().add_menu_item(menu_item_text("Copy",*this,&text_box::on_copy,'C'));
right_click_menu.menu().add_menu_item(menu_item_text("Paste",*this,&text_box::on_paste,'P'));
right_click_menu.menu().add_menu_item(menu_item_text("Delete",*this,&text_box::on_delete_selected,'D'));
right_click_menu.menu().add_menu_item(menu_item_separator());
right_click_menu.menu().add_menu_item(menu_item_text("Select All",*this,&text_box::on_select_all,'A'));
right_click_menu.set_rect(get_text_rect());
set_size(100,100);
enable_events();
t.set_delay_time(500);
}
~text_box (
)
{
disable_events();
parent.invalidate_rectangle(rect);
t.stop_and_wait();
}
template <
typename style_type
>
void set_style (
const style_type& style_
)
{
auto_mutex M(m);
style.reset(new style_type(style_));
scrollable_region::set_style(style_.get_scrollable_region_style());
// call this just so that this widget redraws itself with the new style
set_main_font(mfont);
}
void set_text (
const std::string& text_
);
void set_text (
const std::wstring& text_
);
void set_text (
const dlib::ustring& text_
);
const std::string text (
) const;
const std::wstring wtext (
) const;
const dlib::ustring utext (
) const;
void set_text_color (
const rgb_pixel color
);
const rgb_pixel text_color (
) const;
void set_background_color (
const rgb_pixel color
);
const rgb_pixel background_color (
) const;
void set_size (
unsigned long width,
unsigned long height
);
void set_pos (
long x,
long y
);
void set_main_font (
const std::shared_ptr<font>& f
);
int next_free_user_event_number (
) const
{
return scrollable_region::next_free_user_event_number()+1;
}
void disable (
);
void enable (
);
void hide (
);
void show (
);
template <
typename T
>
void set_text_modified_handler (
T& object,
void (T::*event_handler)()
)
{
auto_mutex M(m);
text_modified_handler = make_mfp(object,event_handler);
}
void set_text_modified_handler (
const any_function<void()>& event_handler
)
{
auto_mutex M(m);
text_modified_handler = event_handler;
}
template <
typename T
>
void set_enter_key_handler (
T& object,
void (T::*event_handler)()
)
{
auto_mutex M(m);
enter_key_handler = make_mfp(object,event_handler);
}
void set_enter_key_handler (
const any_function<void()>& event_handler
)
{
auto_mutex M(m);
enter_key_handler = event_handler;
}
template <
typename T
>
void set_focus_lost_handler (
T& object,
void (T::*event_handler)()
)
{
auto_mutex M(m);
focus_lost_handler = make_mfp(object,event_handler);
}
void set_focus_lost_handler (
const any_function<void()>& event_handler
)
{
auto_mutex M(m);
focus_lost_handler = event_handler;
}
private:
void on_cut (
);
void on_copy (
);
void on_paste (
);
void on_select_all (
);
void on_delete_selected (
);
void on_text_is_selected (
);
void on_no_text_selected (
);
void on_user_event (
int num
)
{
// ignore this user event if it isn't for us
if (num != scrollable_region::next_free_user_event_number())
return;
if (recent_movement == false)
{
cursor_visible = !cursor_visible;
parent.invalidate_rectangle(rect);
}
else
{
if (cursor_visible == false)
{
cursor_visible = true;
parent.invalidate_rectangle(rect);
}
recent_movement = false;
}
}
// The reason for using user actions here rather than just having the timer just call
// what it needs directly is to avoid a potential deadlock during destruction of this widget.
void timer_action (
) { parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); }
/*!
ensures
- flips the state of cursor_visible
!*/
void move_cursor (
unsigned long pos
);
/*!
requires
- pos <= text_.size()
ensures
- moves the cursor to the position given by pos and moves the text
in the text box if necessary
- if the position changes then the parent window will be updated
!*/
rectangle get_text_rect (
) const;
/*!
ensures
- returns the rectangle that should contain the text in this widget
!*/
void adjust_total_rect (
);
/*!
ensures
- adjusts total_rect() so that it is big enough to contain the text
currently in this object.
!*/
dlib::ustring text_;
rgb_pixel text_color_;
rgb_pixel bg_color_;
bool recent_movement;
bool has_focus;
bool cursor_visible;
long cursor_pos;
rectangle cursor_rect;
// this tells you what part of the text is highlighted
long highlight_start;
long highlight_end;
long shift_pos;
any_function<void()> text_modified_handler;
any_function<void()> enter_key_handler;
any_function<void()> focus_lost_handler;
std::unique_ptr<text_box_style> style;
timer<text_box> t;
popup_menu_region right_click_menu;
// restricted functions
text_box(text_box&); // copy constructor
text_box& operator=(text_box&); // assignment operator
protected:
void draw (
const canvas& c
) const;
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void on_mouse_up (
unsigned long btn,
unsigned long state,
long x,
long y
);
void on_mouse_move (
unsigned long state,
long x,
long y
);
void on_keydown (
unsigned long key,
bool is_printable,
unsigned long state
);
void on_string_put (
const std::wstring &str
);
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class check_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class check_box : public toggle_button
{
public:
check_box(
drawable_window& w
) : toggle_button(w)
{
set_style(toggle_button_style_check_box());
}
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class radio_button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class radio_button : public toggle_button
{
public:
radio_button (
drawable_window& w
) : toggle_button(w)
{
set_style(toggle_button_style_radio_button());
}
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class tabbed_display
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class tabbed_display : public drawable
{
/*!
INITIAL VALUE
- tabs.size() == 0
- selected_tab_ == 0
CONVENTION
- number_of_tabs() == tabs.size()
- tab_name(idx) == tabs[idx]
- if (tabs.size() > 0) then
- selected_tab_ == the index of the tab that is currently selected
- for all valid i:
- tabs[i].width == mfont->compute_size(tabs[i].name)
- tabs[i].rect == the rectangle that defines where this tab is
- if (tabs[i].group != 0) then
- tabs[i].group == a pointer to the widget_group for this tab.
- left_pad == the amount of padding in a tab to the left of the name string.
- right_pad == the amount of padding in a tab to the right of the name string.
- top_pad == the amount of padding in a tab to the top of the name string.
- bottom_pad == the amount of padding in a tab to the bottom of the name string.
- if (event_handler.is_set()) then
- event_handler() is what is called to process click events
on this object.
!*/
public:
tabbed_display(
drawable_window& w
);
virtual ~tabbed_display(
);
void set_size (
unsigned long width,
unsigned long height
);
void set_number_of_tabs (
unsigned long num
);
unsigned long selected_tab (
) const;
unsigned long number_of_tabs (
) const;
const std::string tab_name (
unsigned long idx
) const;
const std::wstring tab_wname (
unsigned long idx
) const;
const dlib::ustring& tab_uname (
unsigned long idx
) const;
void set_tab_name (
unsigned long idx,
const std::string& new_name
);
void set_tab_name (
unsigned long idx,
const std::wstring& new_name
);
void set_tab_name (
unsigned long idx,
const dlib::ustring& new_name
);
void set_pos (
long x,
long y
);
template <
typename T
>
void set_click_handler (
T& object,
void (T::*eh)(unsigned long new_idx,unsigned long old_idx)
)
{
auto_mutex M(m);
event_handler = make_mfp(object,eh);
}
void set_click_handler (
const any_function<void(unsigned long,unsigned long)>& eh
)
{
auto_mutex M(m);
event_handler = eh;
}
void set_tab_group (
unsigned long idx,
widget_group& group
);
void show (
);
void hide (
);
void enable (
);
void disable (
);
void set_main_font (
const std::shared_ptr<font>& f
);
void fit_to_contents (
);
protected:
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void draw (
const canvas& c
) const;
private:
void recompute_tabs (
);
/*!
ensures
- recomputes the rectangles for all the tabs and makes this object
wider if needed
!*/
void draw_tab (
const rectangle& tab,
const canvas& c
) const;
/*!
ensures
- draws the outline of a tab as given by the rectangle onto c
!*/
struct tab_data
{
tab_data() : width(0), group(0) {}
dlib::ustring name;
unsigned long width;
rectangle rect;
widget_group* group;
};
unsigned long selected_tab_;
array<tab_data> tabs;
const long left_pad;
const long right_pad;
const long top_pad;
const long bottom_pad;
any_function<void(unsigned long,unsigned long)> event_handler;
// restricted functions
tabbed_display(tabbed_display&); // copy constructor
tabbed_display& operator=(tabbed_display&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class named_rectangle
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class named_rectangle : public drawable
{
/*!
INITIAL VALUE
name == ""
CONVENTION
name_ == name()
!*/
public:
named_rectangle(
drawable_window& w
);
virtual ~named_rectangle(
);
void set_size (
unsigned long width,
unsigned long height
);
void set_name (
const std::string& name
);
void set_name (
const std::wstring& name
);
void set_name (
const dlib::ustring& name
);
const std::string name (
) const;
const std::wstring wname (
) const;
const dlib::ustring uname (
) const;
void wrap_around (
const rectangle& rect
);
void set_main_font (
const std::shared_ptr<font>& f
);
protected:
void draw (
const canvas& c
) const;
private:
void make_name_fit_in_rect (
);
dlib::ustring name_;
unsigned long name_width;
unsigned long name_height;
// restricted functions
named_rectangle(named_rectangle&); // copy constructor
named_rectangle& operator=(named_rectangle&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class mouse_tracker
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class mouse_tracker : public draggable
{
public:
mouse_tracker(
drawable_window& w
);
~mouse_tracker(
);
void show (
);
void hide (
);
void enable (
);
void disable (
);
void set_pos (
long x,
long y
);
void set_main_font (
const std::shared_ptr<font>& f
);
protected:
void on_mouse_move (
unsigned long state,
long x,
long y
);
void on_drag (
);
void draw (
const canvas& c
) const;
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
private:
const long offset;
named_rectangle nr;
label x_label;
label y_label;
std::ostringstream sout;
long click_x, click_y;
// restricted functions
mouse_tracker(mouse_tracker&); // copy constructor
mouse_tracker& operator=(mouse_tracker&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// function message_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
namespace message_box_helper
{
class box_win : public drawable_window
{
void initialize (
);
public:
box_win (
const std::string& title_,
const std::string& message_
);
box_win (
const std::wstring& title_,
const std::wstring& message_
);
box_win (
const dlib::ustring& title_,
const dlib::ustring& message_
);
~box_win (
);
void set_click_handler (
const any_function<void()>& event_handler_
)
{
auto_mutex M(wm);
event_handler = event_handler_;
}
private:
static void deleter_thread (
void* param
);
void on_click (
);
on_close_return_code on_window_close (
);
const std::wstring title;
const std::wstring message;
label msg;
button btn_ok;
any_function<void()> event_handler;
};
class blocking_box_win : public drawable_window
{
void initialize (
);
public:
blocking_box_win (
const std::string& title_,
const std::string& message_
);
blocking_box_win (
const std::wstring& title_,
const std::wstring& message_
);
blocking_box_win (
const dlib::ustring& title_,
const dlib::ustring& message_
);
~blocking_box_win (
);
private:
void on_click (
);
const std::wstring title;
const std::wstring message;
label msg;
button btn_ok;
};
}
template <
typename T
>
void message_box (
const std::string& title,
const std::string& message,
T& object,
void (T::*event_handler)()
)
{
using namespace message_box_helper;
box_win* win = new box_win(title,message);
win->set_click_handler(make_mfp(object,event_handler));
}
inline void message_box (
const std::string& title,
const std::string& message,
const any_function<void()>& event_handler
)
{
using namespace message_box_helper;
box_win* win = new box_win(title,message);
win->set_click_handler(event_handler);
}
inline void message_box (
const std::string& title,
const std::string& message
)
{
using namespace message_box_helper;
new box_win(title,message);
}
inline void message_box_blocking (
const std::string& title,
const std::string& message
)
{
using namespace message_box_helper;
blocking_box_win w(title,message);
w.wait_until_closed();
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class list_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
namespace list_box_helper{
template <typename S = std::string>
class list_box : public scrollable_region,
public enumerable<const S>
{
/*!
INITIAL VALUE
- ms_enabled == false
- items.size() == 0
- last_selected = 0
CONVENTION
- size() == items.size()
- (*this)[i] == items[i].name
- is_selected(i) == items[i].is_selected
- ms_enabled == multiple_select_enabled()
- items[i].width == the width of items[i].name as given by font::compute_size()
- items[i].height == the height of items[i].name as given by font::compute_size()
- last_selected == the last item the user selected
!*/
public:
list_box(
drawable_window& w
);
~list_box(
);
bool is_selected (
unsigned long index
) const;
void select (
unsigned long index
);
void unselect (
unsigned long index
);
template <
typename style_type
>
void set_style (
const style_type& style_
)
{
auto_mutex M(m);
style.reset(new style_type(style_));
scrollable_region::set_style(style_.get_scrollable_region_style());
parent.invalidate_rectangle(rect);
}
template <typename T>
void get_selected (
T& list
) const
{
auto_mutex M(m);
list.clear();
for (unsigned long i = 0; i < items.size(); ++i)
{
if (items[i].is_selected)
{
unsigned long idx = i;
list.enqueue(idx);
}
}
}
template <typename T>
void load (
const T& list
)
{
auto_mutex M(m);
items.clear();
unsigned long i = 0;
items.set_max_size(list.size());
items.set_size(list.size());
list.reset();
unsigned long max_width = 0;
unsigned long total_height = 0;
while (list.move_next())
{
items[i].is_selected = false;
items[i].name = list.element();
mfont->compute_size(items[i].name,items[i].width, items[i].height);
if (items[i].width > max_width)
max_width = items[i].width;
total_height += items[i].height;
++i;
}
set_total_rect_size(max_width, total_height);
parent.invalidate_rectangle(rect);
last_selected = 0;
}
const S& operator[] (
unsigned long index
) const;
bool multiple_select_enabled (
) const;
void enable_multiple_select (
);
void disable_multiple_select (
);
template <
typename T
>
void set_double_click_handler (
T& object,
void (T::*eh)(unsigned long index)
) { auto_mutex M(m); event_handler = make_mfp(object,eh); }
void set_double_click_handler (
const any_function<void(unsigned long)>& eh
) { auto_mutex M(m); event_handler = eh; }
template <
typename T
>
void set_click_handler (
T& object,
void (T::*eh)(unsigned long index)
) { auto_mutex M(m); single_click_event_handler = make_mfp(object,eh); }
void set_click_handler (
const any_function<void(unsigned long)>& eh
) { auto_mutex M(m); single_click_event_handler = eh; }
bool at_start (
) const;
void reset (
) const;
bool current_element_valid (
) const;
const S& element (
) const;
const S& element (
);
bool move_next (
) const;
size_t size (
) const;
unsigned long get_selected (
) const;
void set_main_font (
const std::shared_ptr<font>& f
);
private:
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void draw (
const canvas& c
) const;
template <typename SS>
struct data
{
SS name;
bool is_selected;
unsigned long width;
unsigned long height;
};
bool ms_enabled;
array<data<S> > items;
any_function<void(unsigned long)> event_handler;
any_function<void(unsigned long)> single_click_event_handler;
unsigned long last_selected;
std::unique_ptr<list_box_style> style;
// restricted functions
list_box(list_box&); // copy constructor
list_box& operator=(list_box&); // assignment operator
};
}
typedef list_box_helper::list_box<std::string> list_box;
typedef list_box_helper::list_box<std::wstring> wlist_box;
typedef list_box_helper::list_box<dlib::ustring> ulist_box;
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// function open_file_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
namespace open_file_box_helper
{
class box_win : public drawable_window
{
public:
box_win (
const std::string& title,
bool has_text_field = false
);
~box_win (
);
void set_click_handler (
const any_function<void(const std::string&)>& event_handler_
)
{
auto_mutex M(wm);
event_handler = event_handler_;
}
private:
void set_sizes(
);
void on_window_resized (
);
void deleter_thread (
);
void enter_folder (
const std::string& folder_name
);
void on_dirs_click (
unsigned long idx
);
void on_files_click (
unsigned long idx
);
void on_files_double_click (
unsigned long
);
void on_cancel_click (
);
void on_open_click (
);
void on_path_button_click (
toggle_button& btn
);
bool set_dir (
const std::string& dir
);
void on_root_click (
);
on_close_return_code on_window_close (
);
label lbl_dirs;
label lbl_files;
label lbl_file_name;
list_box lb_dirs;
list_box lb_files;
button btn_ok;
button btn_cancel;
toggle_button btn_root;
text_field tf_file_name;
std::string path;
std::string prefix;
int cur_dir;
any_function<void(const std::string&)> event_handler;
sequence<std::unique_ptr<toggle_button> >::kernel_2a_c sob;
};
}
template <
typename T
>
void open_file_box (
T& object,
void (T::*event_handler)(const std::string&)
)
{
using namespace open_file_box_helper;
box_win* win = new box_win("Open File",true);
win->set_click_handler(make_mfp(object,event_handler));
}
inline void open_file_box (
const any_function<void(const std::string&)>& event_handler
)
{
using namespace open_file_box_helper;
box_win* win = new box_win("Open File",true);
win->set_click_handler(event_handler);
}
template <
typename T
>
void open_existing_file_box (
T& object,
void (T::*event_handler)(const std::string&)
)
{
using namespace open_file_box_helper;
box_win* win = new box_win("Open File");
win->set_click_handler(make_mfp(object,event_handler));
}
inline void open_existing_file_box (
const any_function<void(const std::string&)>& event_handler
)
{
using namespace open_file_box_helper;
box_win* win = new box_win("Open File");
win->set_click_handler(event_handler);
}
template <
typename T
>
void save_file_box (
T& object,
void (T::*event_handler)(const std::string&)
)
{
using namespace open_file_box_helper;
box_win* win = new box_win("Save File",true);
win->set_click_handler(make_mfp(object,event_handler));
}
inline void save_file_box (
const any_function<void(const std::string&)>& event_handler
)
{
using namespace open_file_box_helper;
box_win* win = new box_win("Save File",true);
win->set_click_handler(event_handler);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class menu_bar
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class menu_bar : public drawable
{
/*!
INITIAL VALUE
- menus.size() == 0
- open_menu == 0
CONVENTION
- size() == menus.size()
- all menu data is stored in menus
- menus[x].name == the name of the xth menu
- if (menus[x].underline_pos != std::string::npos) then
- menus[x].underline_pos == the position of the character in the
menu name that should be underlined
- menus[x].underline_p1 != menus[x].underline_p2
and these two points define the underline bar
- else
- menus[x].underline_p1 == menus[x].underline_p2
- menus[x].menu == menu(x)
- menus[x].rect == the rectangle in which menus[x].name is drawn
- menus[x].bgrect == the rectangle for the xth menu button
- if (there is an open menu on the screen) then
- open_menu == the index of the open menu from menus
- else
- open_menu == menus.size()
!*/
public:
menu_bar(
drawable_window& w
);
~menu_bar();
// this function does nothing
void set_pos(long,long){}
void set_main_font (
const std::shared_ptr<font>& f
);
void set_number_of_menus (
unsigned long num
);
unsigned long number_of_menus (
) const;
void set_menu_name (
unsigned long idx,
const std::string name,
char underline_ch = '\0'
);
void set_menu_name (
unsigned long idx,
const std::wstring name,
char underline_ch = '\0'
);
void set_menu_name (
unsigned long idx,
const dlib::ustring name,
char underline_ch = '\0'
);
const std::string menu_name (
unsigned long idx
) const;
const std::wstring menu_wname (
unsigned long idx
) const;
const dlib::ustring menu_uname (
unsigned long idx
) const;
popup_menu& menu (
unsigned long idx
);
const popup_menu& menu (
unsigned long idx
) const;
protected:
void on_window_resized (
);
void draw (
const canvas& c
) const;
void on_window_moved (
);
void on_focus_lost (
);
void on_mouse_down (
unsigned long btn,
unsigned long ,
long x,
long y,
bool
);
void on_mouse_move (
unsigned long ,
long x,
long y
);
void on_keydown (
unsigned long key,
bool is_printable,
unsigned long state
);
private:
void show_menu (
unsigned long i
);
void hide_menu (
);
void on_popup_hide (
);
void compute_menu_geometry (
);
void adjust_position (
);
struct menu_data
{
menu_data():underline_pos(dlib::ustring::npos){}
dlib::ustring name;
dlib::ustring::size_type underline_pos;
popup_menu menu;
rectangle rect;
rectangle bgrect;
point underline_p1;
point underline_p2;
};
array<menu_data> menus;
unsigned long open_menu;
// restricted functions
menu_bar(menu_bar&); // copy constructor
menu_bar& operator=(menu_bar&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class directed_graph_drawer
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename graph_type>
class directed_graph_drawer : public zoomable_region
{
/*!
INITIAL VALUE
- edge_selected == false
- mouse_drag == false
- selected_node == 0
- graph_.number_of_nodes() == 0
- external_graph.number_of_nodes() == 0
- radius == 25
- last_mouse_click_in_display == false
CONVENTION
- radius == the radius of the nodes when they aren't zoomed
- external_graph and graph_ have the same graph structure
- external_graph == graph()
- external_graph.node(i) == graph_node(i)
- if (one of the nodes is selected) then
- selected_node < graph_.number_of_nodes()
- graph_.node(selected_node) == the selected node
- else
- selected_node == graph_.number_of_nodes()
- if (the user is dragging a node with the mouse) then
- mouse_drag == true
- drag_offset == the vector from the mouse position to the
center of the node
- else
- mouse_drag == false
- if (the user has selected an edge) then
- edge_selected == true
- the parent node is graph_.node(selected_edge_parent)
- the child node is graph_.node(selected_edge_parent)
- else
- edge_selected == false
- for all valid i:
- graph_.node(i).data.p == the center of the node in graph space
- graph_.node(i).data.name == node_label(i)
- graph_.node(i).data.color == node_color(i)
- graph_.node(i).data.str_rect == a rectangle sized to contain graph_.node(i).data.name
- if (the last mouse click in our parent window as in our display_rect_ ) then
- last_mouse_click_in_display == true
- else
- last_mouse_click_in_display == false
!*/
public:
directed_graph_drawer (
drawable_window& w
) :
zoomable_region(w,MOUSE_CLICK | MOUSE_WHEEL | KEYBOARD_EVENTS),
radius(25),
edge_selected(false),
last_mouse_click_in_display(false)
{
mouse_drag = false;
selected_node = 0;
// Whenever you make your own drawable (or inherit from draggable or button_action)
// you have to remember to call this function to enable the events. The idea
// here is that you can perform whatever setup you need to do to get your
// object into a valid state without needing to worry about event handlers
// triggering before you are ready.
enable_events();
}
~directed_graph_drawer (
)
{
// Disable all further events for this drawable object. We have to do this
// because we don't want draw() events coming to this object while or after
// it has been destructed.
disable_events();
// Tell the parent window to redraw its area that previously contained this
// drawable object.
parent.invalidate_rectangle(rect);
}
void clear_graph (
)
{
auto_mutex M(m);
graph_.clear();
external_graph.clear();
parent.invalidate_rectangle(display_rect());
}
const typename graph_type::node_type& graph_node (
unsigned long i
) const
{
DLIB_ASSERT ( i < number_of_nodes() ,
"\tgraph_type::node_type& directed_graph_drawer::graph_node(i)"
<< "\n\ti: " << i
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
return external_graph.node(i);
}
typename graph_type::node_type& graph_node (
unsigned long i
)
{
DLIB_ASSERT ( i < number_of_nodes() ,
"\tgraph_type::node_type& directed_graph_drawer::graph_node(i)"
<< "\n\ti: " << i
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
return external_graph.node(i);
}
const graph_type& graph (
) const
{
return external_graph;
}
void save_graph (
std::ostream& out
)
{
auto_mutex M(m);
serialize(external_graph, out);
serialize(graph_, out);
parent.invalidate_rectangle(display_rect());
}
void load_graph (
std::istream& in
)
{
auto_mutex M(m);
deserialize(external_graph, in);
deserialize(graph_, in);
parent.invalidate_rectangle(display_rect());
}
unsigned long number_of_nodes (
) const
{
auto_mutex M(m);
return graph_.number_of_nodes();
}
void set_node_label (
unsigned long i,
const std::string& label
)
{
set_node_label(i, convert_mbstring_to_wstring(label));
}
void set_node_label (
unsigned long i,
const std::wstring& label
)
{
set_node_label(i, convert_wstring_to_utf32(label));
}
void set_node_label (
unsigned long i,
const dlib::ustring& label
)
{
auto_mutex M(m);
DLIB_ASSERT ( i < number_of_nodes() ,
"\tvoid directed_graph_drawer::set_node_label(i,label)"
<< "\n\ti: " << i
<< "\n\tlabel: " << narrow(label)
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
graph_.node(i).data.name = label.c_str();
unsigned long width, height;
mfont->compute_size(label,width,height);
graph_.node(i).data.str_rect = rectangle(width,height);
parent.invalidate_rectangle(display_rect());
}
void set_node_color (
unsigned long i,
rgb_pixel color
)
{
auto_mutex M(m);
DLIB_ASSERT ( i < number_of_nodes() ,
"\tvoid directed_graph_drawer::set_node_color(i,label)"
<< "\n\ti: " << i
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
graph_.node(i).data.color = color;
parent.invalidate_rectangle(display_rect());
}
rgb_pixel node_color (
unsigned long i
) const
{
auto_mutex M(m);
DLIB_ASSERT ( i < number_of_nodes() ,
"\trgb_pixel directed_graph_drawer::node_color(i)"
<< "\n\ti: " << i
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
return graph_.node(i).data.color;
}
const std::string node_label (
unsigned long i
) const
{
auto_mutex M(m);
DLIB_ASSERT ( i < number_of_nodes() ,
"\tconst std::ustring directed_graph_drawer::node_label(i)"
<< "\n\ti: " << i
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
return narrow(graph_.node(i).data.name);
}
const std::wstring node_wlabel (
unsigned long i
) const
{
return convert_utf32_to_wstring(node_ulabel(i));
}
const dlib::ustring node_ulabel (
unsigned long i
) const
{
auto_mutex M(m);
DLIB_ASSERT ( i < number_of_nodes() ,
"\tconst std::ustring directed_graph_drawer::node_label(i)"
<< "\n\ti: " << i
<< "\n\tnumber_of_nodes(): " << number_of_nodes()
);
return graph_.node(i).data.name.c_str();
}
template <
typename T
>
void set_node_selected_handler (
T& object,
void (T::*event_handler_)(unsigned long)
)
{
auto_mutex M(m);
node_selected_handler = make_mfp(object,event_handler_);
}
void set_node_selected_handler (
const any_function<void(unsigned long)>& event_handler_
)
{
auto_mutex M(m);
node_selected_handler = event_handler_;
}
template <
typename T
>
void set_node_deselected_handler (
T& object,
void (T::*event_handler_)(unsigned long)
)
{
auto_mutex M(m);
node_deselected_handler = make_mfp(object,event_handler_);
}
void set_node_deselected_handler (
const any_function<void(unsigned long)>& event_handler_
)
{
auto_mutex M(m);
node_deselected_handler = event_handler_;
}
template <
typename T
>
void set_node_deleted_handler (
T& object,
void (T::*event_handler_)()
)
{
auto_mutex M(m);
node_deleted_handler = make_mfp(object,event_handler_);
}
void set_node_deleted_handler (
const any_function<void()>& event_handler_
)
{
auto_mutex M(m);
node_deleted_handler = event_handler_;
}
template <
typename T
>
void set_graph_modified_handler (
T& object,
void (T::*event_handler_)()
)
{
auto_mutex M(m);
graph_modified_handler = make_mfp(object,event_handler_);
}
void set_graph_modified_handler (
const any_function<void()>& event_handler_
)
{
auto_mutex M(m);
graph_modified_handler = event_handler_;
}
protected:
void on_keydown (
unsigned long key,
bool ,
unsigned long
)
{
// ignore all keyboard input if the last thing the user clicked on
// wasn't the display area
if (last_mouse_click_in_display == false)
return;
// if a node is selected
if (selected_node != graph_.number_of_nodes())
{
// deselect the node if the user hits escape
if (key == base_window::KEY_ESC)
{
parent.invalidate_rectangle(display_rect());
if (node_deselected_handler.is_set())
node_deselected_handler(selected_node);
selected_node = graph_.number_of_nodes();
}
// delete the node if the user hits delete
if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE)
{
parent.invalidate_rectangle(display_rect());
graph_.remove_node(selected_node);
external_graph.remove_node(selected_node);
selected_node = graph_.number_of_nodes();
mouse_drag = false;
if (graph_modified_handler.is_set())
graph_modified_handler();
if (node_deleted_handler.is_set())
node_deleted_handler();
}
}
// if an edge is selected
if (edge_selected)
{
// deselect the node if the user hits escape
if (key == base_window::KEY_ESC)
{
parent.invalidate_rectangle(display_rect());
edge_selected = false;
}
// delete the node if the user hits delete
if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE)
{
parent.invalidate_rectangle(display_rect());
graph_.remove_edge(selected_edge_parent, selected_edge_child);
external_graph.remove_edge(selected_edge_parent, selected_edge_child);
edge_selected = false;
if (graph_modified_handler.is_set())
graph_modified_handler();
}
}
}
void on_mouse_move (
unsigned long state,
long x,
long y
)
{
if (mouse_drag)
{
const point p(nearest_point(display_rect(),point(x,y)));
point center = drag_offset + p;
graph_.node(selected_node).data.p = gui_to_graph_space(center);
parent.invalidate_rectangle(display_rect());
}
else
{
zoomable_region::on_mouse_move(state,x,y);
}
// check if the mouse isn't being dragged anymore
if ((state & base_window::LEFT) == 0)
{
mouse_drag = false;
}
}
void on_mouse_up (
unsigned long btn,
unsigned long state,
long x,
long y
)
{
mouse_drag = false;
zoomable_region::on_mouse_up(btn,state,x,y);
}
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
)
{
bool redraw = false;
if (display_rect().contains(x,y) &&
(btn == base_window::RIGHT || btn == base_window::LEFT) &&
(state & base_window::SHIFT) == 0 )
{
// start out saying no edge is selected
if (edge_selected)
{
edge_selected = false;
redraw = true;
}
bool click_hit_node = false;
dlib::vector<double,2> p(gui_to_graph_space(point(x,y)));
// check if this click is on an existing node
for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
{
dlib::vector<double,2> n(graph_.node(i).data.p);
if ((p-n).length() < radius)
{
click_hit_node = true;
point center = graph_to_gui_space(graph_.node(i).data.p);
mouse_drag = true;
drag_offset = center - point(x,y);
// only do something if the click isn't on the currently
// selected node
if (selected_node != i)
{
// send out the deselected event if appropriate
if (selected_node != graph_.number_of_nodes() && node_deselected_handler.is_set())
node_deselected_handler(selected_node);
selected_node = i;
redraw = true;
if (node_selected_handler.is_set())
node_selected_handler(selected_node);
}
break;
}
}
// if the click didn't hit any node then make sure nothing is selected
if (click_hit_node == false && selected_node != graph_.number_of_nodes())
{
if (node_deselected_handler.is_set())
node_deselected_handler(selected_node);
selected_node = graph_.number_of_nodes();
redraw = true;
}
// check if this click is on an edge if we didn't click on a node
if (click_hit_node == false)
{
for (unsigned long n = 0; n < graph_.number_of_nodes() && edge_selected == false; ++n)
{
const dlib::vector<double,2> parent_center(graph_to_gui_space(graph_.node(n).data.p));
for (unsigned long e = 0; e < graph_.node(n).number_of_children() && edge_selected == false; ++e)
{
const dlib::vector<double,2> child_center(graph_to_gui_space(graph_.node(n).child(e).data.p));
rectangle area;
area += parent_center;
area += child_center;
// if the point(x,y) is between the two nodes then lets consider it further
if (area.contains(point(x,y)))
{
p = point(x,y);
const dlib::vector<double> z(0,0,1);
// find the distance from the line between the two nodes
const dlib::vector<double,2> perpendicular(z.cross(parent_center-child_center).normalize());
double distance = std::abs((child_center-p).dot(perpendicular));
if (distance < 8)
{
edge_selected = true;
selected_edge_parent = n;
selected_edge_child = graph_.node(n).child(e).index();
redraw = true;
}
}
}
}
}
// if the click didn't land on any node then add a new one if this was
// a right mouse button click
if (click_hit_node == false && btn == base_window::RIGHT)
{
const unsigned long n = graph_.add_node();
external_graph.add_node();
graph_.node(n).data.p = gui_to_graph_space(point(x,y));
redraw = true;
selected_node = n;
mouse_drag = false;
if (graph_modified_handler.is_set())
graph_modified_handler();
if (node_selected_handler.is_set())
node_selected_handler(selected_node);
}
else if (selected_node == graph_.number_of_nodes())
{
// in this case the click landed in the white area between nodes
zoomable_region::on_mouse_down( btn, state, x, y, is_double_click);
}
}
// If the user is shift clicking with the mouse then see if we
// should add a new edge.
if (display_rect().contains(x,y) &&
btn == base_window::LEFT &&
(state & base_window::SHIFT) &&
selected_node != graph_.number_of_nodes() )
{
dlib::vector<double,2> p(gui_to_graph_space(point(x,y)));
// check if this click is on an existing node
for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
{
dlib::vector<double,2> n(graph_.node(i).data.p);
if ((p-n).length() < radius)
{
// add the edge if it doesn't already exist and isn't an edge back to
// the same node
if (graph_.has_edge(selected_node,i) == false && selected_node != i &&
graph_.has_edge(i, selected_node) == false)
{
graph_.add_edge(selected_node,i);
external_graph.add_edge(selected_node,i);
redraw = true;
if (graph_modified_handler.is_set())
graph_modified_handler();
}
break;
}
}
}
if (redraw)
parent.invalidate_rectangle(display_rect());
if (display_rect().contains(x,y) == false)
last_mouse_click_in_display = false;
else
last_mouse_click_in_display = true;
}
void draw (
const canvas& c
) const
{
zoomable_region::draw(c);
rectangle area = c.intersect(display_rect());
if (area.is_empty() == true)
return;
if (enabled)
fill_rect(c,display_rect(),255);
else
fill_rect(c,display_rect(),128);
const unsigned long rad = static_cast<unsigned long>(radius*zoom_scale());
point center;
// first draw all the edges
for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
{
center = graph_to_gui_space(graph_.node(i).data.p);
const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8)));
// draw lines to all this node's parents
const dlib::vector<double> z(0,0,1);
for (unsigned long j = 0; j < graph_.node(i).number_of_parents(); ++j)
{
point p(graph_to_gui_space(graph_.node(i).parent(j).data.p));
rgb_pixel color(0,0,0);
// if this is the selected edge then draw it with red instead of black
if (edge_selected && selected_edge_child == i && selected_edge_parent == graph_.node(i).parent(j).index())
{
color.red = 255;
// we need to be careful when drawing this line to not draw it over the node dots since it
// has a different color from them and would look weird
dlib::vector<double,2> v(p-center);
v = v.normalize()*rad;
draw_line(c,center+v,p-v ,color, area);
}
else
{
draw_line(c,center,p ,color, area);
}
// draw the triangle pointing to this node
if (area.intersect(circle_area).is_empty() == false)
{
dlib::vector<double,2> v(p-center);
v = v.normalize();
dlib::vector<double,2> cross = z.cross(v).normalize();
dlib::vector<double,2> r(center + v*rad);
for (double i = 0; i < 8*zoom_scale(); i += 0.1)
draw_line(c,(r+v*i)+cross*i, (r+v*i)-cross*i,color,area);
}
}
}
// now draw all the node dots
for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
{
center = graph_to_gui_space(graph_.node(i).data.p);
const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8)));
// draw the actual dot for this node
if (area.intersect(circle_area).is_empty()==false)
{
rgb_alpha_pixel color;
assign_pixel(color, graph_.node(i).data.color);
// this node is in area so lets draw it and all of its edges as well
draw_solid_circle(c,center,rad-3,color,area);
color.alpha = 240;
draw_circle(c,center,rad-3,color,area);
color.alpha = 200;
draw_circle(c,center,rad-2.5,color,area);
color.alpha = 160;
draw_circle(c,center,rad-2.0,color,area);
color.alpha = 120;
draw_circle(c,center,rad-1.5,color,area);
color.alpha = 80;
draw_circle(c,center,rad-1.0,color,area);
color.alpha = 40;
draw_circle(c,center,rad-0.5,color,area);
}
if (i == selected_node)
draw_circle(c,center,rad+5,rgb_pixel(0,0,255),area);
}
// now draw all the strings last
for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
{
center = graph_to_gui_space(graph_.node(i).data.p);
rectangle circle_area(centered_rect(center,2*rad+3,2*rad+3));
if (area.intersect(circle_area).is_empty()==false)
{
rgb_pixel color = graph_.node(i).data.color;
// invert this color
color.red = 255-color.red;
color.green = 255-color.green;
color.blue = 255-color.blue;
sout << i;
unsigned long width, height;
mfont->compute_size(sout.str(),width,height);
rectangle str_rect(centered_rect(center, width,height));
if (circle_area.contains(str_rect))
{
mfont->draw_string(c,str_rect,sout.str(),color,0,std::string::npos,area);
// draw the label for this node if it isn't empty
if(graph_.node(i).data.name.size() > 0)
{
rectangle str_rect(graph_.node(i).data.str_rect);
str_rect = centered_rect(center.x(), center.y()-rad-mfont->height(), str_rect.width(), str_rect.height());
mfont->draw_string(c,str_rect,graph_.node(i).data.name,0,0,std::string::npos,area);
}
}
sout.str("");
}
}
}
private:
struct data
{
data() : color(0,0,0) {}
vector<double> p;
dlib::ustring name;
rectangle str_rect;
rgb_pixel color;
};
friend void serialize(const data& item, std::ostream& out)
{
serialize(item.p, out);
serialize(item.name, out);
serialize(item.str_rect, out);
serialize(item.color, out);
}
friend void deserialize(data& item, std::istream& in)
{
deserialize(item.p, in);
deserialize(item.name, in);
deserialize(item.str_rect, in);
deserialize(item.color, in);
}
mutable std::ostringstream sout;
const double radius;
unsigned long selected_node;
bool mouse_drag; // true if the user is dragging a node
point drag_offset;
bool edge_selected;
unsigned long selected_edge_parent;
unsigned long selected_edge_child;
any_function<void(unsigned long)> node_selected_handler;
any_function<void(unsigned long)> node_deselected_handler;
any_function<void()> node_deleted_handler;
any_function<void()> graph_modified_handler;
graph_type external_graph;
// rebind the graph_ type to make us a graph_ of data structs
typename graph_type::template rebind<data,char, typename graph_type::mem_manager_type>::other graph_;
bool last_mouse_click_in_display;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class text_grid
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class text_grid : public scrollable_region
{
/*!
INITIAL VALUE
- has_focus == false
- vertical_scroll_increment() == 10
- horizontal_scroll_increment() == 10
- border_color_ == rgb_pixel(128,128,128)
CONVENTION
- grid.nr() == row_height.size()
- grid.nc() == col_width.size()
- border_color() == border_color_
- text(r,c) == grid[r][c].text
- text_color(r,c) == grid[r][c].text_color
- background_color(r,c) == grid[r][c].bg_color
- if (the user has clicked on this widget and caused one of the
boxes to have input focus) then
- has_focus == true
- grid[active_row][active_col] == the active text box
- cursor_pos == the position of the cursor in the above box
- if (the cursor should be displayed) then
- show_cursor == true
- else
- show_cursor == false
- else
- has_focus == false
!*/
public:
text_grid (
drawable_window& w
);
~text_grid (
);
void set_grid_size (
unsigned long rows,
unsigned long cols
);
unsigned long number_of_columns (
) const;
unsigned long number_of_rows (
) const;
int next_free_user_event_number (
) const;
rgb_pixel border_color (
) const;
void set_border_color (
rgb_pixel color
);
const std::string text (
unsigned long row,
unsigned long col
) const;
const std::wstring wtext (
unsigned long row,
unsigned long col
) const;
const dlib::ustring utext (
unsigned long row,
unsigned long col
) const;
void set_text (
unsigned long row,
unsigned long col,
const std::string& str
);
void set_text (
unsigned long row,
unsigned long col,
const std::wstring& str
);
void set_text (
unsigned long row,
unsigned long col,
const dlib::ustring& str
);
const rgb_pixel text_color (
unsigned long row,
unsigned long col
) const;
void set_text_color (
unsigned long row,
unsigned long col,
const rgb_pixel color
);
const rgb_pixel background_color (
unsigned long row,
unsigned long col
) const;
void set_background_color (
unsigned long row,
unsigned long col,
const rgb_pixel color
);
bool is_editable (
unsigned long row,
unsigned long col
) const;
void set_editable (
unsigned long row,
unsigned long col,
bool editable
);
void set_column_width (
unsigned long col,
unsigned long width
);
void set_row_height (
unsigned long row,
unsigned long height
);
void disable (
);
void hide (
);
template <
typename T
>
void set_text_modified_handler (
T& object,
void (T::*eh)(unsigned long, unsigned long)
) { text_modified_handler = make_mfp(object,eh); }
void set_text_modified_handler (
const any_function<void(unsigned long, unsigned long)>& eh
) { text_modified_handler = eh; }
private:
void on_user_event (
int num
);
void timer_action (
);
/*!
ensures
- flips the state of show_cursor
!*/
void compute_bg_rects (
);
void compute_total_rect (
);
void on_keydown (
unsigned long key,
bool is_printable,
unsigned long state
);
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void on_mouse_up (
unsigned long btn,
unsigned long state,
long x,
long y
);
void on_focus_lost (
);
void draw (
const canvas& c
) const;
rectangle get_text_rect (
unsigned long row,
unsigned long col
) const;
rectangle get_bg_rect (
unsigned long row,
unsigned long col
) const;
struct data_type
{
data_type(): text_color(0,0,0), bg_color(255,255,255),
first(0), is_editable(true)
{}
dlib::ustring text;
rgb_pixel text_color;
rgb_pixel bg_color;
rectangle bg_rect;
dlib::ustring::size_type first;
bool is_editable;
};
void drop_input_focus (
);
void move_cursor (
long row,
long col,
long new_cursor_pos
);
array2d<data_type> grid;
array<unsigned long> col_width;
array<unsigned long> row_height;
bool has_focus;
long active_col;
long active_row;
long cursor_pos;
bool show_cursor;
bool recent_cursor_move;
timer<text_grid> cursor_timer;
rgb_pixel border_color_;
any_function<void(unsigned long, unsigned long)> text_modified_handler;
};
// ----------------------------------------------------------------------------------------
class image_display : public scrollable_region
{
/*!
INITIAL VALUE
- img.size() == 0
- overlay_rects.size() == 0
- overlay_lines.size() == 0
- drawing_rect == false
- rect_is_selected == false
CONVENTION
- img == the image this object displays
- overlay_rects == the overlay rectangles this object displays
- overlay_lines == the overlay lines this object displays
- if (drawing_rect) then
- the user is drawing a rectangle on the screen and is
thus holding down CTRL and the left mouse button.
- rect_anchor == the point on the screen where the user
clicked to begin drawing the rectangle.
- rect_to_draw == the rectangle which should appear on the screen.
- 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
- if (moving_overlay) then
- moving_rect == the index in overlay_rects that the move applies to.
- if (moving_what == MOVING_PART) then
- moving_part_name == the name of the part in
overlay_rects[moving_rect] that is being moved around with the
mouse.
- else
- moving_what will tell us which side of the rectangle in
overlay_rects[moving_rect] is being moved by the mouse.
!*/
public:
image_display(
drawable_window& w
);
~image_display(
);
template <
typename image_type
>
void set_image (
const image_type& new_img
)
{
auto_mutex M(m);
// if the new image has a different size when compared to the previous image
// then we should readjust the total rectangle size.
if (num_rows(new_img) != img.nr() || num_columns(new_img) != img.nc())
{
if (zoom_in_scale != 1)
set_total_rect_size(num_columns(new_img)*zoom_in_scale, num_rows(new_img)*zoom_in_scale);
else
set_total_rect_size(num_columns(new_img)/zoom_out_scale, num_rows(new_img)/zoom_out_scale);
}
else
{
parent.invalidate_rectangle(rect);
}
highlighted_rect = std::numeric_limits<unsigned long>::max();
rect_is_selected = false;
parts_menu.disable();
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 (
unsigned long width,
unsigned long height
)
{
auto_mutex lock(m);
scrollable_region::set_size(width,height);
parts_menu.set_rect(rect);
}
struct overlay_rect
{
overlay_rect() :crossed_out(false) { assign_pixel(color, 0);}
template <typename pixel_type>
overlay_rect(const rectangle& r, pixel_type p)
: rect(r),crossed_out(false) { assign_pixel(color, p); }
template <typename pixel_type>
overlay_rect(const rectangle& r, pixel_type p, const std::string& l)
: rect(r),label(l),crossed_out(false) { 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_),crossed_out(false) { assign_pixel(color, p); }
rectangle rect;
rgb_alpha_pixel color;
std::string label;
std::map<std::string,point> parts;
bool crossed_out;
};
struct overlay_line
{
overlay_line() { assign_pixel(color, 0);}
template <typename pixel_type>
overlay_line(const dpoint& p1_, const dpoint& p2_, pixel_type p)
: p1(p1_), p2(p2_) { assign_pixel(color, p); }
dpoint p1;
dpoint p2;
rgb_alpha_pixel color;
};
struct overlay_circle
{
overlay_circle():radius(0) { assign_pixel(color, 0);}
template <typename pixel_type>
overlay_circle(const point& center_, const double radius_, pixel_type p)
: center(center_), radius(radius_) { assign_pixel(color, p); }
template <typename pixel_type>
overlay_circle(const point& center_, const double radius_, pixel_type p, const std::string& l)
: center(center_), radius(radius_), label(l) { assign_pixel(color, p); }
point center;
double radius;
rgb_alpha_pixel color;
std::string label;
};
void add_overlay (
const overlay_rect& overlay
);
void add_overlay (
const overlay_line& overlay
);
void add_overlay (
const overlay_circle& overlay
);
void add_overlay (
const std::vector<overlay_rect>& overlay
);
void add_overlay (
const std::vector<overlay_line>& overlay
);
void add_overlay (
const std::vector<overlay_circle>& overlay
);
void clear_overlay (
);
rectangle get_image_display_rect (
) const;
std::vector<overlay_rect> get_overlay_rects (
) const;
void set_default_overlay_rect_label (
const std::string& label
);
std::string get_default_overlay_rect_label (
) const;
void set_default_overlay_rect_color (
const rgb_alpha_pixel& color
);
rgb_alpha_pixel get_default_overlay_rect_color (
) const;
template <
typename T
>
void set_overlay_rects_changed_handler (
T& object,
void (T::*event_handler_)()
)
{
auto_mutex M(m);
event_handler = make_mfp(object,event_handler_);
}
void set_overlay_rects_changed_handler (
const any_function<void()>& event_handler_
)
{
auto_mutex M(m);
event_handler = event_handler_;
}
template <
typename T
>
void set_overlay_rect_selected_handler (
T& object,
void (T::*event_handler_)(const overlay_rect& orect)
)
{
auto_mutex M(m);
orect_selected_event_handler = make_mfp(object,event_handler_);
}
void set_overlay_rect_selected_handler (
const any_function<void(const overlay_rect& orect)>& event_handler_
)
{
auto_mutex M(m);
orect_selected_event_handler = event_handler_;
}
template <
typename T
>
void set_image_clicked_handler (
T& object,
void (T::*event_handler_)(const point& p, bool is_double_click, unsigned long btn)
)
{
auto_mutex M(m);
image_clicked_handler = make_mfp(object,event_handler_);
}
void set_image_clicked_handler (
const any_function<void(const point& p, bool is_double_click, unsigned long btn)>& event_handler_
)
{
auto_mutex M(m);
image_clicked_handler = event_handler_;
}
void add_labelable_part_name (
const std::string& name
);
void clear_labelable_part_names (
);
void enable_overlay_editing (
) { auto_mutex M(m); overlay_editing_enabled = true; }
void disable_overlay_editing (
)
{
auto_mutex M(m);
overlay_editing_enabled = false;
rect_is_selected = false;
drawing_rect = false;
parent.invalidate_rectangle(rect);
}
bool overlay_editing_is_enabled (
) const { auto_mutex M(m); return overlay_editing_enabled; }
void zoom_in (
);
void zoom_out (
);
private:
void draw (
const canvas& c
) const;
void on_wheel_up (
unsigned long state
);
void on_wheel_down (
unsigned long state
);
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void on_mouse_up (
unsigned long btn,
unsigned long state,
long x,
long y
);
void on_mouse_move (
unsigned long state,
long x,
long y
);
void on_keydown (
unsigned long key,
bool is_printable,
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); }
virtual int next_free_user_event_number (
) const { return scrollable_region::next_free_user_event_number()+1; }
// The reason for using user actions here rather than just having the timer just call
// what it needs directly is to avoid a potential deadlock during destruction of this widget.
void timer_event_unhighlight_rect()
{
highlight_timer.stop();
parent.trigger_user_event(this,scrollable_region::next_free_user_event_number());
}
void on_user_event (int num)
{
// ignore this user event if it isn't for us
if (num != scrollable_region::next_free_user_event_number())
return;
if (highlighted_rect < overlay_rects.size())
{
highlighted_rect = std::numeric_limits<unsigned long>::max();
parent.invalidate_rectangle(rect);
}
}
array2d<rgb_alpha_pixel> img;
std::vector<overlay_rect> overlay_rects;
std::vector<overlay_line> overlay_lines;
std::vector<overlay_circle> overlay_circles;
long zoom_in_scale;
long zoom_out_scale;
bool drawing_rect;
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;
any_function<void(const point& p, bool is_double_click, unsigned long btn)> image_clicked_handler;
popup_menu_region parts_menu;
point last_right_click_pos;
const double part_width;
std::set<std::string> part_names;
bool overlay_editing_enabled;
timer<image_display> highlight_timer;
unsigned long highlighted_rect;
bool holding_shift_key;
bool moving_overlay;
unsigned long moving_rect;
enum {
MOVING_RECT_LEFT,
MOVING_RECT_TOP,
MOVING_RECT_RIGHT,
MOVING_RECT_BOTTOM,
MOVING_PART
} moving_what;
std::string moving_part_name;
// restricted functions
image_display(image_display&); // copy constructor
image_display& operator=(image_display&); // assignment operator
};
// ----------------------------------------------------------------------------------------
class perspective_display : public drawable, noncopyable
{
public:
perspective_display(
drawable_window& w
);
~perspective_display(
);
virtual void set_size (
unsigned long width,
unsigned long height
);
struct overlay_line
{
overlay_line() { assign_pixel(color, 0);}
overlay_line(const vector<double>& p1_, const vector<double>& p2_)
: p1(p1_), p2(p2_) { assign_pixel(color, 255); }
template <typename pixel_type>
overlay_line(const vector<double>& p1_, const vector<double>& p2_, pixel_type p)
: p1(p1_), p2(p2_) { assign_pixel(color, p); }
vector<double> p1;
vector<double> p2;
rgb_pixel color;
};
struct overlay_dot
{
overlay_dot() { assign_pixel(color, 0);}
overlay_dot(const vector<double>& p_)
: p(p_) { assign_pixel(color, 255); }
template <typename pixel_type>
overlay_dot(const vector<double>& p_, pixel_type color_)
: p(p_) { assign_pixel(color, color_); }
vector<double> p;
rgb_pixel color;
};
void add_overlay (
const std::vector<overlay_line>& overlay
);
void add_overlay (
const std::vector<overlay_dot>& overlay
);
void clear_overlay (
);
template <
typename T
>
void set_dot_double_clicked_handler (
T& object,
void (T::*event_handler_)(const vector<double>&)
)
{
auto_mutex M(m);
dot_clicked_event_handler = make_mfp(object,event_handler_);
}
void set_dot_double_clicked_handler (
const any_function<void(const vector<double>&)>& event_handler_
);
private:
void draw (
const canvas& c
) const;
void on_wheel_up (
unsigned long state
);
void on_wheel_down (
unsigned long state
);
void on_mouse_down (
unsigned long btn,
unsigned long state,
long x,
long y,
bool is_double_click
);
void on_mouse_move (
unsigned long state,
long x,
long y
);
static bool compare_second (
const std::pair<overlay_dot,float>& a,
const std::pair<overlay_dot,float>& b
) { return a.second < b.second; }
point last;
std::vector<overlay_line> overlay_lines;
std::vector<overlay_dot> overlay_dots;
camera_transform tform;
vector<double> sum_pts;
vector<double> max_pts;
any_function<void(const vector<double>&)> dot_clicked_event_handler;
mutable array2d<float> depth;
};
// ----------------------------------------------------------------------------------------
class perspective_window : public drawable_window, noncopyable
{
public:
typedef perspective_display::overlay_line overlay_line;
typedef perspective_display::overlay_dot overlay_dot;
perspective_window(
) : disp(*this)
{
set_size(100,100);
on_window_resized();
show();
}
perspective_window(
const std::vector<dlib::vector<double> >& point_cloud
) :
disp(*this)
{
set_size(100,100);
on_window_resized();
add_overlay(point_cloud);
show();
}
perspective_window(
const std::vector<dlib::vector<double> >& point_cloud,
const std::string& title
) :
disp(*this)
{
set_size(100,100);
on_window_resized();
add_overlay(point_cloud);
set_title(title);
show();
}
~perspective_window(
)
{
// You should always call close_window() in the destructor of window
// objects to ensure that no events will be sent to this window while
// it is being destructed.
close_window();
}
void add_overlay (
const std::vector<overlay_line>& overlay
)
{
disp.add_overlay(overlay);
}
void add_overlay (
const std::vector<overlay_dot>& overlay
)
{
disp.add_overlay(overlay);
}
void clear_overlay (
)
{
disp.clear_overlay();
}
template <typename pixel_type>
void add_overlay(const vector<double>& p1, const vector<double>& p2, pixel_type p)
{
add_overlay(std::vector<overlay_line>(1,overlay_line(p1,p2,p)));
}
void add_overlay(const std::vector<dlib::vector<double> >& d)
{
add_overlay(d, 255);
}
template <typename pixel_type>
void add_overlay(const std::vector<dlib::vector<double> >& d, pixel_type p)
{
std::vector<overlay_dot> temp;
temp.resize(d.size());
for (unsigned long i = 0; i < temp.size(); ++i)
temp[i] = overlay_dot(d[i], p);
add_overlay(temp);
}
template <
typename T
>
void set_dot_double_clicked_handler (
T& object,
void (T::*event_handler_)(const vector<double>&)
)
{
disp.set_dot_double_clicked_handler(object,event_handler_);
}
void set_dot_double_clicked_handler (
const any_function<void(const vector<double>&)>& event_handler_
)
{
disp.set_dot_double_clicked_handler(event_handler_);
}
private:
void on_window_resized(
)
{
drawable_window::on_window_resized();
unsigned long width, height;
get_size(width,height);
disp.set_pos(0,0);
disp.set_size(width, height);
}
perspective_display disp;
};
// ----------------------------------------------------------------------------------------
class image_window : public drawable_window
{
public:
typedef image_display::overlay_rect overlay_rect;
typedef image_display::overlay_line overlay_line;
typedef image_display::overlay_circle overlay_circle;
image_window(
);
template < typename image_type >
image_window(
const image_type& img
) :
gui_img(*this),
window_has_closed(false),
have_last_click(false),
mouse_btn(0),
clicked_signaler(this->wm),
have_last_keypress(false),
tie_input_events(false)
{
gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);
gui_img.disable_overlay_editing();
set_image(img);
show();
}
template < typename image_type >
image_window(
const image_type& img,
const std::string& title
) :
gui_img(*this),
window_has_closed(false),
have_last_click(false),
mouse_btn(0),
clicked_signaler(this->wm),
have_last_keypress(false),
tie_input_events(false)
{
gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);
gui_img.disable_overlay_editing();
set_image(img);
set_title(title);
show();
}
~image_window(
);
template < typename image_type >
void set_image (
const image_type& img
)
{
const unsigned long padding = scrollable_region_style_default().get_border_size();
auto_mutex M(wm);
gui_img.set_image(img);
// Only ever mess with the size of the window if the user is giving us an image
// that is a different size. Otherwise we assume that they will have already
// sized the window to whatever they feel is reasonable for an image of the
// current size.
if (previous_image_size != get_rect(img))
{
const rectangle r = gui_img.get_image_display_rect();
if (image_rect != r)
{
// set the size of this window to match the size of the input image
set_size(r.width()+padding*2,r.height()+padding*2);
// call this to make sure everything else is setup properly
on_window_resized();
image_rect = r;
}
previous_image_size = get_rect(img);
}
}
void add_overlay (
const overlay_rect& overlay
);
template <typename pixel_type>
void add_overlay(const rectangle& r, pixel_type p)
{ add_overlay(image_display::overlay_rect(r,p)); }
void add_overlay(const rectangle& r)
{ add_overlay(image_display::overlay_rect(r,rgb_pixel(255,0,0))); }
template <typename pixel_type>
void add_overlay(const rectangle& r, pixel_type p, const std::string& l)
{ add_overlay(image_display::overlay_rect(r,p,l)); }
template <typename pixel_type>
void add_overlay(const std::vector<rectangle>& r, pixel_type p)
{
std::vector<overlay_rect> temp;
temp.resize(r.size());
for (unsigned long i = 0; i < temp.size(); ++i)
temp[i] = overlay_rect(r[i], p);
add_overlay(temp);
}
void add_overlay(const std::vector<rectangle>& r)
{ add_overlay(r, rgb_pixel(255,0,0)); }
void add_overlay(
const full_object_detection& object,
const std::vector<std::string>& part_names
)
{
add_overlay(overlay_rect(object.get_rect(), rgb_pixel(255,0,0)));
std::vector<overlay_circle> temp;
temp.reserve(object.num_parts());
for (unsigned long i = 0; i < object.num_parts(); ++i)
{
if (object.part(i) != OBJECT_PART_NOT_PRESENT)
{
if (i < part_names.size())
temp.push_back(overlay_circle(object.part(i), 7, rgb_pixel(0,255,0), part_names[i]));
else
temp.push_back(overlay_circle(object.part(i), 7, rgb_pixel(0,255,0)));
}
}
add_overlay(temp);
}
void add_overlay(
const full_object_detection& object
)
{
std::vector<std::string> part_names;
add_overlay(object, part_names);
}
void add_overlay(
const std::vector<full_object_detection>& objects,
const std::vector<std::string>& part_names
)
{
std::vector<overlay_rect> rtemp;
rtemp.reserve(objects.size());
for (unsigned long i = 0; i < objects.size(); ++i)
{
rtemp.push_back(overlay_rect(objects[i].get_rect(), rgb_pixel(255,0,0)));
}
add_overlay(rtemp);
std::vector<overlay_circle> temp;
for (unsigned long i = 0; i < objects.size(); ++i)
{
for (unsigned long j = 0; j < objects[i].num_parts(); ++j)
{
if (objects[i].part(j) != OBJECT_PART_NOT_PRESENT)
{
if (j < part_names.size())
temp.push_back(overlay_circle(objects[i].part(j), 7, rgb_pixel(0,255,0),part_names[j]));
else
temp.push_back(overlay_circle(objects[i].part(j), 7, rgb_pixel(0,255,0)));
}
}
}
add_overlay(temp);
}
void add_overlay(
const std::vector<full_object_detection>& objects
)
{
std::vector<std::string> part_names;
add_overlay(objects, part_names);
}
void add_overlay (
const overlay_line& overlay
);
template <typename pixel_type>
void add_overlay(const line& l, pixel_type p)
{
add_overlay(image_display::overlay_line(l.p1(),l.p2(),p));
}
void add_overlay(const line& l)
{
add_overlay(l, rgb_pixel(255,0,0));
}
void add_overlay (
const overlay_circle& overlay
);
template <typename pixel_type>
void add_overlay(const point& p1, const point& p2, pixel_type p)
{ add_overlay(image_display::overlay_line(p1,p2,p)); }
void add_overlay (
const std::vector<overlay_rect>& overlay
);
void add_overlay (
const std::vector<overlay_line>& overlay
);
void add_overlay (
const std::vector<overlay_circle>& overlay
);
void clear_overlay (
);
bool get_next_double_click (
point& p,
unsigned long& mouse_button
);
void tie_events (
);
void untie_events (
);
bool events_tied (
) const;
bool get_next_double_click (
point& p
)
{
unsigned long mouse_button;
return get_next_double_click(p, mouse_button);
}
bool get_next_keypress (
unsigned long& key,
bool& is_printable,
unsigned long& state
);
bool get_next_keypress (
unsigned long& key,
bool& is_printable
)
{
unsigned long state;
return get_next_keypress(key,is_printable,state);
}
private:
virtual base_window::on_close_return_code on_window_close(
);
void on_window_resized(
);
void on_image_clicked (
const point& p,
bool is_double_click,
unsigned long btn
);
virtual void on_keydown (
unsigned long key,
bool is_printable,
unsigned long state
);
// restricted functions
image_window(image_window&);
image_window& operator= (image_window&);
image_display gui_img;
rectangle image_rect;
rectangle previous_image_size;
bool window_has_closed;
bool have_last_click;
point last_clicked_point;
unsigned long mouse_btn;
rsignaler clicked_signaler;
bool have_last_keypress;
unsigned long next_key;
bool next_is_printable;
unsigned long next_state;
bool tie_input_events;
};
// ----------------------------------------------------------------------------------------
}
#ifdef NO_MAKEFILE
#include "widgets.cpp"
#endif
#endif // DLIB_WIDGETs_