A single mesh can now hold multiple parts if they share the same texture.
rebuild();
}
-void Button::rebuild_special(const Part &part, CachedPart &cache)
+void Button::rebuild_special(const Part &part)
{
if(part.get_name()=="text")
- text.build(part, geom, cache);
+ text.build(part, geom, part_cache);
if(part.get_name()=="icon")
{
- cache.texture = icon;
if(icon)
{
Geometry rgeom;
rgeom.h = icon->get_height();
part.get_alignment().apply(rgeom, geom, part.get_margin());
- cache.clear_mesh();
-
- GL::MeshBuilder bld(*cache.mesh);
+ GL::MeshBuilder bld(part_cache.create_mesh(part, *icon));
bld.color(1.0f, 1.0f, 1.0f);
bld.begin(GL::QUADS);
bld.texcoord(0, 0);
void set_icon(const GL::Texture2D *);
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
public:
virtual void button_press(int, int, unsigned);
rebuild();
}
-void Dropdown::rebuild_special(const Part &part, CachedPart &cache)
+void Dropdown::set_selected_index(int index)
+{
+ list.set_selected_index(index);
+ if(index<0)
+ text.set(string());
+}
+
+void Dropdown::rebuild_special(const Part &part)
{
if(part.get_name()=="text")
- {
- int sel = list.get_selected_index();
- if(sel>=0)
- Text(*style, list.get_data().get_string(sel)).build(part, geom, cache);
- else
- cache.texture = 0;
- }
+ text.build(part, geom, part_cache);
+ else
+ Widget::rebuild_special(part);
}
void Dropdown::render_special(const Part &part, GL::Renderer &renderer) const
void Dropdown::on_style_change()
{
+ text.set_style(style);
resize_list();
}
signal_ungrab_pointer.emit();
}
+ text.set(list.get_data().get_string(index));
+
signal_item_selected.emit(index);
rebuild();
}
#include <sigc++/signal.h>
#include "list.h"
+#include "text.h"
#include "widget.h"
namespace Msp {
private:
List list;
bool dropped;
+ Text text;
public:
Dropdown();
ListData &get_data() { return list.get_data(); }
const ListData &get_data() const { return list.get_data(); }
- void set_selected_index(int i) { list.set_selected_index(i); }
+ void set_selected_index(int);
int get_selected_index() const { return list.get_selected_index(); }
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
virtual void render_special(const Part &, GL::Renderer &) const;
public:
}
}
-void Entry::rebuild_special(const Part &part, CachedPart &cache)
+void Entry::rebuild_special(const Part &part)
{
if(part.get_name()=="text")
- text.build(part, geom, first_row, cache);
+ text.build(part, geom, first_row, part_cache);
else if(part.get_name()=="cursor")
{
const Graphic *graphic = part.get_graphic(state);
- if(!text_part || !graphic)
- {
- cache.texture = 0;
+ if(!text_part || !graphic || !graphic->get_texture())
return;
- }
unsigned row, col;
text.offset_to_coords(edit_pos, row, col);
if(row<first_row || row>=first_row+visible_rows)
- {
- cache.texture = 0;
return;
- }
Geometry rgeom = text.coords_to_geometry(*text_part, geom, first_row, row, col);
- cache.texture = graphic->get_texture();
- cache.clear_mesh();
-
- GL::MeshBuilder bld(*cache.mesh);
+ GL::MeshBuilder bld(part_cache.create_mesh(part, *graphic->get_texture()));
bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
graphic->build(part.get_geometry().w, part.get_geometry().h, bld);
}
+ else
+ Widget::rebuild_special(part);
}
void Entry::render_special(const Part &part, GL::Renderer &renderer) const
bool is_multiline() const { return multiline; }
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
virtual void render_special(const Part &, GL::Renderer &) const;
public:
}
}
-void HSlider::rebuild_special(const Part &part, CachedPart &cache)
+void HSlider::rebuild_special(const Part &part)
{
if(part.get_name()=="slider")
{
const Graphic *graphic = part.get_graphic(state);
- if(!graphic)
+ if(!graphic || !graphic->get_texture())
return;
Alignment align = part.get_alignment();
Geometry pgeom = part.get_geometry();
align.apply(pgeom, geom, part.get_margin());
- cache.texture = part.get_graphic(state)->get_texture();
- cache.clear_mesh();
-
- GL::MeshBuilder bld(*cache.mesh);
+ GL::MeshBuilder bld(part_cache.create_mesh(part, *graphic->get_texture()));
bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y, 0);
graphic->build(pgeom.w, pgeom.h, bld);
}
virtual void autosize();
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
public:
virtual void button_press(int, int, unsigned);
rebuild();
}
-void Image::rebuild_special(const Part &part, CachedPart &cache)
+void Image::rebuild_special(const Part &part)
{
if(part.get_name()=="image")
{
if(!image)
- {
- cache.texture = 0;
return;
- }
const Alignment &align = part.get_alignment();
Geometry rgeom = part.get_geometry();
}
}
- cache.texture = image;
- cache.clear_mesh();
-
- GL::MeshBuilder bld(*cache.mesh);
+ GL::MeshBuilder bld(part_cache.create_mesh(part, *image));
bld.color(1.0f, 1.0f, 1.0f);
bld.begin(GL::QUADS);
bld.texcoord(0.0, 0.0);
void set_keep_aspect(bool);
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
};
} // namespace GLtk
rebuild();
}
-void Label::rebuild_special(const Part &part, CachedPart &cache)
+void Label::rebuild_special(const Part &part)
{
if(part.get_name()=="text")
- text.build(part, geom, cache);
+ text.build(part, geom, part_cache);
}
void Label::on_style_change()
void set_text(const std::string &);
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
virtual void on_style_change();
};
return graphic[state];
}
-void Part::build(const Geometry &parent, State state, CachedPart &cache) const
+void Part::build(const Geometry &parent, State state, PartCache &cache) const
{
- if(!graphic[state])
- {
- cache.texture = 0;
+ if(!graphic[state] || !graphic[state]->get_texture())
return;
- }
-
- cache.texture = graphic[state]->get_texture();
- cache.clear_mesh();
Geometry rgeom = geom;
align.apply(rgeom, parent, margin);
- GL::MeshBuilder bld(*cache.mesh);
+ GL::MeshBuilder bld(cache.create_mesh(*this, *graphic[state]->get_texture()));
bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
graphic[state]->build(rgeom.w, rgeom.h, bld);
}
namespace Msp {
namespace GLtk {
-class CachedPart;
class Graphic;
+class PartCache;
class Resources;
/**
const Geometry &get_geometry() const { return geom; }
const Sides &get_margin() const { return margin; }
const Alignment &get_alignment() const { return align; }
- void build(const Geometry &, State, CachedPart &) const;
+ void build(const Geometry &, State, PartCache &) const;
};
} // namespace GLtk
+#include "part.h"
#include "partcache.h"
+using namespace std;
+
namespace Msp {
namespace GLtk {
CachedPart::CachedPart():
+ part(0),
texture(0),
mesh(0)
{ }
delete mesh;
}
-void CachedPart::clear_mesh()
+
+void PartCache::clear()
+{
+ parts.clear();
+}
+
+void PartCache::insert_special(const Part &part)
{
- if(!mesh)
- mesh = new GL::Mesh((GL::TEXCOORD2, GL::COLOR4_UBYTE, GL::VERTEX2));
- else
- mesh->clear();
+ if(part.get_name().empty())
+ throw invalid_argument("PartCache::insert_special");
+
+ parts.push_back(CachedPart());
+ parts.back().part = ∂
+}
+
+GL::Mesh &PartCache::create_mesh(const Part &part, const GL::Texture2D &tex)
+{
+ if(!parts.empty() && parts.back().texture==&tex)
+ return *parts.back().mesh;
+
+ parts.push_back(CachedPart());
+ CachedPart &cpart = parts.back();
+ cpart.part = ∂
+ cpart.texture = &tex;
+ cpart.mesh = new GL::Mesh((GL::TEXCOORD2, GL::COLOR4_UBYTE, GL::VERTEX2));
+ return *cpart.mesh;
}
} // namespace GLtk
namespace Msp {
namespace GLtk {
+class Part;
+
struct CachedPart
{
+ const Part *part;
const GL::Texture2D *texture;
GL::Mesh *mesh;
CachedPart();
~CachedPart();
+};
+
+class PartCache
+{
+public:
+ typedef std::list<CachedPart> PartList;
+
+private:
+ PartList parts;
+
+public:
+ void clear();
+ void insert_special(const Part &);
+ GL::Mesh &create_mesh(const Part &, const GL::Texture2D &);
- void clear_mesh();
+ const PartList &get_parts() const { return parts; }
};
} // namespace GLtk
}
if(value!=old_value)
+ {
signal_value_changed.emit(value);
+ rebuild();
+ }
}
void Slider::set_range(double a, double b)
void Slider::drag(int p)
{
if(max>min)
- {
set_value(drag_start_value+(p-drag_start_pos)*(max-min)/drag_area_size);
- rebuild();
- }
}
void Slider::end_drag()
return data.result;
}
-void Text::build(const Part &part, const Geometry &parent, CachedPart &cache) const
+void Text::build(const Part &part, const Geometry &parent, PartCache &cache) const
{
build(part, parent, 0, cache);
}
-void Text::build(const Part &part, const Geometry &parent, unsigned first_row, CachedPart &cache) const
+void Text::build(const Part &part, const Geometry &parent, unsigned first_row, PartCache &cache) const
{
if(!style || lines.empty())
- {
- cache.texture = 0;
return;
- }
-
- cache.clear_mesh();
- GL::MeshBuilder bld(*cache.mesh);
const GL::Font &font = style->get_font();
+ GL::MeshBuilder bld(cache.create_mesh(part, font.get_texture()));
bld.color(style->get_font_color());
RenderData data;
data.bld = &bld;
- cache.texture = &font.get_texture();
-
process_lines<RenderData, &Text::build_line>(part, parent, first_row, data);
}
namespace Msp {
namespace GLtk {
-class CachedPart;
class Geometry;
class Part;
+class PartCache;
class Style;
/**
unsigned coords_to_offset(unsigned, unsigned) const;
Geometry coords_to_geometry(const Part &, const Geometry &, unsigned, unsigned, unsigned) const;
- void build(const Part &, const Geometry &, CachedPart &) const;
- void build(const Part &, const Geometry &, unsigned, CachedPart &) const;
+ void build(const Part &, const Geometry &, PartCache &) const;
+ void build(const Part &, const Geometry &, unsigned, PartCache &) const;
Text &operator=(const std::string &);
private:
clear_state(ACTIVE);
}
-void Toggle::rebuild_special(const Part &part, CachedPart &cache)
+void Toggle::rebuild_special(const Part &part)
{
if(part.get_name()=="text")
- text.build(part, geom, cache);
+ text.build(part, geom, part_cache);
}
void Toggle::button_press(int, int, unsigned btn)
bool get_value() const { return value; }
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
public:
virtual void button_press(int, int, unsigned);
}
}
-void VSlider::rebuild_special(const Part &part, CachedPart &cache)
+void VSlider::rebuild_special(const Part &part)
{
if(part.get_name()=="slider")
{
const Graphic *graphic = part.get_graphic(state);
- if(!graphic)
+ if(!graphic || !graphic->get_texture())
return;
Alignment align = part.get_alignment();
Geometry pgeom = part.get_geometry();
align.apply(pgeom, geom, part.get_margin());
- cache.texture = part.get_graphic(state)->get_texture();
- cache.clear_mesh();
-
- GL::MeshBuilder bld(*cache.mesh);
+ GL::MeshBuilder bld(part_cache.create_mesh(part, *graphic->get_texture()));
bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y, 0);
graphic->build(pgeom.w, pgeom.h, bld);
}
virtual void autosize();
private:
- virtual void rebuild_special(const Part &, CachedPart &);
+ virtual void rebuild_special(const Part &);
public:
virtual void button_press(int, int, unsigned);
if(!style)
return;
+ part_cache.clear();
const Style::PartSeq &parts = style->get_parts();
- list<CachedPart>::iterator j = cached_parts.begin();
- for(Style::PartSeq::const_iterator i=parts.begin(); i!=parts.end(); ++i, ++j)
+ for(Style::PartSeq::const_iterator i=parts.begin(); i!=parts.end(); ++i)
{
- if(j==cached_parts.end())
- j = cached_parts.insert(j, CachedPart());
if(i->get_name().empty())
- i->build(geom, state, *j);
+ i->build(geom, state, part_cache);
else
- rebuild_special(*i, *j);
+ rebuild_special(*i);
}
}
+void Widget::rebuild_special(const Part &part)
+{
+ part_cache.insert_special(part);
+}
+
void Widget::render(GL::Renderer &renderer) const
{
if(!style)
GL::MatrixStack::Push _pushm(renderer.matrix_stack());
renderer.matrix_stack() *= GL::Matrix::translation(geom.x, geom.y, 0);
- const Style::PartSeq &parts = style->get_parts();
- list<CachedPart>::const_iterator j = cached_parts.begin();
- for(Style::PartSeq::const_iterator i=parts.begin(); (i!=parts.end() && j!=cached_parts.end()); ++i, ++j)
+ const PartCache::PartList &parts = part_cache.get_parts();
+ for(PartCache::PartList::const_iterator i=parts.begin(); i!=parts.end(); ++i)
{
- if(j->mesh && j->texture)
+ if(i->mesh && i->texture)
{
- renderer.set_texture(j->texture);
- j->mesh->draw(renderer);
+ renderer.set_texture(i->texture);
+ i->mesh->draw(renderer);
}
- else if(!i->get_name().empty())
- render_special(*i, renderer);
+ else if(i->part)
+ render_special(*i->part, renderer);
}
}
bool focusable;
Container *parent;
std::string tooltip;
- std::list<CachedPart> cached_parts;
+ PartCache part_cache;
Widget();
public:
void set_state(State, State);
void rebuild();
- virtual void rebuild_special(const Part &, CachedPart &) { }
+ virtual void rebuild_special(const Part &);
public:
void render(GL::Renderer &) const;