diff --git a/examples/SimpleDisplay/main.cpp b/examples/SimpleDisplay/main.cpp index ebaed8b40..d62f380c7 100644 --- a/examples/SimpleDisplay/main.cpp +++ b/examples/SimpleDisplay/main.cpp @@ -30,9 +30,9 @@ std::istream& operator>> (std::istream& is, CustomType& o){ return is; } -void GlobalKeyHook() +void SampleMethod() { - cout << "You pushed ctrl-r" << endl; + cout << "You typed ctrl-r or pushed reset" << endl; } int main( int /*argc*/, char* argv[] ) @@ -68,12 +68,6 @@ int main( int /*argc*/, char* argv[] ) pangolin::CreatePanel("ui") .SetBounds(0.0, 1.0, 0.0, Attach::Pix(UI_WIDTH)); - // Demonstration of how we can register a keyboard hook to alter a Var - pangolin::RegisterKeyPressCallback( PANGO_CTRL + 'b', SetVarFunctor("ui.A Double", 3.5) ); - - // Demonstration of how we can register a keyboard hook to trigger a method - pangolin::RegisterKeyPressCallback( PANGO_CTRL + 'r', GlobalKeyHook ); - // Safe and efficient binding of named variables. // Specialisations mean no conversions take place for exact types // and conversions between scalar types are cheap. @@ -90,6 +84,16 @@ int main( int /*argc*/, char* argv[] ) Var record_teapot("ui.Record Teapot",false,false); + // boost::function / std::function objects can be used for Var's too. + // In C++11, these work great with closures. + Var > reset("ui.Reset", SampleMethod); + + // Demonstration of how we can register a keyboard hook to alter a Var + pangolin::RegisterKeyPressCallback(PANGO_CTRL + 'b', SetVarFunctor("ui.A Double", 3.5)); + + // Demonstration of how we can register a keyboard hook to trigger a method + pangolin::RegisterKeyPressCallback(PANGO_CTRL + 'r', SampleMethod); + // Default hooks for exiting (Esc) and fullscreen (tab). while( !pangolin::ShouldQuit() ) { diff --git a/include/pangolin/type_convert.h b/include/pangolin/type_convert.h index 7010aceb6..caef235d6 100644 --- a/include/pangolin/type_convert.h +++ b/include/pangolin/type_convert.h @@ -31,6 +31,7 @@ #include #include +#include #include namespace pangolin @@ -40,6 +41,27 @@ struct BadInputException : std::exception { char const* what() const throw() { return "Failed to serialise type"; } }; +// Dummy methods to serialise functions / functors / lambdas etc +#ifdef CALLEE_HAS_CPP11 +template +std::istream& operator>>(std::istream& is, std::function& f) { + throw BadInputException(); +} +template +std::ostream& operator<<(std::ostream& os, const std::function& f) { + throw BadInputException(); +} +#else +template +std::istream& operator>>(std::istream& is, boostd::function& f) { + throw BadInputException(); +} +template +std::ostream& operator<<(std::ostream& os, const boostd::function& f) { + throw BadInputException(); +} +#endif + template struct Convert; diff --git a/include/pangolin/widgets.h b/include/pangolin/widgets.h index 0d51233bd..1404851ab 100644 --- a/include/pangolin/widgets.h +++ b/include/pangolin/widgets.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace pangolin { @@ -76,6 +77,20 @@ struct PANGOLIN_EXPORT Button : public Widget bool down; }; +struct PANGOLIN_EXPORT FunctionButton : public Widget > +{ + FunctionButton(std::string title, VarValueGeneric& tv); + void Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state); + void Render(); + + //Cache params on resize + void ResizeChildren(); + int text_width; + GLfloat raster[2]; + Viewport vinside; + bool down; +}; + struct PANGOLIN_EXPORT Checkbox : public Widget { Checkbox(std::string title, VarValueGeneric& tv); diff --git a/src/widgets.cpp b/src/widgets.cpp index 4c517a8fa..5bfd20b59 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -161,8 +161,10 @@ void Panel::AddVariable(void* data, const std::string& name, VarValueGeneric& va View* nv = NULL; if( !strcmp(reg_type_name, typeid(bool).name()) ) { nv = var.Meta().flags ? (View*)new Checkbox(title,var) : (View*)new Button(title,var); - }else if( !strcmp(reg_type_name, typeid(double).name()) || !strcmp(reg_type_name, typeid(float).name()) || !strcmp(reg_type_name, typeid(int).name()) || !strcmp(reg_type_name, typeid(unsigned int).name()) ) { - nv = new Slider(title,var); + } else if (!strcmp(reg_type_name, typeid(double).name()) || !strcmp(reg_type_name, typeid(float).name()) || !strcmp(reg_type_name, typeid(int).name()) || !strcmp(reg_type_name, typeid(unsigned int).name())) { + nv = new Slider(title, var); + } else if (!strcmp(reg_type_name, typeid(boostd::function).name() ) ) { + nv = (View*)new FunctionButton(title, var); }else{ nv = new TextInput(title,var); } @@ -261,6 +263,45 @@ void Button::ResizeChildren() vinside = v.Inset(border); } +FunctionButton::FunctionButton(string title, VarValueGeneric& tv) + : Widget >(title, tv), down(false) +{ + top = 1.0; bottom = Attach::Pix(-tab_h); + left = 0.0; right = 1.0; + hlock = LockLeft; + vlock = LockBottom; + text_width = glutBitmapLength(font, (unsigned char*)title.c_str()); +} + +void FunctionButton::Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state) +{ + if (button == MouseButtonLeft) + { + down = pressed; + if (!pressed) { + var->Get()(); + GuiVarChanged(*this); + } + } +} + +void FunctionButton::Render() +{ + glColor4fv(colour_fg); + glRect(v); + glColor4fv(colour_tx); + glRasterPos2f(raster[0], raster[1] - down); + glutBitmapString(font, (unsigned char*)title.c_str()); + DrawShadowRect(v, down); +} + +void FunctionButton::ResizeChildren() +{ + raster[0] = v.l + (v.w - text_width) / 2.0f; + raster[1] = v.b + (v.h - text_height) / 2.0f; + vinside = v.Inset(border); +} + Checkbox::Checkbox(std::string title, VarValueGeneric& tv) : Widget(title,tv) {