|
|
|
|
|
|
|
#ifndef DLIB_BASE_WIDGETs_ |
|
#define DLIB_BASE_WIDGETs_ |
|
|
|
#include <cctype> |
|
#include <memory> |
|
|
|
#include "base_widgets_abstract.h" |
|
#include "drawable.h" |
|
#include "../gui_core.h" |
|
#include "../algs.h" |
|
#include "../member_function_pointer.h" |
|
#include "../timer.h" |
|
#include "../map.h" |
|
#include "../set.h" |
|
#include "../array2d.h" |
|
#include "../pixel.h" |
|
#include "../image_transforms/assign_image.h" |
|
#include "../array.h" |
|
#include "style.h" |
|
#include "../unicode.h" |
|
#include "../any.h" |
|
|
|
|
|
namespace dlib |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class draggable : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
draggable( |
|
drawable_window& w, |
|
unsigned long events = 0 |
|
) : |
|
drawable(w,events | MOUSE_MOVE | MOUSE_CLICK), |
|
drag(false) |
|
{} |
|
|
|
virtual ~draggable( |
|
) = 0; |
|
|
|
rectangle draggable_area ( |
|
) const { auto_mutex M(m); return area; } |
|
|
|
void set_draggable_area ( |
|
const rectangle& area_ |
|
) { auto_mutex M(m); area = area_; } |
|
|
|
protected: |
|
|
|
bool is_being_dragged ( |
|
) const { return drag; } |
|
|
|
virtual void on_drag ( |
|
){} |
|
|
|
virtual void on_drag_stop ( |
|
){} |
|
|
|
void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
void on_mouse_down ( |
|
unsigned long btn, |
|
unsigned long , |
|
long x, |
|
long y, |
|
bool |
|
); |
|
|
|
void on_mouse_up ( |
|
unsigned long btn, |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
private: |
|
|
|
rectangle area; |
|
bool drag; |
|
long x, y; |
|
|
|
|
|
draggable(draggable&); |
|
draggable& operator=(draggable&); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class mouse_over_event : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
mouse_over_event( |
|
drawable_window& w, |
|
unsigned long events = 0 |
|
) : |
|
drawable(w,events | MOUSE_MOVE), |
|
is_mouse_over_(false) |
|
{} |
|
|
|
|
|
virtual ~mouse_over_event( |
|
) = 0; |
|
|
|
int next_free_user_event_number() const |
|
{ |
|
return drawable::next_free_user_event_number()+1; |
|
} |
|
|
|
protected: |
|
|
|
bool is_mouse_over ( |
|
) const; |
|
|
|
virtual void on_mouse_over ( |
|
){} |
|
|
|
virtual void on_mouse_not_over ( |
|
){} |
|
|
|
void on_mouse_leave ( |
|
); |
|
|
|
void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
void on_user_event ( |
|
int num |
|
); |
|
|
|
private: |
|
mutable bool is_mouse_over_; |
|
|
|
|
|
mouse_over_event(mouse_over_event&); |
|
mouse_over_event& operator=(mouse_over_event&); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class button_action : public mouse_over_event |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
button_action( |
|
drawable_window& w, |
|
unsigned long events = 0 |
|
) : |
|
mouse_over_event(w,events | MOUSE_MOVE | MOUSE_CLICK), |
|
is_depressed_(false), |
|
seen_click(false) |
|
{} |
|
|
|
|
|
virtual ~button_action( |
|
) = 0; |
|
|
|
int next_free_user_event_number() const |
|
{ |
|
return mouse_over_event::next_free_user_event_number()+1; |
|
} |
|
|
|
protected: |
|
|
|
bool is_depressed ( |
|
) const; |
|
|
|
virtual void on_button_down ( |
|
){} |
|
|
|
virtual void on_button_up ( |
|
bool |
|
){} |
|
|
|
void on_mouse_not_over ( |
|
); |
|
|
|
void on_mouse_down ( |
|
unsigned long btn, |
|
unsigned long , |
|
long x, |
|
long y, |
|
bool |
|
); |
|
|
|
void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
void on_mouse_up ( |
|
unsigned long btn, |
|
unsigned long, |
|
long x, |
|
long y |
|
); |
|
|
|
|
|
private: |
|
mutable bool is_depressed_; |
|
bool seen_click; |
|
|
|
void on_user_event ( |
|
int num |
|
); |
|
|
|
|
|
button_action(button_action&); |
|
button_action& operator=(button_action&); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class widget_group : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct relpos |
|
{ |
|
unsigned long x; |
|
unsigned long y; |
|
}; |
|
|
|
public: |
|
widget_group( |
|
drawable_window& w |
|
) : drawable(w) { rect = rectangle(0,0,-1,-1); enable_events();} |
|
|
|
virtual ~widget_group( |
|
){ disable_events(); } |
|
|
|
void empty ( |
|
); |
|
|
|
void add ( |
|
drawable& widget, |
|
unsigned long x, |
|
unsigned long y |
|
); |
|
|
|
void add ( |
|
widget_group& widget, |
|
unsigned long x, |
|
unsigned long y |
|
); |
|
|
|
bool is_member ( |
|
const drawable& widget |
|
) const; |
|
|
|
void remove ( |
|
const drawable& widget |
|
); |
|
|
|
size_t size ( |
|
) const; |
|
|
|
void set_pos ( |
|
long x, |
|
long y |
|
); |
|
|
|
void set_z_order ( |
|
long order |
|
); |
|
|
|
void show ( |
|
); |
|
|
|
void hide ( |
|
); |
|
|
|
void enable ( |
|
); |
|
|
|
void disable ( |
|
); |
|
|
|
void fit_to_contents ( |
|
); |
|
|
|
protected: |
|
|
|
|
|
void draw ( |
|
const canvas& |
|
) const {} |
|
|
|
private: |
|
|
|
map<drawable*,relpos>::kernel_1a_c widgets; |
|
set<widget_group*>::kernel_1a_c wg_widgets; |
|
|
|
|
|
|
|
widget_group(widget_group&); |
|
widget_group& operator=(widget_group&); |
|
}; |
|
|
|
|
|
|
|
|
|
class image_widget : public draggable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
image_widget( |
|
drawable_window& w |
|
): draggable(w) { enable_events(); } |
|
|
|
~image_widget( |
|
) |
|
{ |
|
disable_events(); |
|
parent.invalidate_rectangle(rect); |
|
} |
|
|
|
template < |
|
typename image_type |
|
> |
|
void set_image ( |
|
const image_type& new_img |
|
) |
|
{ |
|
auto_mutex M(m); |
|
assign_image_scaled(img,new_img); |
|
rectangle old(rect); |
|
rect.set_right(rect.left()+num_columns(img)-1); |
|
rect.set_bottom(rect.top()+num_rows(img)-1); |
|
parent.invalidate_rectangle(rect+old); |
|
} |
|
|
|
private: |
|
|
|
void draw ( |
|
const canvas& c |
|
) const |
|
{ |
|
rectangle area = rect.intersect(c); |
|
if (area.is_empty()) |
|
return; |
|
|
|
draw_image(c, point(rect.left(),rect.top()), img); |
|
} |
|
|
|
array2d<rgb_alpha_pixel> img; |
|
|
|
|
|
image_widget(image_widget&); |
|
image_widget& operator=(image_widget&); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class tooltip : public mouse_over_event |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
tooltip( |
|
drawable_window& w |
|
) : |
|
mouse_over_event(w,MOUSE_CLICK) |
|
{} |
|
|
|
~tooltip( |
|
){ disable_events();} |
|
|
|
void set_size ( |
|
unsigned long width, |
|
unsigned long height |
|
) |
|
{ |
|
auto_mutex M(m); |
|
rect = resize_rect(rect,width,height); |
|
} |
|
|
|
|
|
void set_text ( |
|
const std::string& str |
|
) |
|
{ |
|
set_text(convert_mbstring_to_wstring(str)); |
|
} |
|
|
|
void set_text ( |
|
const std::wstring& str |
|
) |
|
{ |
|
set_text(convert_wstring_to_utf32(str)); |
|
} |
|
|
|
void set_text ( |
|
const ustring& str |
|
) |
|
{ |
|
auto_mutex M(m); |
|
if (!stuff) |
|
{ |
|
stuff.reset(new data(*this)); |
|
enable_events(); |
|
} |
|
|
|
stuff->win.set_text(str); |
|
} |
|
|
|
const std::string text ( |
|
) const |
|
{ |
|
return convert_wstring_to_mbstring(wtext()); |
|
} |
|
|
|
const std::wstring wtext ( |
|
) const |
|
{ |
|
return convert_utf32_to_wstring(utext()); |
|
} |
|
|
|
const dlib::ustring utext ( |
|
) const |
|
{ |
|
auto_mutex M(m); |
|
dlib::ustring temp; |
|
if (stuff) |
|
{ |
|
temp = stuff->win.text; |
|
} |
|
return temp.c_str(); |
|
} |
|
|
|
void hide ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
mouse_over_event::hide(); |
|
if (stuff) |
|
{ |
|
stuff->tt_timer.stop(); |
|
stuff->win.hide(); |
|
} |
|
} |
|
|
|
void disable ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
mouse_over_event::disable(); |
|
if (stuff) |
|
{ |
|
stuff->tt_timer.stop(); |
|
stuff->win.hide(); |
|
} |
|
} |
|
|
|
protected: |
|
|
|
void on_mouse_over() |
|
{ |
|
stuff->x = lastx; |
|
stuff->y = lasty; |
|
stuff->tt_timer.start(); |
|
} |
|
|
|
void on_mouse_not_over () |
|
{ |
|
stuff->tt_timer.stop(); |
|
stuff->win.hide(); |
|
} |
|
|
|
void on_mouse_down ( |
|
unsigned long btn, |
|
unsigned long state, |
|
long x, |
|
long y, |
|
bool is_double_click |
|
) |
|
{ |
|
mouse_over_event::on_mouse_down(btn,state,x,y,is_double_click); |
|
stuff->tt_timer.stop(); |
|
stuff->win.hide(); |
|
} |
|
|
|
void draw ( |
|
const canvas& |
|
) const{} |
|
|
|
private: |
|
|
|
class tooltip_window : public base_window |
|
{ |
|
public: |
|
tooltip_window (const std::shared_ptr<font>& f) : base_window(false,true), pad(3), mfont(f) |
|
{ |
|
} |
|
|
|
ustring text; |
|
rectangle rect_all; |
|
rectangle rect_text; |
|
const unsigned long pad; |
|
const std::shared_ptr<font> mfont; |
|
|
|
void set_text ( |
|
const std::string& str |
|
) |
|
{ |
|
set_text(convert_mbstring_to_wstring(str)); |
|
} |
|
|
|
void set_text ( |
|
const std::wstring& str |
|
) |
|
{ |
|
set_text(convert_wstring_to_utf32(str)); |
|
} |
|
|
|
void set_text ( |
|
const dlib::ustring& str |
|
) |
|
{ |
|
text = str.c_str(); |
|
|
|
unsigned long width, height; |
|
mfont->compute_size(text,width,height); |
|
|
|
set_size(width+pad*2, height+pad*2); |
|
rect_all.set_left(0); |
|
rect_all.set_top(0); |
|
rect_all.set_right(width+pad*2-1); |
|
rect_all.set_bottom(height+pad*2-1); |
|
|
|
rect_text = move_rect(rectangle(width,height),pad,pad); |
|
} |
|
|
|
void paint(const canvas& c) |
|
{ |
|
c.fill(255,255,150); |
|
draw_rectangle(c, rect_all); |
|
mfont->draw_string(c,rect_text,text); |
|
} |
|
}; |
|
|
|
void show_tooltip ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
long x, y; |
|
|
|
|
|
if (lastx != stuff->x || lasty != stuff->y) |
|
{ |
|
stuff->x = lastx; |
|
stuff->y = lasty; |
|
return; |
|
} |
|
|
|
unsigned long display_width, display_height; |
|
|
|
stuff->tt_timer.stop(); |
|
parent.get_pos(x,y); |
|
x += lastx+15; |
|
y += lasty+15; |
|
|
|
|
|
parent.get_display_size(display_width, display_height); |
|
rectangle wrect(move_rect(stuff->win.rect_all,x,y)); |
|
rectangle srect(display_width, display_height); |
|
if (srect.contains(wrect) == false) |
|
{ |
|
rectangle temp(srect.intersect(wrect)); |
|
x -= wrect.width()-temp.width(); |
|
y -= wrect.height()-temp.height(); |
|
} |
|
|
|
stuff->win.set_pos(x,y); |
|
stuff->win.show(); |
|
} |
|
|
|
|
|
|
|
|
|
struct data |
|
{ |
|
data( |
|
tooltip& self |
|
) : |
|
x(-1), |
|
y(-1), |
|
win(self.mfont), |
|
tt_timer(self,&tooltip::show_tooltip) |
|
{ |
|
tt_timer.set_delay_time(400); |
|
} |
|
|
|
long x, y; |
|
tooltip_window win; |
|
timer<tooltip> tt_timer; |
|
|
|
}; |
|
friend struct data; |
|
std::unique_ptr<data> stuff; |
|
|
|
|
|
|
|
|
|
tooltip(tooltip&); |
|
tooltip& operator=(tooltip&); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class button : public button_action |
|
{ |
|
public: |
|
button( |
|
drawable_window& w |
|
) : |
|
button_action(w), |
|
btn_tooltip(w) |
|
{ |
|
style.reset(new button_style_default()); |
|
enable_events(); |
|
} |
|
|
|
~button() { disable_events(); parent.invalidate_rectangle(style->get_invalidation_rect(rect)); } |
|
|
|
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 set_tooltip_text ( |
|
const std::string& text |
|
); |
|
|
|
void set_tooltip_text ( |
|
const std::wstring& text |
|
); |
|
|
|
void set_tooltip_text ( |
|
const dlib::ustring& text |
|
); |
|
|
|
void set_pos( |
|
long x, |
|
long y |
|
); |
|
|
|
const std::string tooltip_text ( |
|
) const; |
|
|
|
const std::wstring tooltip_wtext ( |
|
) const; |
|
|
|
const dlib::ustring tooltip_utext ( |
|
) const; |
|
|
|
void set_main_font ( |
|
const std::shared_ptr<font>& f |
|
); |
|
|
|
void show ( |
|
); |
|
|
|
void hide ( |
|
); |
|
|
|
void enable ( |
|
); |
|
|
|
void disable ( |
|
); |
|
|
|
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(style->get_invalidation_rect(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_)(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(button&)>& event_handler_ |
|
) |
|
{ |
|
auto_mutex M(m); |
|
event_handler_self = event_handler_; |
|
event_handler.clear(); |
|
} |
|
|
|
bool is_depressed ( |
|
) const |
|
{ |
|
auto_mutex M(m); |
|
return button_action::is_depressed(); |
|
} |
|
|
|
template < |
|
typename T |
|
> |
|
void set_button_down_handler ( |
|
T& object, |
|
void (T::*event_handler)() |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_down_handler = make_mfp(object,event_handler); |
|
} |
|
|
|
void set_button_down_handler ( |
|
const any_function<void()>& event_handler |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_down_handler = event_handler; |
|
} |
|
|
|
template < |
|
typename T |
|
> |
|
void set_button_up_handler ( |
|
T& object, |
|
void (T::*event_handler)(bool mouse_over) |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_up_handler = make_mfp(object,event_handler); |
|
} |
|
|
|
void set_button_up_handler ( |
|
const any_function<void(bool)>& event_handler |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_up_handler = event_handler; |
|
} |
|
|
|
template < |
|
typename T |
|
> |
|
void set_button_down_handler ( |
|
T& object, |
|
void (T::*event_handler)(button&) |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_down_handler_self = make_mfp(object,event_handler); |
|
} |
|
|
|
void set_sourced_button_down_handler ( |
|
const any_function<void(button&)>& event_handler |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_down_handler_self = event_handler; |
|
} |
|
|
|
template < |
|
typename T |
|
> |
|
void set_button_up_handler ( |
|
T& object, |
|
void (T::*event_handler)(bool mouse_over, button&) |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_up_handler_self = make_mfp(object,event_handler); |
|
} |
|
|
|
void set_sourced_button_up_handler ( |
|
const any_function<void(bool,button&)>& event_handler |
|
) |
|
{ |
|
auto_mutex M(m); |
|
button_up_handler_self = event_handler; |
|
} |
|
|
|
private: |
|
|
|
|
|
button(button&); |
|
button& operator=(button&); |
|
|
|
dlib::ustring name_; |
|
tooltip btn_tooltip; |
|
|
|
any_function<void()> event_handler; |
|
any_function<void(button&)> event_handler_self; |
|
any_function<void()> button_down_handler; |
|
any_function<void(bool)> button_up_handler; |
|
any_function<void(button&)> button_down_handler_self; |
|
any_function<void(bool,button&)> button_up_handler_self; |
|
|
|
std::unique_ptr<button_style> style; |
|
|
|
protected: |
|
|
|
void draw ( |
|
const canvas& c |
|
) const { style->draw_button(c,rect,enabled,*mfont,lastx,lasty,name_,is_depressed()); } |
|
|
|
void on_button_up ( |
|
bool mouse_over |
|
); |
|
|
|
void on_button_down ( |
|
); |
|
|
|
void on_mouse_over ( |
|
){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(style->get_invalidation_rect(rect)); } |
|
|
|
void on_mouse_not_over ( |
|
){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(style->get_invalidation_rect(rect)); } |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class scroll_bar : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
enum bar_orientation |
|
{ |
|
HORIZONTAL, |
|
VERTICAL |
|
}; |
|
|
|
scroll_bar( |
|
drawable_window& w, |
|
bar_orientation orientation_ |
|
); |
|
|
|
virtual ~scroll_bar( |
|
); |
|
|
|
bar_orientation orientation ( |
|
) const; |
|
|
|
void set_length ( |
|
unsigned long length |
|
); |
|
|
|
long max_slider_pos ( |
|
) const; |
|
|
|
void set_max_slider_pos ( |
|
long mpos |
|
); |
|
|
|
void set_slider_pos ( |
|
long pos |
|
); |
|
|
|
long slider_pos ( |
|
) const; |
|
|
|
template < |
|
typename T |
|
> |
|
void set_scroll_handler ( |
|
T& object, |
|
void (T::*eh)() |
|
) { auto_mutex M(m); scroll_handler = make_mfp(object,eh); } |
|
|
|
void set_scroll_handler ( |
|
const any_function<void()>& eh |
|
) { auto_mutex M(m); scroll_handler = eh; } |
|
|
|
void set_pos ( |
|
long x, |
|
long y |
|
); |
|
|
|
void enable ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
if (!hidden) |
|
show_slider(); |
|
if (max_pos != 0) |
|
{ |
|
b1.enable(); |
|
b2.enable(); |
|
} |
|
drawable::enable(); |
|
} |
|
|
|
void disable ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
hide_slider(); |
|
b1.disable(); |
|
b2.disable(); |
|
drawable::disable(); |
|
} |
|
|
|
void hide ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
hide_slider(); |
|
top_filler.hide(); |
|
bottom_filler.hide(); |
|
b1.hide(); |
|
b2.hide(); |
|
drawable::hide(); |
|
} |
|
|
|
void show ( |
|
) |
|
{ |
|
auto_mutex M(m); |
|
b1.show(); |
|
b2.show(); |
|
drawable::show(); |
|
top_filler.show(); |
|
if (enabled) |
|
show_slider(); |
|
} |
|
|
|
void set_z_order ( |
|
long order |
|
) |
|
{ |
|
auto_mutex M(m); |
|
slider.set_z_order(order); |
|
top_filler.set_z_order(order); |
|
bottom_filler.set_z_order(order); |
|
b1.set_z_order(order); |
|
b2.set_z_order(order); |
|
drawable::set_z_order(order); |
|
} |
|
|
|
void set_jump_size ( |
|
long js |
|
); |
|
|
|
long jump_size ( |
|
) const; |
|
|
|
template < |
|
typename style_type |
|
> |
|
void set_style ( |
|
const style_type& style_ |
|
) |
|
{ |
|
auto_mutex M(m); |
|
style.reset(new style_type(style_)); |
|
|
|
if (ori == HORIZONTAL) |
|
{ |
|
b1.set_style(style_.get_left_button_style()); |
|
b2.set_style(style_.get_right_button_style()); |
|
set_length(rect.width()); |
|
} |
|
else |
|
{ |
|
b1.set_style(style_.get_up_button_style()); |
|
b2.set_style(style_.get_down_button_style()); |
|
set_length(rect.height()); |
|
} |
|
|
|
} |
|
|
|
private: |
|
|
|
void hide_slider ( |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
void show_slider ( |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void on_slider_drag ( |
|
); |
|
|
|
|
|
|
|
|
|
|
|
void draw ( |
|
const canvas& c |
|
) const; |
|
|
|
void b1_down ( |
|
); |
|
|
|
void b1_up ( |
|
bool mouse_over |
|
); |
|
|
|
void b2_down ( |
|
); |
|
|
|
void b2_up ( |
|
bool mouse_over |
|
); |
|
|
|
void top_filler_down ( |
|
); |
|
|
|
void top_filler_up ( |
|
bool mouse_over |
|
); |
|
|
|
void bottom_filler_down ( |
|
); |
|
|
|
void bottom_filler_up ( |
|
bool mouse_over |
|
); |
|
|
|
void on_user_event ( |
|
int i |
|
); |
|
|
|
void delayed_set_slider_pos ( |
|
unsigned long dpos |
|
); |
|
|
|
void b1_down_t ( |
|
); |
|
|
|
void b2_down_t ( |
|
); |
|
|
|
void top_filler_down_t ( |
|
); |
|
|
|
void bottom_filler_down_t ( |
|
); |
|
|
|
friend class filler; |
|
class filler : public button_action |
|
{ |
|
friend class scroll_bar; |
|
public: |
|
filler ( |
|
drawable_window& w, |
|
scroll_bar& object, |
|
void (scroll_bar::*down)(), |
|
void (scroll_bar::*up)(bool) |
|
): |
|
button_action(w), |
|
my_scroll_bar(object) |
|
{ |
|
bup = make_mfp(object,up); |
|
bdown = make_mfp(object,down); |
|
|
|
enable_events(); |
|
} |
|
|
|
~filler ( |
|
) |
|
{ |
|
disable_events(); |
|
} |
|
|
|
void set_size ( |
|
unsigned long width, |
|
unsigned long height |
|
) |
|
{ |
|
rectangle old(rect); |
|
const unsigned long x = rect.left(); |
|
const unsigned long y = rect.top(); |
|
rect.set_right(x+width-1); |
|
rect.set_bottom(y+height-1); |
|
|
|
parent.invalidate_rectangle(rect+old); |
|
} |
|
|
|
private: |
|
|
|
void draw ( |
|
const canvas& c |
|
) const |
|
{ |
|
my_scroll_bar.style->draw_scroll_bar_background(c,rect,enabled,lastx,lasty,is_depressed()); |
|
} |
|
|
|
void on_button_down ( |
|
) { bdown(); } |
|
|
|
void on_button_up ( |
|
bool mouse_over |
|
) { bup(mouse_over); } |
|
|
|
scroll_bar& my_scroll_bar; |
|
any_function<void()> bdown; |
|
any_function<void(bool)> bup; |
|
}; |
|
|
|
friend class slider_class; |
|
class slider_class : public draggable |
|
{ |
|
friend class scroll_bar; |
|
public: |
|
slider_class ( |
|
drawable_window& w, |
|
scroll_bar& object, |
|
void (scroll_bar::*handler)() |
|
) : |
|
draggable(w, MOUSE_MOVE), |
|
mouse_in_widget(false), |
|
my_scroll_bar(object) |
|
{ |
|
callback = make_mfp(object,handler); |
|
enable_events(); |
|
} |
|
|
|
~slider_class ( |
|
) |
|
{ |
|
disable_events(); |
|
} |
|
|
|
void set_size ( |
|
unsigned long width, |
|
unsigned long height |
|
) |
|
{ |
|
rectangle old(rect); |
|
const unsigned long x = rect.left(); |
|
const unsigned long y = rect.top(); |
|
rect.set_right(x+width-1); |
|
rect.set_bottom(y+height-1); |
|
|
|
parent.invalidate_rectangle(rect+old); |
|
} |
|
|
|
private: |
|
virtual void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
) |
|
{ |
|
draggable::on_mouse_move(state,x,y); |
|
if (!hidden && my_scroll_bar.style->redraw_on_mouse_over_slider()) |
|
{ |
|
if (rect.contains(x,y) && !mouse_in_widget) |
|
{ |
|
mouse_in_widget = true; |
|
parent.invalidate_rectangle(rect); |
|
} |
|
else if (rect.contains(x,y) == false && mouse_in_widget) |
|
{ |
|
mouse_in_widget = false; |
|
parent.invalidate_rectangle(rect); |
|
} |
|
} |
|
} |
|
|
|
void on_mouse_leave ( |
|
) |
|
{ |
|
if (mouse_in_widget && my_scroll_bar.style->redraw_on_mouse_over_slider()) |
|
{ |
|
mouse_in_widget = false; |
|
parent.invalidate_rectangle(rect); |
|
} |
|
} |
|
|
|
void on_drag_stop ( |
|
) |
|
{ |
|
if (my_scroll_bar.style->redraw_on_mouse_over_slider()) |
|
parent.invalidate_rectangle(rect); |
|
} |
|
|
|
void on_drag ( |
|
) |
|
{ |
|
callback(); |
|
} |
|
|
|
void draw ( |
|
const canvas& c |
|
) const |
|
{ |
|
my_scroll_bar.style->draw_scroll_bar_slider(c,rect,enabled,lastx,lasty, is_being_dragged()); |
|
} |
|
|
|
bool mouse_in_widget; |
|
scroll_bar& my_scroll_bar; |
|
any_function<void()> callback; |
|
}; |
|
|
|
|
|
void adjust_fillers ( |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned long get_slider_size ( |
|
) const; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
button b1, b2; |
|
slider_class slider; |
|
bar_orientation ori; |
|
filler top_filler, bottom_filler; |
|
any_function<void()> scroll_handler; |
|
|
|
long pos; |
|
long max_pos; |
|
long js; |
|
|
|
timer<scroll_bar> b1_timer; |
|
timer<scroll_bar> b2_timer; |
|
timer<scroll_bar> top_filler_timer; |
|
timer<scroll_bar> bottom_filler_timer; |
|
long delayed_pos; |
|
std::unique_ptr<scroll_bar_style> style; |
|
|
|
|
|
scroll_bar(scroll_bar&); |
|
scroll_bar& operator=(scroll_bar&); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class menu_item |
|
{ |
|
public: |
|
virtual ~menu_item() {} |
|
|
|
virtual rectangle get_left_size ( |
|
) const { return rectangle(); } |
|
virtual rectangle get_middle_size ( |
|
) const = 0; |
|
virtual rectangle get_right_size ( |
|
) const { return rectangle(); } |
|
|
|
virtual unichar get_hot_key ( |
|
) const { return 0; } |
|
|
|
virtual void draw_background ( |
|
const canvas& , |
|
const rectangle& , |
|
const bool , |
|
const bool |
|
) const {} |
|
|
|
virtual void draw_left ( |
|
const canvas& , |
|
const rectangle& , |
|
const bool , |
|
const bool |
|
) const {} |
|
|
|
virtual void draw_middle ( |
|
const canvas& , |
|
const rectangle& , |
|
const bool , |
|
const bool |
|
) const = 0; |
|
|
|
virtual void draw_right ( |
|
const canvas& , |
|
const rectangle& , |
|
const bool , |
|
const bool |
|
) const {} |
|
|
|
virtual void on_click ( |
|
) const {} |
|
|
|
virtual bool has_click_event ( |
|
) const { return false; } |
|
|
|
}; |
|
|
|
|
|
|
|
class menu_item_submenu : public menu_item |
|
{ |
|
void initialize ( |
|
unichar hk |
|
) |
|
{ |
|
const dlib::ustring &str = text; |
|
if (hk != 0) |
|
{ |
|
std::string::size_type pos = str.find_first_of(hk); |
|
if (pos != std::string::npos) |
|
{ |
|
|
|
rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos); |
|
rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1); |
|
|
|
underline_p1.x() = r1.left()+1; |
|
underline_p2.x() = r2.left()-1; |
|
underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2; |
|
underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2; |
|
} |
|
} |
|
} |
|
public: |
|
menu_item_submenu ( |
|
const std::string& str, |
|
unichar hk = 0 |
|
) : |
|
text(convert_wstring_to_utf32(convert_mbstring_to_wstring(str))), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(hk); |
|
} |
|
|
|
menu_item_submenu ( |
|
const std::wstring& str, |
|
unichar hk = 0 |
|
) : |
|
text(convert_wstring_to_utf32(str)), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(hk); |
|
} |
|
|
|
menu_item_submenu ( |
|
const dlib::ustring& str, |
|
unichar hk = 0 |
|
) : |
|
text(str), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(hk); |
|
} |
|
|
|
virtual unichar get_hot_key ( |
|
) const { return hotkey; } |
|
|
|
virtual rectangle get_middle_size ( |
|
) const |
|
{ |
|
unsigned long width, height; |
|
f->compute_size(text,width,height); |
|
return rectangle(width+30,height); |
|
} |
|
|
|
virtual rectangle get_right_size ( |
|
) const |
|
{ |
|
return rectangle(15, 5); |
|
} |
|
|
|
virtual void draw_background ( |
|
const canvas& c, |
|
const rectangle& rect, |
|
const bool enabled, |
|
const bool is_selected |
|
) const |
|
{ |
|
if (c.intersect(rect).is_empty()) |
|
return; |
|
|
|
if (enabled && is_selected) |
|
{ |
|
fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100)); |
|
draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100)); |
|
} |
|
} |
|
|
|
virtual void draw_right ( |
|
const canvas& c, |
|
const rectangle& rect, |
|
const bool enabled, |
|
const bool |
|
) const |
|
{ |
|
if (c.intersect(rect).is_empty()) |
|
return; |
|
|
|
unsigned char color = 0; |
|
|
|
if (enabled == false) |
|
color = 128; |
|
|
|
long x, y; |
|
x = rect.right() - 7; |
|
y = rect.top() + rect.height()/2; |
|
|
|
for ( unsigned long i = 0; i < 5; ++i) |
|
draw_line (c, point(x - i, y + i), point(x - i, y - i), color); |
|
} |
|
|
|
virtual void draw_middle ( |
|
const canvas& c, |
|
const rectangle& rect, |
|
const bool enabled, |
|
const bool |
|
) const |
|
{ |
|
if (c.intersect(rect).is_empty()) |
|
return; |
|
|
|
if (enabled) |
|
{ |
|
f->draw_string(c,rect,text); |
|
} |
|
else |
|
{ |
|
f->draw_string(c,rect,text,128); |
|
} |
|
|
|
if (underline_p1 != underline_p2) |
|
{ |
|
point base(rect.left(),rect.top()); |
|
draw_line(c, base+underline_p1, base+underline_p2); |
|
} |
|
} |
|
|
|
private: |
|
dlib::ustring text; |
|
const std::shared_ptr<font> f; |
|
any_function<void()> action; |
|
unichar hotkey; |
|
point underline_p1; |
|
point underline_p2; |
|
}; |
|
|
|
|
|
|
|
class menu_item_text : public menu_item |
|
{ |
|
void initialize ( |
|
const any_function<void()>& event_handler_, |
|
unichar hk |
|
) |
|
{ |
|
dlib::ustring &str = text; |
|
action = event_handler_; |
|
|
|
if (hk != 0) |
|
{ |
|
std::string::size_type pos = str.find_first_of(hk); |
|
if (pos != std::string::npos) |
|
{ |
|
|
|
rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos); |
|
rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1); |
|
|
|
underline_p1.x() = r1.left()+1; |
|
underline_p2.x() = r2.left()-1; |
|
underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2; |
|
underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2; |
|
} |
|
} |
|
} |
|
|
|
public: |
|
template <typename T> |
|
menu_item_text ( |
|
const std::string& str, |
|
T& object, |
|
void (T::*event_handler_)(), |
|
unichar hk = 0 |
|
) : |
|
text(convert_wstring_to_utf32(convert_mbstring_to_wstring(str))), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(make_mfp(object, event_handler_), hk); |
|
} |
|
|
|
menu_item_text ( |
|
const std::string& str, |
|
const any_function<void()>& event_handler_, |
|
unichar hk = 0 |
|
) : |
|
text(convert_wstring_to_utf32(convert_mbstring_to_wstring(str))), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(event_handler_, hk); |
|
} |
|
|
|
template <typename T> |
|
menu_item_text ( |
|
const std::wstring& str, |
|
T& object, |
|
void (T::*event_handler_)(), |
|
unichar hk = 0 |
|
) : |
|
text(convert_wstring_to_utf32(str)), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(make_mfp(object, event_handler_), hk); |
|
} |
|
|
|
menu_item_text ( |
|
const std::wstring& str, |
|
const any_function<void()>& event_handler_, |
|
unichar hk = 0 |
|
) : |
|
text(convert_wstring_to_utf32(str)), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(event_handler_, hk); |
|
} |
|
|
|
template <typename T> |
|
menu_item_text ( |
|
const dlib::ustring& str, |
|
T& object, |
|
void (T::*event_handler_)(), |
|
unichar hk = 0 |
|
) : |
|
text(str), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(make_mfp(object, event_handler_), hk); |
|
} |
|
|
|
menu_item_text ( |
|
const dlib::ustring& str, |
|
const any_function<void()>& event_handler_, |
|
unichar hk = 0 |
|
) : |
|
text(str), |
|
f(default_font::get_font()), |
|
hotkey(hk) |
|
{ |
|
initialize(event_handler_, hk); |
|
} |
|
|
|
virtual unichar get_hot_key ( |
|
) const { return hotkey; } |
|
|
|
virtual rectangle get_middle_size ( |
|
) const |
|
{ |
|
unsigned long width, height; |
|
f->compute_size(text,width,height); |
|
return rectangle(width,height); |
|
} |
|
|
|
virtual void draw_background ( |
|
const canvas& c, |
|
const rectangle& rect, |
|
const bool enabled, |
|
const bool is_selected |
|
) const |
|
{ |
|
if (c.intersect(rect).is_empty()) |
|
return; |
|
|
|
if (enabled && is_selected) |
|
{ |
|
fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100)); |
|
draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100)); |
|
} |
|
} |
|
|
|
virtual void draw_middle ( |
|
const canvas& c, |
|
const rectangle& rect, |
|
const bool enabled, |
|
const bool |
|
) const |
|
{ |
|
if (c.intersect(rect).is_empty()) |
|
return; |
|
|
|
unsigned char color = 0; |
|
|
|
if (enabled == false) |
|
color = 128; |
|
|
|
f->draw_string(c,rect,text,color); |
|
|
|
if (underline_p1 != underline_p2) |
|
{ |
|
point base(rect.left(),rect.top()); |
|
draw_line(c, base+underline_p1, base+underline_p2, color); |
|
} |
|
} |
|
|
|
virtual void on_click ( |
|
) const |
|
{ |
|
action(); |
|
} |
|
|
|
virtual bool has_click_event ( |
|
) const { return true; } |
|
|
|
private: |
|
dlib::ustring text; |
|
const std::shared_ptr<font> f; |
|
any_function<void()> action; |
|
unichar hotkey; |
|
point underline_p1; |
|
point underline_p2; |
|
}; |
|
|
|
|
|
|
|
class menu_item_separator : public menu_item |
|
{ |
|
public: |
|
virtual rectangle get_middle_size ( |
|
) const |
|
{ |
|
return rectangle(10,4); |
|
} |
|
|
|
virtual void draw_background ( |
|
const canvas& c, |
|
const rectangle& rect, |
|
const bool , |
|
const bool |
|
) const |
|
{ |
|
if (c.intersect(rect).is_empty()) |
|
return; |
|
|
|
point p1(rect.left(),rect.top()+rect.height()/2-1); |
|
point p2(rect.right(),rect.top()+rect.height()/2-1); |
|
|
|
point p3(rect.left(),rect.top()+rect.height()/2); |
|
point p4(rect.right(),rect.top()+rect.height()/2); |
|
draw_line(c, p1,p2,128); |
|
draw_line(c, p3,p4,255); |
|
} |
|
|
|
virtual void draw_middle ( |
|
const canvas& , |
|
const rectangle& , |
|
const bool , |
|
const bool |
|
) const |
|
{ |
|
} |
|
}; |
|
|
|
|
|
|
|
class popup_menu : public base_window |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
popup_menu ( |
|
); |
|
|
|
template < |
|
typename menu_item_type |
|
> |
|
unsigned long add_menu_item ( |
|
const menu_item_type& new_item |
|
) |
|
{ |
|
auto_mutex M(wm); |
|
bool t = true; |
|
std::unique_ptr<menu_item> item(new menu_item_type(new_item)); |
|
items.push_back(item); |
|
item_enabled.push_back(t); |
|
|
|
|
|
rectangle left = new_item.get_left_size(); |
|
rectangle middle = new_item.get_middle_size(); |
|
rectangle right = new_item.get_right_size(); |
|
|
|
bool recalc_rect_positions = false; |
|
const rectangle all = left+middle+right; |
|
|
|
|
|
|
|
if (left.width() > left_width) |
|
{ |
|
left_width = left.width(); |
|
recalc_rect_positions = true; |
|
} |
|
|
|
if (middle.width() > middle_width) |
|
{ |
|
middle_width = middle.width(); |
|
recalc_rect_positions = true; |
|
} |
|
|
|
|
|
if (cur_rect.width() < left_width + middle_width + right.width() + 2*item_pad) |
|
{ |
|
cur_rect = resize_rect_width(cur_rect, left_width + middle_width + right.width() + 2*item_pad); |
|
recalc_rect_positions = true; |
|
} |
|
|
|
const long y = cur_rect.bottom()+1 + item_pad; |
|
const long x = cur_rect.left() + item_pad; |
|
|
|
|
|
cur_rect.set_bottom(cur_rect.bottom()+all.height() + 2*item_pad); |
|
|
|
|
|
|
|
if (recalc_rect_positions) |
|
{ |
|
long y = cur_rect.top() + item_pad; |
|
for (unsigned long i = 0; i < left_rects.size(); ++i) |
|
{ |
|
middle_rects[i] = move_rect(middle_rects[i], x+left_width, y); |
|
right_rects[i] = move_rect(right_rects[i], x+cur_rect.width()-right_rects[i].width()-item_pad, y); |
|
line_rects[i] = resize_rect_width(line_rects[i], cur_rect.width()); |
|
|
|
y += line_rects[i].height(); |
|
} |
|
} |
|
|
|
|
|
|
|
left = move_rect(left,x,y); |
|
middle = move_rect(middle,x+left_width,y); |
|
right = move_rect(right,x+cur_rect.width()-right.width()-item_pad,y); |
|
rectangle line(move_rect(rectangle(cur_rect.width(),all.height()+2*item_pad), x-item_pad, y-item_pad)); |
|
|
|
|
|
|
|
if (left.height() < all.height()) |
|
left = translate_rect(left,0, (all.height()-left.height())/2); |
|
if (middle.height() < all.height()) |
|
middle = translate_rect(middle,0, (all.height()-middle.height())/2); |
|
if (right.height() < all.height()) |
|
right = translate_rect(right,0, (all.height()-right.height())/2); |
|
|
|
left_rects.push_back(left); |
|
middle_rects.push_back(middle); |
|
right_rects.push_back(right); |
|
line_rects.push_back(line); |
|
|
|
popup_menu* junk = 0; |
|
submenus.push_back(junk); |
|
|
|
win_rect.set_right(cur_rect.right()+pad); |
|
win_rect.set_bottom(cur_rect.bottom()+pad); |
|
set_size(win_rect.width(),win_rect.height()); |
|
|
|
|
|
selected_item = submenus.size(); |
|
|
|
return items.size()-1; |
|
} |
|
|
|
template < |
|
typename menu_item_type |
|
> |
|
unsigned long add_submenu ( |
|
const menu_item_type& new_item, |
|
popup_menu& submenu |
|
) |
|
{ |
|
auto_mutex M(wm); |
|
|
|
submenus[add_menu_item(new_item)] = &submenu; |
|
|
|
submenu.set_on_hide_handler(*this,&popup_menu::on_submenu_hide); |
|
|
|
return items.size()-1; |
|
} |
|
|
|
void enable_menu_item ( |
|
unsigned long idx |
|
); |
|
|
|
void disable_menu_item ( |
|
unsigned long idx |
|
); |
|
|
|
size_t size ( |
|
) const; |
|
|
|
void clear ( |
|
); |
|
|
|
void show ( |
|
); |
|
|
|
void hide ( |
|
); |
|
|
|
template <typename T> |
|
void set_on_hide_handler ( |
|
T& object, |
|
void (T::*event_handler)() |
|
) |
|
{ |
|
auto_mutex M(wm); |
|
|
|
member_function_pointer<> temp; |
|
temp.set(object,event_handler); |
|
|
|
|
|
bool found_handler = false; |
|
for (unsigned long i = 0; i < hide_handlers.size(); ++i) |
|
{ |
|
if (hide_handlers[i] == temp) |
|
{ |
|
found_handler = true; |
|
break; |
|
} |
|
} |
|
|
|
if (found_handler == false) |
|
{ |
|
hide_handlers.push_back(temp); |
|
} |
|
} |
|
|
|
void select_first_item ( |
|
); |
|
|
|
bool forwarded_on_keydown ( |
|
unsigned long key, |
|
bool is_printable, |
|
unsigned long state |
|
); |
|
|
|
private: |
|
|
|
void on_submenu_hide ( |
|
); |
|
|
|
void on_window_resized( |
|
); |
|
|
|
void on_mouse_up ( |
|
unsigned long btn, |
|
unsigned long, |
|
long x, |
|
long y |
|
); |
|
|
|
void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
void close_submenu ( |
|
); |
|
|
|
bool display_selected_submenu ( |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void on_mouse_leave ( |
|
); |
|
|
|
void paint ( |
|
const canvas& c |
|
); |
|
|
|
const long pad; |
|
const long item_pad; |
|
rectangle cur_rect; |
|
rectangle win_rect; |
|
unsigned long left_width; |
|
unsigned long middle_width; |
|
array<std::unique_ptr<menu_item> > items; |
|
array<bool> item_enabled; |
|
array<rectangle> left_rects; |
|
array<rectangle> middle_rects; |
|
array<rectangle> right_rects; |
|
array<rectangle> line_rects; |
|
array<popup_menu*> submenus; |
|
unsigned long selected_item; |
|
bool submenu_open; |
|
array<member_function_pointer<> > hide_handlers; |
|
|
|
|
|
popup_menu(popup_menu&); |
|
popup_menu& operator=(popup_menu&); |
|
}; |
|
|
|
|
|
|
|
class zoomable_region : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
zoomable_region ( |
|
drawable_window& w, |
|
unsigned long events = 0 |
|
); |
|
|
|
virtual ~zoomable_region ( |
|
)= 0; |
|
|
|
virtual 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_)); |
|
hsb.set_style(style_.get_horizontal_scroll_bar_style()); |
|
vsb.set_style(style_.get_vertical_scroll_bar_style()); |
|
|
|
|
|
set_size(rect.width(), rect.height()); |
|
} |
|
|
|
void set_zoom_increment ( |
|
double zi |
|
); |
|
|
|
double zoom_increment ( |
|
) const; |
|
|
|
void set_max_zoom_scale ( |
|
double ms |
|
); |
|
|
|
void set_min_zoom_scale ( |
|
double ms |
|
); |
|
|
|
double min_zoom_scale ( |
|
) const; |
|
|
|
double max_zoom_scale ( |
|
) const; |
|
|
|
virtual void set_size ( |
|
unsigned long width, |
|
unsigned long height |
|
); |
|
|
|
void show ( |
|
); |
|
|
|
void hide ( |
|
); |
|
|
|
void enable ( |
|
); |
|
|
|
void disable ( |
|
); |
|
|
|
void set_z_order ( |
|
long order |
|
); |
|
|
|
protected: |
|
|
|
virtual void on_view_changed () {} |
|
|
|
point graph_to_gui_space ( |
|
const vector<double,2>& p |
|
) const; |
|
|
|
vector<double,2> gui_to_graph_space ( |
|
const point& p |
|
) const; |
|
|
|
point max_graph_point ( |
|
) const; |
|
|
|
rectangle display_rect ( |
|
) const; |
|
|
|
double zoom_scale ( |
|
) const; |
|
|
|
void set_zoom_scale ( |
|
double new_scale |
|
); |
|
|
|
void center_display_at_graph_point ( |
|
const vector<double,2>& p |
|
); |
|
|
|
|
|
|
|
void on_wheel_down ( |
|
unsigned long state |
|
); |
|
|
|
void on_wheel_up ( |
|
unsigned long state |
|
); |
|
|
|
void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
void on_mouse_up ( |
|
unsigned long btn, |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
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 on_h_scroll ( |
|
); |
|
|
|
void on_v_scroll ( |
|
); |
|
|
|
void redraw_graph ( |
|
); |
|
|
|
void adjust_origin ( |
|
const point& gui_p, |
|
const vector<double,2>& graph_p |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<double,2> gr_orig; |
|
vector<double,2> lr_point; |
|
|
|
mutable std::ostringstream sout; |
|
|
|
double scale; |
|
double min_scale; |
|
double max_scale; |
|
double zoom_increment_; |
|
rectangle display_rect_; |
|
|
|
bool mouse_drag_screen; |
|
vector<double,2> drag_screen_point; |
|
|
|
scroll_bar vsb; |
|
scroll_bar hsb; |
|
|
|
std::unique_ptr<scrollable_region_style> style; |
|
|
|
|
|
zoomable_region(zoomable_region&); |
|
zoomable_region& operator=(zoomable_region&); |
|
|
|
}; |
|
|
|
|
|
|
|
class scrollable_region : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
scrollable_region ( |
|
drawable_window& w, |
|
unsigned long events = 0 |
|
); |
|
|
|
virtual ~scrollable_region ( |
|
) = 0; |
|
|
|
template < |
|
typename style_type |
|
> |
|
void set_style ( |
|
const style_type& style_ |
|
) |
|
{ |
|
auto_mutex M(m); |
|
style.reset(new style_type(style_)); |
|
hsb.set_style(style_.get_horizontal_scroll_bar_style()); |
|
vsb.set_style(style_.get_vertical_scroll_bar_style()); |
|
|
|
|
|
set_size(rect.width(), rect.height()); |
|
} |
|
|
|
void show ( |
|
); |
|
|
|
void hide ( |
|
); |
|
|
|
void enable ( |
|
); |
|
|
|
void disable ( |
|
); |
|
|
|
void set_z_order ( |
|
long order |
|
); |
|
|
|
virtual void set_size ( |
|
unsigned long width, |
|
unsigned long height |
|
); |
|
|
|
unsigned long horizontal_mouse_wheel_scroll_increment ( |
|
) const; |
|
|
|
unsigned long vertical_mouse_wheel_scroll_increment ( |
|
) const; |
|
|
|
void set_horizontal_mouse_wheel_scroll_increment ( |
|
unsigned long inc |
|
); |
|
|
|
void set_vertical_mouse_wheel_scroll_increment ( |
|
unsigned long inc |
|
); |
|
|
|
unsigned long horizontal_scroll_increment ( |
|
) const; |
|
|
|
unsigned long vertical_scroll_increment ( |
|
) const; |
|
|
|
void set_horizontal_scroll_increment ( |
|
unsigned long inc |
|
); |
|
|
|
void set_vertical_scroll_increment ( |
|
unsigned long inc |
|
); |
|
|
|
long horizontal_scroll_pos ( |
|
) const; |
|
|
|
long vertical_scroll_pos ( |
|
) const; |
|
|
|
void set_horizontal_scroll_pos ( |
|
long pos |
|
); |
|
|
|
void set_vertical_scroll_pos ( |
|
long pos |
|
); |
|
|
|
virtual void set_pos ( |
|
long x, |
|
long y |
|
); |
|
|
|
bool mouse_drag_enabled ( |
|
) const; |
|
|
|
void enable_mouse_drag ( |
|
); |
|
|
|
void disable_mouse_drag ( |
|
); |
|
|
|
protected: |
|
|
|
virtual void on_view_changed () {} |
|
|
|
const rectangle& display_rect ( |
|
) const; |
|
|
|
void set_total_rect_size ( |
|
unsigned long width, |
|
unsigned long height |
|
); |
|
|
|
const rectangle& total_rect ( |
|
) const; |
|
|
|
void scroll_to_rect ( |
|
const rectangle& r_ |
|
); |
|
|
|
void on_wheel_down ( |
|
unsigned long state |
|
); |
|
|
|
void on_mouse_move ( |
|
unsigned long state, |
|
long x, |
|
long y |
|
); |
|
|
|
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_wheel_up ( |
|
unsigned long state |
|
); |
|
|
|
void draw ( |
|
const canvas& c |
|
) const; |
|
|
|
private: |
|
|
|
bool need_h_scroll ( |
|
) const; |
|
|
|
bool need_v_scroll ( |
|
) const; |
|
|
|
void on_h_scroll ( |
|
); |
|
|
|
void on_v_scroll ( |
|
); |
|
|
|
rectangle total_rect_; |
|
rectangle display_rect_; |
|
scroll_bar hsb; |
|
scroll_bar vsb; |
|
unsigned long hscroll_bar_inc; |
|
unsigned long vscroll_bar_inc; |
|
unsigned long h_wheel_scroll_bar_inc; |
|
unsigned long v_wheel_scroll_bar_inc; |
|
bool mouse_drag_enabled_; |
|
bool user_is_dragging_mouse; |
|
point drag_origin; |
|
std::unique_ptr<scrollable_region_style> style; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class popup_menu_region : public drawable |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
popup_menu_region( |
|
drawable_window& w |
|
); |
|
|
|
virtual ~popup_menu_region( |
|
); |
|
|
|
void set_size ( |
|
unsigned long width, |
|
unsigned long height |
|
); |
|
|
|
void set_rect ( |
|
const rectangle& new_rect |
|
); |
|
|
|
popup_menu& menu ( |
|
); |
|
|
|
void hide ( |
|
); |
|
|
|
void disable ( |
|
); |
|
|
|
bool popup_menu_visible ( |
|
) const { auto_mutex M(m); return popup_menu_shown; } |
|
|
|
protected: |
|
|
|
void on_keydown ( |
|
unsigned long key, |
|
bool is_printable, |
|
unsigned long state |
|
); |
|
|
|
void on_focus_lost ( |
|
); |
|
|
|
void on_focus_gained ( |
|
); |
|
|
|
void on_window_moved( |
|
); |
|
|
|
void on_mouse_down ( |
|
unsigned long btn, |
|
unsigned long state, |
|
long x, |
|
long y, |
|
bool is_double_click |
|
); |
|
|
|
void on_menu_becomes_hidden ( |
|
); |
|
|
|
void draw ( |
|
const canvas& |
|
) const; |
|
|
|
private: |
|
|
|
popup_menu menu_; |
|
bool popup_menu_shown; |
|
|
|
|
|
popup_menu_region(popup_menu_region&); |
|
popup_menu_region& operator=(popup_menu_region&); |
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
#ifdef NO_MAKEFILE |
|
#include "base_widgets.cpp" |
|
#endif |
|
|
|
#endif |
|
|
|
|