00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "widgets.h"
00029
00030 #include <boost/thread/thread.hpp>
00031 #include <boost/thread/mutex.hpp>
00032 #include <iostream>
00033 #include <iomanip>
00034 #include "display_internal.h"
00035
00036 using namespace std;
00037
00038 namespace pangolin
00039 {
00040
00041 extern __thread PangolinGl* context;
00042
00043 const static int border = 1;
00044 const static int tab_w = 15;
00045 const static int tab_h = 20;
00046 const static int tab_p = 5;
00047 const static float colour_s1[4] = {0.2, 0.2, 0.2, 1.0};
00048 const static float colour_s2[4] = {0.6, 0.6, 0.6, 1.0};
00049 const static float colour_bg[4] = {0.9, 0.9, 0.9, 1.0};
00050 const static float colour_fg[4] = {1.0, 1.0 ,1.0, 1.0};
00051 const static float colour_tx[4] = {0.0, 0.0, 0.0, 1.0};
00052 const static float colour_hl[4] = {0.9, 0.9, 0.9, 1.0};
00053 const static float colour_dn[4] = {1.0, 0.7 ,0.7, 1.0};
00054 static void* font = GLUT_BITMAP_HELVETICA_12;
00055 static int text_height = 8;
00056 static int cb_height = text_height * 1.6;
00057
00058 boost::mutex display_mutex;
00059
00060 static bool guiVarHasChanged = true;
00061
00062 bool GuiVarHasChanged()
00063 {
00064 return pangolin::Pushed(guiVarHasChanged);
00065 }
00066
00067 template<typename T>
00068 void GuiVarChanged( Var<T>& var)
00069 {
00070 guiVarHasChanged = true;
00071 var.var->meta_gui_changed = true;
00072
00073 BOOST_FOREACH(GuiVarChangedCallback& gvc, gui_var_changed_callbacks)
00074 if( boost::starts_with(var.var->meta_full_name,gvc.filter) )
00075 gvc.fn(gvc.data,var.var->meta_full_name,*var.var);
00076 }
00077
00078 void glRect(Viewport v)
00079 {
00080 glRecti(v.l,v.b,v.r(),v.t());
00081 }
00082
00083 void glRect(Viewport v, int inset)
00084 {
00085 glRecti(v.l+inset,v.b+inset,v.r()-inset,v.t()-inset);
00086 }
00087
00088 void DrawShadowRect(Viewport& v)
00089 {
00090 glColor4fv(colour_s2);
00091 glBegin(GL_LINE_STRIP);
00092 glVertex2i(v.l,v.b);
00093 glVertex2i(v.l,v.t());
00094 glVertex2i(v.r(),v.t());
00095 glVertex2i(v.r(),v.b);
00096 glVertex2i(v.l,v.b);
00097 glEnd();
00098 }
00099
00100 void DrawShadowRect(Viewport& v, bool pushed)
00101 {
00102 glColor4fv(pushed ? colour_s1 : colour_s2);
00103 glBegin(GL_LINE_STRIP);
00104 glVertex2i(v.l,v.b);
00105 glVertex2i(v.l,v.t());
00106 glVertex2i(v.r(),v.t());
00107 glEnd();
00108
00109 glColor3fv(pushed ? colour_s2 : colour_s1);
00110 glBegin(GL_LINE_STRIP);
00111 glVertex2i(v.r(),v.t());
00112 glVertex2i(v.r(),v.b);
00113 glVertex2i(v.l,v.b);
00114 glEnd();
00115 }
00116
00117 Panel::Panel()
00118 : context_views(context->named_managed_views)
00119 {
00120 handler = &StaticHandlerScroll;
00121 layout = LayoutVertical;
00122 }
00123
00124 Panel::Panel(const std::string& auto_register_var_prefix)
00125 : context_views(context->named_managed_views)
00126 {
00127 handler = &StaticHandlerScroll;
00128 layout = LayoutVertical;
00129 RegisterNewVarCallback(&Panel::AddVariable,(void*)this,auto_register_var_prefix);
00130
00131
00132
00133 }
00134
00135 void Panel::AddVariable(void* data, const std::string& name, _Var& var, const char* reg_type_name, bool brand_new )
00136 {
00137 Panel* thisptr = (Panel*)data;
00138
00139 const string& title = var.meta_friendly;
00140
00141 display_mutex.lock();
00142
00143 boost::ptr_unordered_map<const std::string,View>::iterator pnl =
00144 thisptr->context_views.find(name);
00145
00146
00147
00148 if( pnl == thisptr->context_views.end() )
00149 {
00150 if( reg_type_name == typeid(bool).name() )
00151 {
00152 View* nv = var.meta_flags ? (View*)new Checkbox(title,var) : (View*)new Button(title,var);
00153
00154 thisptr->context_views.insert(name,nv);
00155 thisptr->views.push_back(nv);
00156 thisptr->ResizeChildren();
00157 }
00158 else if( reg_type_name == typeid(double).name() || reg_type_name == typeid(float).name() || reg_type_name == typeid(int).name() || reg_type_name == typeid(unsigned int).name() )
00159 {
00160 View* nv = new Slider(title,var);
00161
00162 thisptr->context_views.insert(name,nv);
00163 thisptr->views.push_back( nv );
00164 thisptr->ResizeChildren();
00165 }
00166 else
00167 {
00168 View* nv = new TextInput(title,var);
00169
00170 thisptr->context_views.insert(name,nv);
00171 thisptr->views.push_back( nv );
00172 thisptr->ResizeChildren();
00173 }
00174 }
00175
00176 display_mutex.unlock();
00177 }
00178
00179 void Panel::Render()
00180 {
00181 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_SCISSOR_BIT | GL_VIEWPORT_BIT);
00182
00183 OpenGlRenderState::ApplyWindowCoords();
00184 glDisable(GL_DEPTH_TEST);
00185 glDisable(GL_SCISSOR_TEST);
00186 glDisable(GL_LINE_SMOOTH);
00187 glLineWidth(1.0);
00188
00189 glColor4fv(colour_s2);
00190 glRect(v);
00191 glColor4fv(colour_bg);
00192 glRect(v,1);
00193
00194 RenderChildren();
00195
00196 glPopAttrib();
00197 }
00198
00199 void Panel::ResizeChildren()
00200 {
00201 View::ResizeChildren();
00202 }
00203
00204
00205 View& CreatePanel(const std::string& name)
00206 {
00207 Panel * p = new Panel(name);
00208 bool inserted = context->named_managed_views.insert(name, p).second;
00209 if(!inserted) throw exception();
00210 context->base.views.push_back(p);
00211 return *p;
00212 }
00213
00214 Button::Button(string title, _Var& tv)
00215 : Widget<bool>(title,tv), down(false)
00216 {
00217 top = 1.0;
00218 bottom = Attach::Pix(-20);
00219 left = 0.0;
00220 right = 1.0;
00221 hlock = LockLeft;
00222 vlock = LockBottom;
00223 text_width = glutBitmapLength(font,(unsigned char*)title.c_str());
00224 }
00225
00226 void Button::Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state)
00227 {
00228 if(button == MouseButtonLeft )
00229 {
00230 down = pressed;
00231 if( !pressed )
00232 {
00233 a->Set(!a->Get());
00234 GuiVarChanged(*this);
00235 }
00236 }
00237 }
00238
00239 void Button::Render()
00240 {
00241 glColor4fv(colour_fg );
00242 glRect(v);
00243 glColor4fv(colour_tx);
00244 glRasterPos2f(raster[0],raster[1]-down);
00245 glutBitmapString(font,(unsigned char*)title.c_str());
00246 DrawShadowRect(v, down);
00247 }
00248
00249 void Button::ResizeChildren()
00250 {
00251 raster[0] = v.l + (v.w-text_width)/2.0;
00252 raster[1] = v.b + (v.h-text_height)/2.0;
00253 vinside = v.Inset(border);
00254 }
00255
00256 Checkbox::Checkbox(std::string title, _Var& tv)
00257 : Widget<bool>(title,tv)
00258 {
00259 top = 1.0;
00260 bottom = Attach::Pix(-20);
00261 left = 0.0;
00262 right = 1.0;
00263 hlock = LockLeft;
00264 vlock = LockBottom;
00265 handler = this;
00266 }
00267
00268 void Checkbox::Mouse(View&, MouseButton button, int x, int y, bool pressed, int mouse_state)
00269 {
00270 if( button == MouseButtonLeft && pressed )
00271 {
00272 a->Set(!a->Get());
00273 GuiVarChanged(*this);
00274 }
00275 }
00276
00277 void Checkbox::ResizeChildren()
00278 {
00279 raster[0] = v.l + cb_height + 4;
00280 raster[1] = v.b + (v.h-text_height)/2.0;
00281 const int h = v.h;
00282 const int t = (h-cb_height) / 2.0;
00283 vcb = Viewport(v.l,v.b+t,cb_height,cb_height);
00284 }
00285
00286 void Checkbox::Render()
00287 {
00288 const bool val = a->Get();
00289
00290 if( val )
00291 {
00292 glColor4fv(colour_dn);
00293 glRect(vcb);
00294 }
00295 glColor4fv(colour_tx);
00296 glRasterPos2fv( raster );
00297 glutBitmapString(font,(unsigned char*)title.c_str());
00298 DrawShadowRect(vcb, val);
00299 }
00300
00301
00302 Slider::Slider(std::string title, _Var& tv)
00303 : Widget<double>(title+":", tv), lock_bounds(true)
00304 {
00305 top = 1.0;
00306 bottom = Attach::Pix(-20);
00307 left = 0.0;
00308 right = 1.0;
00309 hlock = LockLeft;
00310 vlock = LockBottom;
00311 handler = this;
00312 logscale = (int)tv.logscale;
00313 }
00314
00315 void Slider::Keyboard(View&, unsigned char key, int x, int y, bool pressed)
00316 {
00317
00318 if( pressed && var->meta_range[0] < var->meta_range[1] )
00319 {
00320 double val = !logscale ? a->Get() : log(a->Get());
00321
00322 if(key=='-')
00323 {
00324 if (logscale)
00325 a->Set( exp(max(var->meta_range[0],min(var->meta_range[1],val - var->meta_increment) ) ) );
00326 else
00327 a->Set( max(var->meta_range[0],min(var->meta_range[1],val - var->meta_increment) ) );
00328 }
00329 else if(key == '=')
00330 {
00331 if (logscale)
00332 a->Set( exp(max(var->meta_range[0],min(var->meta_range[1],val + var->meta_increment) ) ) );
00333 else
00334 a->Set( max(var->meta_range[0],min(var->meta_range[1],val + var->meta_increment) ) );
00335 }
00336 else if(key == 'r')
00337 {
00338 Reset();
00339 }
00340 else
00341 {
00342 return;
00343 }
00344 GuiVarChanged(*this);
00345 }
00346 }
00347
00348 void Slider::Mouse(View& view, MouseButton button, int x, int y, bool pressed, int mouse_state)
00349 {
00350 if(pressed)
00351 {
00352
00353 if( button == MouseWheelUp || button == MouseWheelDown )
00354 {
00355
00356 const double frac = max(0.0,min(1.0,(double)(x - v.l)/(double)v.w));
00357 double val = frac * (var->meta_range[1] - var->meta_range[0]) + var->meta_range[0];
00358
00359 if (logscale)
00360 {
00361 if (val<=0)
00362 val = std::numeric_limits<double>::min();
00363 else
00364 val = log(val);
00365 }
00366
00367 const double scale = (button == MouseWheelUp ? 1.2 : 1.0 / 1.2 );
00368 var->meta_range[1] = val + (var->meta_range[1] - val)*scale;
00369 var->meta_range[0] = val - (val - var->meta_range[0])*scale;
00370 }
00371 else
00372 {
00373 lock_bounds = (button == MouseButtonLeft);
00374 MouseMotion(view,x,y,mouse_state);
00375 }
00376 }
00377 else
00378 {
00379 if(!lock_bounds)
00380 {
00381 double val = !logscale ? a->Get() : log(a->Get());
00382
00383 var->meta_range[0] = min(var->meta_range[0], val);
00384 var->meta_range[1] = max(var->meta_range[1], val);
00385 }
00386 }
00387 }
00388
00389 void Slider::MouseMotion(View&, int x, int y, int mouse_state)
00390 {
00391 if( var->meta_range[0] != var->meta_range[1] )
00392 {
00393 const double range = (var->meta_range[1] - var->meta_range[0]);
00394 const double frac = (double)(x - v.l)/(double)v.w;
00395 double val;
00396
00397 if( lock_bounds )
00398 {
00399 const double bfrac = max(0.0,min(1.0,frac));
00400 val = bfrac * range + var->meta_range[0] ;
00401 }
00402 else
00403 {
00404 val = frac * range + var->meta_range[0];
00405 }
00406
00407 if (logscale) val = exp(val);
00408
00409 a->Set(val);
00410 GuiVarChanged(*this);
00411 }
00412 }
00413
00414
00415 void Slider::ResizeChildren()
00416 {
00417 raster[0] = v.l+2;
00418 raster[1] = v.b + (v.h-text_height)/2.0;
00419 }
00420
00421 void Slider::Render()
00422 {
00423 const double val = a->Get();
00424
00425 if( var->meta_range[0] != var->meta_range[1] )
00426 {
00427 double rval = val;
00428 if (logscale)
00429 {
00430 rval = log(val);
00431 }
00432 glColor4fv(colour_fg);
00433 glRect(v);
00434 glColor4fv(colour_dn);
00435 const double norm_val = max(0.0,min(1.0,(rval - var->meta_range[0]) / (var->meta_range[1] - var->meta_range[0])));
00436 glRect(Viewport(v.l,v.b,v.w*norm_val,v.h));
00437 DrawShadowRect(v);
00438 }
00439
00440 glColor4fv(colour_tx);
00441 glRasterPos2fv( raster );
00442 glutBitmapString(font,(unsigned char*)title.c_str());
00443
00444 std::ostringstream oss;
00445 oss << setprecision(4) << val;
00446 string str = oss.str();
00447 const int l = glutBitmapLength(font,(unsigned char*)str.c_str()) + 2;
00448 glRasterPos2f( v.l + v.w - l, raster[1] );
00449 glutBitmapString(font,(unsigned char*)str.c_str());
00450 }
00451
00452
00453 TextInput::TextInput(std::string title, _Var& tv)
00454 : Widget<std::string>(title+":", tv), do_edit(false)
00455 {
00456 top = 1.0;
00457 bottom = Attach::Pix(-20);
00458 left = 0.0;
00459 right = 1.0;
00460 hlock = LockLeft;
00461 vlock = LockBottom;
00462 handler = this;
00463 sel[0] = -1;
00464 sel[1] = -1;
00465 }
00466
00467 void TextInput::Keyboard(View&, unsigned char key, int x, int y, bool pressed)
00468 {
00469 if(pressed)
00470 {
00471 const bool selection = sel[1] > sel[0] && sel[0] >= 0;
00472
00473 if(key == 13)
00474 {
00475 a->Set(edit);
00476 GuiVarChanged(*this);
00477
00478 do_edit = false;
00479 sel[0] = sel[1] = -1;
00480 }
00481 else if(key == 8)
00482 {
00483
00484 if(selection)
00485 {
00486 edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
00487 sel[1] = sel[0];
00488 }
00489 else
00490 {
00491 if(sel[0] >0)
00492 {
00493 edit = edit.substr(0,sel[0]-1) + edit.substr(sel[0],edit.length()-sel[0]);
00494 sel[0]--;
00495 sel[1]--;
00496 }
00497 }
00498 }
00499 else if(key == 127)
00500 {
00501
00502 if(selection)
00503 {
00504 edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
00505 sel[1] = sel[0];
00506 }
00507 else
00508 {
00509 if(sel[0] < (int)edit.length())
00510 {
00511 edit = edit.substr(0,sel[0]) + edit.substr(sel[0]+1,edit.length()-sel[0]+1);
00512 }
00513 }
00514 }
00515 else if(key == 230)
00516 {
00517
00518 sel[0] = min((int)edit.length(),sel[0]+1);
00519 sel[1] = sel[0];
00520 }
00521 else if(key == 228)
00522 {
00523
00524 sel[0] = max(0,sel[0]-1);
00525 sel[1] = sel[0];
00526 }
00527 else if(key == 234)
00528 {
00529
00530 sel[0] = sel[1] = 0;
00531 }
00532 else if(key == 235)
00533 {
00534
00535 sel[0] = sel[1] = edit.length();
00536 }
00537 else
00538 {
00539
00540 edit = edit.substr(0,sel[0]).append(1,key) + edit.substr(sel[1],edit.length()-sel[1]);
00541 sel[1] = sel[0];
00542 sel[0]++;
00543 sel[1]++;
00544 }
00545 }
00546 }
00547
00548 void TextInput::Mouse(View& view, MouseButton button, int x, int y, bool pressed, int mouse_state)
00549 {
00550 if(button != MouseWheelUp && button != MouseWheelDown )
00551 {
00552
00553 if(do_edit)
00554 {
00555 const int sl = glutBitmapLength(font,(unsigned char*)edit.c_str()) + 2;
00556 const int rl = v.l + v.w - sl;
00557 int ep = edit.length();
00558
00559 if( x < rl )
00560 {
00561 ep = 0;
00562 }
00563 else
00564 {
00565 for( unsigned i=0; i<edit.length(); ++i )
00566 {
00567 const int tl = rl + glutBitmapLength(font,(unsigned char*)edit.substr(0,i).c_str());
00568 if(x < tl+2)
00569 {
00570 ep = i;
00571 break;
00572 }
00573 }
00574 }
00575 if(pressed)
00576 {
00577 sel[0] = sel[1] = ep;
00578 }
00579 else
00580 {
00581 sel[1] = ep;
00582 }
00583
00584 if(sel[0] > sel[1])
00585 std::swap(sel[0],sel[1]);
00586 }
00587 else
00588 {
00589 do_edit = !pressed;
00590 sel[0] = 0;
00591 sel[1] = edit.length();
00592 }
00593 }
00594 }
00595
00596 void TextInput::MouseMotion(View&, int x, int y, int mouse_state)
00597 {
00598 if(do_edit)
00599 {
00600 const int sl = glutBitmapLength(font,(unsigned char*)edit.c_str()) + 2;
00601 const int rl = v.l + v.w - sl;
00602 int ep = edit.length();
00603
00604 if( x < rl )
00605 {
00606 ep = 0;
00607 }
00608 else
00609 {
00610 for( unsigned i=0; i<edit.length(); ++i )
00611 {
00612 const int tl = rl + glutBitmapLength(font,(unsigned char*)edit.substr(0,i).c_str());
00613 if(x < tl+2)
00614 {
00615 ep = i;
00616 break;
00617 }
00618 }
00619 }
00620
00621 sel[1] = ep;
00622 }
00623 }
00624
00625
00626 void TextInput::ResizeChildren()
00627 {
00628 raster[0] = v.l+2;
00629 raster[1] = v.b + (v.h-text_height)/2.0;
00630 }
00631
00632 void TextInput::Render()
00633 {
00634 if(!do_edit) edit = a->Get();
00635
00636 glColor4fv(colour_fg);
00637 glRect(v);
00638
00639 const int sl = glutBitmapLength(font,(unsigned char*)edit.c_str()) + 2;
00640 const int rl = v.l + v.w - sl;
00641
00642 if( do_edit && sel[0] >= 0)
00643 {
00644 const int tl = rl + glutBitmapLength(font,(unsigned char*)edit.substr(0,sel[0]).c_str());
00645 const int tr = rl + glutBitmapLength(font,(unsigned char*)edit.substr(0,sel[1]).c_str());
00646 glColor4fv(colour_dn);
00647 glRect(Viewport(tl,v.b,tr-tl,v.h));
00648 }
00649
00650 glColor4fv(colour_tx);
00651 glRasterPos2fv( raster );
00652 glutBitmapString(font,(unsigned char*)title.c_str());
00653
00654 glRasterPos2f( rl, raster[1] );
00655 glutBitmapString(font,(unsigned char*)edit.c_str());
00656 DrawShadowRect(v);
00657 }
00658
00659 }