Commit 9db0ca77 authored by Davis King's avatar Davis King

Cleaned up the list_box's objects code by making it use the scrollable_region widget.

Also gave the list_box a user settable style.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402598
parent 1fc2b4e1
...@@ -577,6 +577,139 @@ namespace dlib ...@@ -577,6 +577,139 @@ namespace dlib
}; };
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// list_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class list_box_style
{
public:
virtual ~list_box_style() {}
virtual void draw_list_box_background (
const canvas& c,
const rectangle& display_rect,
const bool enabled
) const = 0;
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const std::string& text,
const bool is_selected
) const = 0;
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const std::wstring& text,
const bool is_selected
) const = 0;
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const ustring& text,
const bool is_selected
) const = 0;
};
// ----------------------------------------------------------------------------------------
class list_box_style_default : public list_box_style
{
public:
scrollable_region_style_default get_scrollable_region_style (
) const { return scrollable_region_style_default(); }
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const std::string& text,
const bool is_selected
) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const std::wstring& text,
const bool is_selected
) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const ustring& text,
const bool is_selected
) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }
template <typename string_type>
void draw_list_box_item_template (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const string_type& text,
const bool is_selected
) const
{
if (is_selected)
{
if (enabled)
fill_rect_with_vertical_gradient(c,rect,rgb_pixel(110,160,255), rgb_pixel(100,130,250),display_rect);
else
fill_rect_with_vertical_gradient(c,rect,rgb_pixel(140,190,255), rgb_pixel(130,160,250),display_rect);
}
if (enabled)
mfont.draw_string(c,rect,text,rgb_pixel(0,0,0),0,std::string::npos,display_rect);
else
mfont.draw_string(c,rect,text,rgb_pixel(128,128,128),0,std::string::npos,display_rect);
}
virtual void draw_list_box_background (
const canvas& c,
const rectangle& display_rect,
const bool enabled
) const
{
if (enabled)
{
// first fill our area with white
fill_rect(c, display_rect,rgb_pixel(255,255,255));
}
else
{
// first fill our area with gray
fill_rect(c, display_rect,rgb_pixel(212,208,200));
}
}
};
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
} }
......
...@@ -499,6 +499,110 @@ namespace dlib ...@@ -499,6 +499,110 @@ namespace dlib
!*/ !*/
}; };
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// list_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
class list_box_style
{
/*!
WHAT THIS OBJECT REPRESENTS
This is an abstract class that defines the interface a
list_box style object must implement.
Note that derived classes must be copyable via
their copy constructors.
!*/
public:
virtual ~list_box_style() {}
virtual void draw_list_box_background (
const canvas& c,
const rectangle& display_rect,
const bool enabled
) const = 0;
/*!
requires
- the mutex drawable::m is locked
- c == the canvas to draw on
- display_rect == the display_rect for the list_box. This is the area
in which list box items are drawn (see display_rect in the scrollable_region
widget for more info)
- enabled == true if the list box is enabled
ensures
- draws the background of a list box on the canvas c at the location given
by display_rect.
!*/
scrollable_region_style_type get_scrollable_region_style (
) const;
/*!
ensures
- returns the style of scrollable_region to use for the
list_box.
!*/
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const std::string& text,
const bool is_selected
) const = 0;
/*!
requires
- the mutex drawable::m is locked
- c == the canvas to draw on
- rect == the rectangle that defines where on the screen this list box item is.
- display_rect == the display_rect for the list_box. This is the area
in which list box items are drawn (see display_rect in the scrollable_region
widget for more info)
- mfont == the font to use to draw the list box item
- text == the text of the list box item to be drawn
- enabled == true if the list box is enabled
- is_selected == true if the item is to be drawn in a selected state
ensures
- draws the list box item on the canvas c at the location given by rect.
!*/
// wide character overloads
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const std::wstring& text,
const bool is_selected
) const = 0;
virtual void draw_list_box_item (
const canvas& c,
const rectangle& rect,
const rectangle& display_rect,
const bool enabled,
const font& mfont,
const ustring& text,
const bool is_selected
) const = 0;
};
// ----------------------------------------------------------------------------------------
class list_box_style_default : public list_box_style
{
public:
/*!
This is the default style for list_box objects.
!*/
};
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
} }
......
...@@ -2109,17 +2109,13 @@ namespace dlib ...@@ -2109,17 +2109,13 @@ namespace dlib
list_box( list_box(
drawable_window& w drawable_window& w
) : ) :
drawable(w,MOUSE_WHEEL|MOUSE_CLICK), scrollable_region(w,MOUSE_WHEEL|MOUSE_CLICK),
ms_enabled(false), ms_enabled(false),
pos(0), last_selected(0)
text_start(0), {
last_selected(0), set_vertical_scroll_increment(mfont->height());
sbv(w,scroll_bar::VERTICAL),
sbh(w,scroll_bar::HORIZONTAL) style.reset(new list_box_style_default());
{
adjust_sliders();
sbv.set_scroll_handler(*this,&list_box::sbv_handler);
sbh.set_scroll_handler(*this,&list_box::sbh_handler);
enable_events(); enable_events();
} }
...@@ -2149,30 +2145,10 @@ namespace dlib ...@@ -2149,30 +2145,10 @@ namespace dlib
{ {
mfont->compute_size(items[i].name,items[i].width, items[i].height); mfont->compute_size(items[i].name,items[i].width, items[i].height);
} }
adjust_sliders(); set_vertical_scroll_increment(mfont->height());
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
} }
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
set_size (
unsigned long width_,
unsigned long height_
)
{
auto_mutex M(m);
rectangle old(rect);
const long x = rect.left();
const long y = rect.top();
rect.set_right(x+width_-1);
rect.set_bottom(y+height_-1);
adjust_sliders();
parent.invalidate_rectangle(rect+old);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template <typename S> template <typename S>
...@@ -2364,242 +2340,32 @@ namespace dlib ...@@ -2364,242 +2340,32 @@ namespace dlib
const canvas& c const canvas& c
) const ) const
{ {
rectangle area = rect.intersect(c); scrollable_region::draw(c);
rectangle area = display_rect().intersect(c);
if (area.is_empty()) if (area.is_empty())
return; return;
if (enabled) style->draw_list_box_background(c, display_rect(), enabled);
{
// first fill our area with white
fill_rect(c, area,rgb_pixel(255,255,255));
}
else
{
// first fill our area with gray
fill_rect(c, area,rgb_pixel(212,208,200));
}
draw_sunken_rectangle(c, rect);
long y = text_area.top();
long x = text_area.left();
for (unsigned long i = pos; i < items.size(); ++i)
{
rectangle r(x-(long)text_start,y,text_area.right(),y+items[i].height);
rectangle draw_area(x,y,text_area.right(),y+items[i].height);
draw_area = draw_area.intersect(text_area);
if (draw_area.is_empty())
break;
if (items[i].is_selected)
{
if (enabled)
fill_rect_with_vertical_gradient(c,draw_area,rgb_pixel(110,160,255), rgb_pixel(100,130,250));
else
fill_rect_with_vertical_gradient(c,draw_area,rgb_pixel(140,190,255), rgb_pixel(130,160,250));
}
if (enabled)
mfont->draw_string(c,r,items[i].name,rgb_pixel(0,0,0),0,std::string::npos,draw_area);
else
mfont->draw_string(c,r,items[i].name,rgb_pixel(128,128,128),0,std::string::npos,draw_area);
y += items[i].height;
if (y > area.bottom())
break;
}
}
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
hide (
)
{
auto_mutex M(m);
sbv.hide();
sbh.hide();
drawable::hide();
}
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
show (
)
{
auto_mutex M(m);
hidden = false;
adjust_sliders();
drawable::show();
}
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
disable (
)
{
sbv.disable();
sbh.disable();
drawable::disable();
}
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
enable (
)
{
sbv.enable();
sbh.enable();
drawable::enable();
}
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
set_pos (
long x,
long y
)
{
auto_mutex M(m);
drawable::set_pos(x,y);
adjust_sliders();
}
// ---------------------------------------------------------------------------------------- long y = total_rect().top();
template <typename S>
void list_box<S>::
adjust_sliders (
)
{
text_area = rectangle(rect.left()+2,rect.top()+2,rect.right()-1,rect.bottom()-1);
int extra_count = 0;
// find the max width and height of our text
unsigned long maxw = 0, maxh = 0;
for (unsigned long i = 0; i < items.size(); ++i) for (unsigned long i = 0; i < items.size(); ++i)
{ {
maxh += items[i].height; if (y+(long)items[i].height <= area.top())
if (maxh > text_area.height())
++extra_count;
if (items[i].width > maxw )
maxw = items[i].width;
}
if (maxh > text_area.height() && text_area.is_empty() == false)
{
if (!hidden)
sbv.show();
sbv.set_pos(rect.right()-sbv.width()-pad+1,rect.top()+pad);
sbv.set_length(rect.height()-pad*2);
text_area.set_right(text_area.right()-sbv.width()-1);
if (maxw > text_area.width())
{
if (!hidden)
sbh.show();
sbh.set_pos(rect.left()+pad,rect.bottom()-sbh.height()-pad+1);
sbh.set_length(rect.width()-pad*2 - sbv.width());
text_area.set_bottom(text_area.bottom()-sbh.height()-1);
sbh.set_max_slider_pos(maxw - text_area.width());
++extra_count;
}
else
{
sbh.hide();
}
sbv.set_max_slider_pos(extra_count);
}
else
{
sbv.hide();
pos = 0;
sbv.set_max_slider_pos(0);
if (maxw > text_area.width() && text_area.is_empty() == false)
{
if (!hidden)
sbh.show();
sbh.set_pos(rect.left()+pad,rect.bottom()-sbh.height()-pad+1);
sbh.set_length(rect.width()-pad*2);
text_area.set_bottom(text_area.bottom()-sbh.height()-1);
sbh.set_max_slider_pos(maxw - text_area.width());
}
else
{
sbh.hide();
}
}
}
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
sbh_handler (
)
{ {
text_start = sbh.slider_pos(); y += items[i].height;
parent.invalidate_rectangle(rect); continue;
} }
// ---------------------------------------------------------------------------------------- rectangle r(total_rect().left(), y, display_rect().right(), y+items[i].height-1);
template <typename S>
void list_box<S>::
sbv_handler (
)
{
pos = sbv.slider_pos();
parent.invalidate_rectangle(rect);
}
// ---------------------------------------------------------------------------------------- style->draw_list_box_item(c,r, display_rect(), enabled, *mfont, items[i].name, items[i].is_selected);
template <typename S>
void list_box<S>::
on_wheel_up (
unsigned long state
)
{
if (rect.contains(lastx,lasty) && enabled && !hidden)
{
long new_pos = sbv.slider_pos();
if (new_pos > 0)
{
pos = new_pos-1;
sbv.set_slider_pos(pos);
parent.invalidate_rectangle(rect);
}
}
}
// ---------------------------------------------------------------------------------------- y += items[i].height;
template <typename S> if (y > area.bottom())
void list_box<S>:: break;
on_wheel_down (
unsigned long state
)
{
if (rect.contains(lastx,lasty) && enabled && !hidden)
{
long new_pos = sbv.slider_pos();
if (new_pos < sbv.max_slider_pos())
{
pos = new_pos+1;
sbv.set_slider_pos(pos);
parent.invalidate_rectangle(rect);
}
} }
} }
...@@ -2615,7 +2381,7 @@ namespace dlib ...@@ -2615,7 +2381,7 @@ namespace dlib
bool is_double_click bool is_double_click
) )
{ {
if (text_area.contains(x,y) && btn == base_window::LEFT && enabled && !hidden ) if (display_rect().contains(x,y) && btn == base_window::LEFT && enabled && !hidden )
{ {
if ( ms_enabled == false || if ( ms_enabled == false ||
(!(state&base_window::CONTROL)) && !(state&base_window::SHIFT)) (!(state&base_window::CONTROL)) && !(state&base_window::SHIFT))
...@@ -2627,9 +2393,9 @@ namespace dlib ...@@ -2627,9 +2393,9 @@ namespace dlib
} }
} }
y -= text_area.top(); y -= total_rect().top();
long h = 0; long h = 0;
for (unsigned long i = pos; i < items.size(); ++i) for (unsigned long i = 0; i < items.size(); ++i)
{ {
h += items[i].height; h += items[i].height;
if (h >= y) if (h >= y)
...@@ -2679,19 +2445,6 @@ namespace dlib ...@@ -2679,19 +2445,6 @@ namespace dlib
} }
} }
// ----------------------------------------------------------------------------------------
template <typename S>
void list_box<S>::
set_z_order (
long order
)
{
sbv.set_z_order(order);
sbh.set_z_order(order);
drawable::set_z_order(order);
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template <typename S> template <typename S>
......
...@@ -1105,34 +1105,24 @@ namespace dlib ...@@ -1105,34 +1105,24 @@ namespace dlib
namespace list_box_helper{ namespace list_box_helper{
template <typename S = std::string> template <typename S = std::string>
class list_box : public drawable, class list_box : public scrollable_region,
public enumerable<const S> public enumerable<const S>
{ {
/*! /*!
INITIAL VALUE INITIAL VALUE
- ms_enabled == false - ms_enabled == false
- items.size() == 0 - items.size() == 0
- pos == 0
- text_start = 0
- last_selected = 0 - last_selected = 0
CONVENTION CONVENTION
- size() == items.size() - size() == items.size()
- (*this)[i] == items[i].name - (*this)[i] == items[i].name
- is_selected(i) == items[i].is_selected - 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].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() - items[i].height == the height of items[i].name as given by font::compute_size()
- items[pos] == the item currently being displayed at the top of the list box
- sbv == our vertical scroll bar
- sbh == our horizontal scroll bar
- text_area == the area that is free to be used for text display (e.g. not occluded
by scroll bars or anything)
- text_start == the amount of pixels the text should be shifted to the left (but the
part outside this widget should be clipped). This is used by the horizontal
scroll bar.
- pos == the first line that is shown in the list box
- last_selected == the last item the user selected - last_selected == the last item the user selected
!*/ !*/
...@@ -1145,16 +1135,6 @@ namespace dlib ...@@ -1145,16 +1135,6 @@ namespace dlib
~list_box( ~list_box(
); );
void set_size (
unsigned long width_,
unsigned long height_
);
void set_pos (
long x,
long y
);
bool is_selected ( bool is_selected (
unsigned long index unsigned long index
) const; ) const;
...@@ -1167,6 +1147,19 @@ namespace dlib ...@@ -1167,6 +1147,19 @@ namespace dlib
unsigned long index 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> template <typename T>
void get_selected ( void get_selected (
T& list T& list
...@@ -1195,15 +1188,22 @@ namespace dlib ...@@ -1195,15 +1188,22 @@ namespace dlib
items.set_max_size(list.size()); items.set_max_size(list.size());
items.set_size(list.size()); items.set_size(list.size());
list.reset(); list.reset();
unsigned long max_width = 0;
unsigned long total_height = 0;
while (list.move_next()) while (list.move_next())
{ {
items[i].is_selected = false; items[i].is_selected = false;
items[i].name = list.element(); items[i].name = list.element();
mfont->compute_size(items[i].name,items[i].width, items[i].height); 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; ++i;
} }
pos = 0; set_total_rect_size(max_width, total_height);
adjust_sliders();
parent.invalidate_rectangle(rect); parent.invalidate_rectangle(rect);
last_selected = 0; last_selected = 0;
} }
...@@ -1258,22 +1258,6 @@ namespace dlib ...@@ -1258,22 +1258,6 @@ namespace dlib
unsigned long size ( unsigned long size (
) const; ) const;
void show(
);
void hide (
);
void enable (
);
void disable (
);
void set_z_order (
long order
);
unsigned long get_selected ( unsigned long get_selected (
) const; ) const;
...@@ -1283,29 +1267,6 @@ namespace dlib ...@@ -1283,29 +1267,6 @@ namespace dlib
private: private:
void sbv_handler (
);
void sbh_handler (
);
void adjust_sliders (
);
/*!
requires
- m is locked
ensures
- adjusts the scroll bars so that they are properly displayed
!*/
void on_wheel_up (
unsigned long state
);
void on_wheel_down (
unsigned long state
);
void on_mouse_down ( void on_mouse_down (
unsigned long btn, unsigned long btn,
unsigned long state, unsigned long state,
...@@ -1327,19 +1288,13 @@ namespace dlib ...@@ -1327,19 +1288,13 @@ namespace dlib
unsigned long height; unsigned long height;
}; };
const static long pad = 2;
bool ms_enabled; bool ms_enabled;
typename array<data<S> >::kernel_2a_c items; typename array<data<S> >::kernel_2a_c items;
member_function_pointer<unsigned long>::kernel_1a event_handler; member_function_pointer<unsigned long>::kernel_1a event_handler;
member_function_pointer<unsigned long>::kernel_1a single_click_event_handler; member_function_pointer<unsigned long>::kernel_1a single_click_event_handler;
unsigned long pos;
unsigned long text_start;
unsigned long last_selected; unsigned long last_selected;
scroll_bar sbv;
scroll_bar sbh;
rectangle text_area;
scoped_ptr<list_box_style> style;
// restricted functions // restricted functions
list_box(list_box&); // copy constructor list_box(list_box&); // copy constructor
......
...@@ -956,7 +956,7 @@ namespace dlib ...@@ -956,7 +956,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
class list_box : public drawable, class list_box : public scrollable_region,
public enumerable<const std::string> public enumerable<const std::string>
{ {
/*! /*!
...@@ -996,6 +996,19 @@ namespace dlib ...@@ -996,6 +996,19 @@ namespace dlib
- all resources associated with *this have been released - all resources associated with *this have been released
!*/ !*/
template <
typename style_type
>
void set_style (
const style_type& style
);
/*!
requires
- style_type == a type that inherits from list_box_style
ensures
- this list_box object will draw itself using the given style
!*/
void set_size ( void set_size (
unsigned long width_, unsigned long width_,
unsigned long height_ unsigned long height_
...@@ -1165,13 +1178,13 @@ namespace dlib ...@@ -1165,13 +1178,13 @@ namespace dlib
list_box& operator=(list_box&); // assignment operator list_box& operator=(list_box&); // assignment operator
}; };
class wlist_box : public drawable, class wlist_box : public scrollable_region,
public enumerable<const std::wstring>; public enumerable<const std::wstring>;
/*! /*!
same as list_box except for std::wstring instead of std::string same as list_box except for std::wstring instead of std::string
!*/ !*/
class ulist_box : public drawable, class ulist_box : public scrollable_region,
public enumerable<const dlib::ustring>; public enumerable<const dlib::ustring>;
/*! /*!
same as list_box except for dlib::ustring instead of std::string same as list_box except for dlib::ustring instead of std::string
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment