$search
00001 00002 /* 00003 * Copyright (c) 2008, Willow Garage, Inc. 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * 00009 * * Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * * Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * * Neither the name of the Willow Garage, Inc. nor the names of its 00015 * contributors may be used to endorse or promote products derived from 00016 * this software without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00028 * POSSIBILITY OF SUCH DAMAGE. 00029 */ 00030 00031 #include "displays_panel.h" 00032 #include "visualization_manager.h" 00033 #include "display.h" 00034 #include "display_wrapper.h" 00035 #include "new_display_dialog.h" 00036 #include "properties/property.h" 00037 #include "properties/property_manager.h" 00038 #include "plugin/type_registry.h" 00039 #include "plugin/plugin_manager.h" 00040 #include "plugin/plugin.h" 00041 00042 #include <wx/propgrid/propgrid.h> 00043 #include <wx/msgdlg.h> 00044 #include <wx/confbase.h> 00045 #include <wx/artprov.h> 00046 #include <wx/timer.h> 00047 #include <wx/textdlg.h> 00048 00049 #include <boost/bind.hpp> 00050 00051 static const wxString PROPERTY_GRID_CONFIG(wxT("Property Grid State")); 00052 00053 namespace rviz 00054 { 00055 00056 class ManageDisplaysDialog : public ManageDisplaysDialogGenerated 00057 { 00058 public: 00059 ManageDisplaysDialog(V_DisplayWrapper& displays, VisualizationManager* manager, wxWindow* parent); 00060 00061 virtual void onRename( wxCommandEvent& event ); 00062 virtual void onRemove( wxCommandEvent& event ); 00063 virtual void onRemoveAll( wxCommandEvent& event ); 00064 virtual void onMoveUp( wxCommandEvent& event ); 00065 virtual void onMoveDown( wxCommandEvent& event ); 00066 virtual void onOK( wxCommandEvent& event ); 00067 00068 V_DisplayWrapper& displays_; 00069 VisualizationManager* manager_; 00070 }; 00071 00072 ManageDisplaysDialog::ManageDisplaysDialog(V_DisplayWrapper& displays, VisualizationManager* manager, wxWindow* parent) 00073 : ManageDisplaysDialogGenerated(parent) 00074 , displays_(displays) 00075 , manager_(manager) 00076 { 00077 move_up_->SetBitmapLabel( wxArtProvider::GetIcon( wxART_GO_UP, wxART_OTHER, wxSize(16,16) ) ); 00078 move_down_->SetBitmapLabel( wxArtProvider::GetIcon( wxART_GO_DOWN, wxART_OTHER, wxSize(16,16) ) ); 00079 00080 V_DisplayWrapper::iterator it = displays_.begin(); 00081 V_DisplayWrapper::iterator end = displays_.end(); 00082 for (; it != end; ++it) 00083 { 00084 DisplayWrapper* wrapper = *it; 00085 const std::string& name = wrapper->getName(); 00086 listbox_->Append(wxString::FromAscii(name.c_str())); 00087 } 00088 } 00089 00090 void ManageDisplaysDialog::onRename( wxCommandEvent& event ) 00091 { 00092 int sel = listbox_->GetSelection(); 00093 if (sel < 0) 00094 { 00095 return; 00096 } 00097 00098 bool ok = true; 00099 wxString new_name; 00100 do 00101 { 00102 if (!ok) 00103 { 00104 new_name = wxGetTextFromUser(wxT("That name is already taken. Please try another."), wxT("Rename Display"), listbox_->GetString(sel), this); 00105 } 00106 else 00107 { 00108 new_name = wxGetTextFromUser(wxT("New Name?"), wxT("Rename Display"), listbox_->GetString(sel), this); 00109 } 00110 00111 ok = true; 00112 if (new_name.IsEmpty() || new_name == listbox_->GetString(sel)) 00113 { 00114 return; 00115 } 00116 00117 // Make sure the new name is not already taken 00118 V_DisplayWrapper::iterator it = displays_.begin(); 00119 V_DisplayWrapper::iterator end = displays_.end(); 00120 for (; it != end; ++it) 00121 { 00122 DisplayWrapper* wrapper = *it; 00123 if (wrapper->getName() == (const char*)new_name.mb_str()) 00124 { 00125 ok = false; 00126 break; 00127 } 00128 } 00129 } while (!ok); 00130 00131 displays_[sel]->setName((const char*)new_name.mb_str()); 00132 listbox_->SetString(sel, new_name); 00133 } 00134 00135 void ManageDisplaysDialog::onRemove(wxCommandEvent& event) 00136 { 00137 int sel = listbox_->GetSelection(); 00138 if (sel < 0) 00139 { 00140 return; 00141 } 00142 00143 manager_->removeDisplay(displays_[sel]); 00144 listbox_->Delete(sel); 00145 if (sel < (int) listbox_->GetCount()) 00146 { 00147 listbox_->SetSelection(sel); 00148 } 00149 else if (sel > 0) 00150 { 00151 listbox_->SetSelection(sel - 1); 00152 } 00153 } 00154 00155 void ManageDisplaysDialog::onRemoveAll(wxCommandEvent& event) 00156 { 00157 manager_->removeAllDisplays(); 00158 listbox_->Clear(); 00159 } 00160 00161 void ManageDisplaysDialog::onMoveUp( wxCommandEvent& event ) 00162 { 00163 int sel = listbox_->GetSelection(); 00164 if (sel > 0) 00165 { 00166 std::swap(displays_[sel], displays_[sel - 1]); 00167 listbox_->Insert(listbox_->GetString(sel - 1), sel + 1); 00168 listbox_->Delete(sel - 1); 00169 listbox_->SetSelection(sel - 1); 00170 } 00171 } 00172 00173 void ManageDisplaysDialog::onMoveDown( wxCommandEvent& event ) 00174 { 00175 int sel = listbox_->GetSelection(); 00176 if (sel >= 0 && sel < (int) listbox_->GetCount() - 1) 00177 { 00178 std::swap(displays_[sel], displays_[sel + 1]); 00179 listbox_->Insert(listbox_->GetString(sel + 1), sel); 00180 listbox_->Delete(sel + 2); 00181 listbox_->SetSelection(sel + 1); 00182 } 00183 } 00184 00185 void ManageDisplaysDialog::onOK( wxCommandEvent& event ) 00186 { 00187 EndModal(wxOK); 00188 } 00189 00190 DisplaysPanel::DisplaysPanel( wxWindow* parent ) 00191 : DisplaysPanelGenerated( parent ) 00192 , manager_(NULL) 00193 { 00194 property_grid_ = new wxPropertyGrid( properties_panel_, wxID_ANY, wxDefaultPosition, wxSize(500, 500), wxPG_SPLITTER_AUTO_CENTER | wxPG_DEFAULT_STYLE ); 00195 properties_panel_sizer_->Add( property_grid_, 1, wxEXPAND, 5 ); 00196 00197 property_grid_->SetExtraStyle(wxPG_EX_DISABLE_TLP_TRACKING); 00198 00199 property_grid_->Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( DisplaysPanel::onPropertyChanging ), NULL, this ); 00200 property_grid_->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DisplaysPanel::onPropertyChanged ), NULL, this ); 00201 property_grid_->Connect( wxEVT_PG_SELECTED, wxPropertyGridEventHandler( DisplaysPanel::onPropertySelected ), NULL, this ); 00202 property_grid_->Connect( wxEVT_PG_HIGHLIGHTED, wxPropertyGridEventHandler( DisplaysPanel::onPropertyHighlighted ), NULL, this ); 00203 00204 property_grid_->SetCaptionBackgroundColour( wxColour( 4, 89, 127 ) ); 00205 /* START_WX-2.9_COMPAT_CODE 00206 This code is related to ticket: https://code.ros.org/trac/ros-pkg/ticket/5157 00207 */ 00208 #if wxMAJOR_VERSION == 2 and wxMINOR_VERSION == 8 // If wxWidgets 2.8.x 00209 // This function is no longer available in wxPropgrid for wx-2.9 00210 property_grid_->SetCaptionForegroundColour( *wxWHITE ); 00211 #endif 00212 /* END_WX-2.9_COMPAT_CODE */ 00213 00214 help_html_->Connect(wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler(DisplaysPanel::onLinkClicked), NULL, this); 00215 00216 state_changed_timer_ = new wxTimer(this); 00217 state_changed_timer_->Start(200); 00218 Connect(state_changed_timer_->GetId(), wxEVT_TIMER, wxTimerEventHandler(DisplaysPanel::onStateChangedTimer), NULL, this); 00219 } 00220 00221 DisplaysPanel::~DisplaysPanel() 00222 { 00223 delete state_changed_timer_; 00224 00225 property_grid_->Destroy(); 00226 } 00227 00228 void DisplaysPanel::initialize(VisualizationManager* manager) 00229 { 00230 manager_ = manager; 00231 manager_->getDisplayAddingSignal().connect( boost::bind( &DisplaysPanel::onDisplayAdding, this, _1 ) ); 00232 manager_->getDisplayAddedSignal().connect( boost::bind( &DisplaysPanel::onDisplayAdded, this, _1 ) ); 00233 manager_->getDisplayRemovingSignal().connect( boost::bind( &DisplaysPanel::onDisplayRemoving, this, _1 ) ); 00234 manager_->getDisplayRemovedSignal().connect( boost::bind( &DisplaysPanel::onDisplayRemoved, this, _1 ) ); 00235 manager_->getDisplaysRemovingSignal().connect( boost::bind( &DisplaysPanel::onDisplaysRemoving, this, _1 ) ); 00236 manager_->getDisplaysRemovedSignal().connect( boost::bind( &DisplaysPanel::onDisplaysRemoved, this, _1 ) ); 00237 manager_->getDisplaysConfigLoadedSignal().connect( boost::bind( &DisplaysPanel::onDisplaysConfigLoaded, this, _1 ) ); 00238 manager_->getDisplaysConfigSavingSignal().connect( boost::bind( &DisplaysPanel::onDisplaysConfigSaving, this, _1 ) ); 00239 00240 manager_->getPropertyManager()->setPropertyGrid(property_grid_); 00241 00242 sortDisplays(); 00243 } 00244 00245 void DisplaysPanel::sortDisplays() 00246 { 00247 property_grid_->Freeze(); 00248 /* START_WX-2.9_COMPAT_CODE 00249 This code is related to ticket: https://code.ros.org/trac/ros-pkg/ticket/5157 00250 */ 00251 #if wxMAJOR_VERSION == 2 and wxMINOR_VERSION == 8 // If wxWidgets 2.8.x 00252 property_grid_->Sort(property_grid_->GetRoot()); 00253 #else 00254 // This is the new way to sort a wxPropertyGrid 00255 property_grid_->Sort(); 00256 #endif 00257 /* END_WX-2.9_COMPAT_CODE */ 00258 property_grid_->Refresh(); 00259 property_grid_->Thaw(); 00260 } 00261 00262 void DisplaysPanel::onPropertyChanging( wxPropertyGridEvent& event ) 00263 { 00264 wxPGProperty* property = event.GetProperty(); 00265 00266 if ( !property ) 00267 { 00268 return; 00269 } 00270 00271 manager_->getPropertyManager()->propertyChanging( event ); 00272 } 00273 00274 void DisplaysPanel::onPropertyChanged( wxPropertyGridEvent& event ) 00275 { 00276 wxPGProperty* property = event.GetProperty(); 00277 00278 if ( !property ) 00279 { 00280 return; 00281 } 00282 00283 manager_->getPropertyManager()->propertyChanged( event ); 00284 } 00285 00286 void DisplaysPanel::onPropertySelected( wxPropertyGridEvent& event ) 00287 { 00288 // Hack to fix bug #4885. If I put this in the constructor or in 00289 // initialize() this has no effect. Similarly, 00290 // GetSizer()->SetMinSize() has no effect. Only directly calling 00291 // this->SetMinSize() actually changes anything. If the layout 00292 // structure is changed, these calls to GetItem(1) and (2) may need 00293 // to change. -hersh 00294 wxSize size = GetMinSize(); 00295 int height = 0; 00296 height += GetSizer()->GetItem(1)->GetMinSize().GetHeight(); 00297 height += GetSizer()->GetItem(2)->GetMinSize().GetHeight(); 00298 size.SetHeight( height ); 00299 SetMinSize( size ); 00300 00301 wxPGProperty* pg_property = event.GetProperty(); 00302 00303 selected_display_ = 0; 00304 00305 if ( !pg_property ) 00306 { 00307 return; 00308 } 00309 00310 wxString text = pg_property->GetHelpString(); 00311 wxString html = wxT("<html><body bgcolor=\"#EFEBE7\"><strong>") + pg_property->GetLabel() + wxT("</strong><br>") + text + wxT("</body></html>"); 00312 00313 help_html_->SetPage(html); 00314 00315 void* client_data = pg_property->GetClientData(); 00316 if ( client_data ) 00317 { 00318 PropertyBase* property = reinterpret_cast<PropertyBase*>(client_data); 00319 00320 void* user_data = property->getUserData(); 00321 if ( user_data ) 00322 { 00323 DisplayWrapper* wrapper = reinterpret_cast<DisplayWrapper*>(user_data); 00324 00325 if ( manager_->isValidDisplay( wrapper ) ) 00326 { 00327 selected_display_ = manager_->getDisplayWrapper(wrapper->getName()); 00328 } 00329 else 00330 { 00331 DisplayWrapper* wrapper = manager_->getDisplayWrapper(reinterpret_cast<Display*>(user_data)); 00332 00333 if (wrapper) 00334 { 00335 selected_display_ = wrapper; 00336 } 00337 } 00338 } 00339 } 00340 } 00341 00342 void DisplaysPanel::onPropertyHighlighted( wxPropertyGridEvent& event ) 00343 { 00344 wxPGProperty* property = event.GetProperty(); 00345 00346 if ( !property ) 00347 { 00348 return; 00349 } 00350 00351 /* 00352 wxString text = property->GetHelpString(); 00353 wxString html = wxT("<html><body bgcolor=\"#EFEBE7\"><strong>") + property->GetLabel() + wxT("</strong><br>") + text + wxT("</body></html>"); 00354 00355 help_html_->SetPage(html); 00356 */ 00357 } 00358 00359 void DisplaysPanel::onLinkClicked(wxHtmlLinkEvent& event) 00360 { 00361 wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref()); 00362 } 00363 00364 void DisplaysPanel::onNewDisplay( wxCommandEvent& event ) 00365 { 00366 L_DisplayTypeInfo display_types; 00367 PluginManager* pm = manager_->getPluginManager(); 00368 00369 S_string current_display_names; 00370 manager_->getDisplayNames(current_display_names); 00371 00372 NewDisplayDialog dialog( this, pm->getPlugins(), current_display_names ); 00373 while (1) 00374 { 00375 if ( dialog.ShowModal() == wxOK ) 00376 { 00377 std::string class_name = dialog.getClassName(); 00378 std::string name = dialog.getDisplayName(); 00379 std::string package = dialog.getPackageName(); 00380 00381 if (manager_->getDisplayWrapper(name)) 00382 { 00383 wxMessageBox( wxT("A display with that name already exists!"), wxT("Invalid name"), wxICON_ERROR | wxOK, this ); 00384 continue; 00385 } 00386 00387 DisplayWrapper* wrapper = manager_->createDisplay( package, class_name, name, true ); 00388 (void)wrapper; 00389 break; 00390 } 00391 else 00392 { 00393 break; 00394 } 00395 } 00396 } 00397 00398 void DisplaysPanel::onDeleteDisplay( wxCommandEvent& event ) 00399 { 00400 DisplayWrapper* selected = selected_display_; 00401 if ( !selected ) 00402 { 00403 return; 00404 } 00405 00406 manager_->removeDisplay(selected); 00407 selected_display_ = 0; 00408 } 00409 00410 void DisplaysPanel::onManage(wxCommandEvent& event) 00411 { 00412 V_DisplayWrapper& displays = manager_->getDisplays(); 00413 ManageDisplaysDialog d(displays, manager_, this); 00414 d.ShowModal(); 00415 00416 // Remap the displays based on the new indices 00417 { 00418 display_map_.clear(); 00419 V_DisplayWrapper::iterator it = displays.begin(); 00420 V_DisplayWrapper::iterator end = displays.end(); 00421 for (; it != end; ++it) 00422 { 00423 DisplayWrapper* display = *it; 00424 uint32_t index = it - displays.begin(); 00425 display_map_[display] = index; 00426 setDisplayCategoryLabel(display, index); 00427 } 00428 } 00429 00430 sortDisplays(); 00431 } 00432 00433 void DisplaysPanel::setDisplayCategoryLabel(const DisplayWrapper* wrapper, int index) 00434 { 00435 std::string display_name; 00436 if (wrapper->isLoaded()) 00437 { 00438 display_name = wrapper->getTypeInfo()->display_name; 00439 } 00440 else 00441 { 00442 display_name = "Plugin from package [" + wrapper->getPackage() + "] not loaded for display class [" + wrapper->getClassName() + "]"; 00443 } 00444 00445 char buf[1024]; 00446 snprintf( buf, 1024, "%02d. %s (%s)", index + 1, wrapper->getName().c_str(), display_name.c_str()); 00447 wrapper->getCategory().lock()->setLabel(buf); 00448 } 00449 00450 void DisplaysPanel::setDisplayCategoryColor(const DisplayWrapper* wrapper) 00451 { 00452 CategoryPropertyPtr cat = wrapper->getCategory().lock(); 00453 wxPGProperty* property = wrapper->getCategory().lock()->getPGProperty(); 00454 00455 /* START_WX-2.9_COMPAT_CODE 00456 This code is related to ticket: https://code.ros.org/trac/ros-pkg/ticket/5157 00457 */ 00458 #if wxMAJOR_VERSION == 2 and wxMINOR_VERSION == 8 // If wxWidgets 2.8.x 00459 wxPGCell* cell = property->GetCell( 0 ); 00460 if ( !cell ) 00461 { 00462 cell = new wxPGCell(*(wxString*)0, wxNullBitmap, wxNullColour, wxNullColour); 00463 property->SetCell( 0, cell ); 00464 } 00465 #else 00466 // The new API returns a reference not a pointer 00467 // and the library automatically creates a cell if one does not exists for you 00468 wxPGCell _cell = property->GetCell(0); 00469 #endif 00470 /* END_WX-2.9_COMPAT_CODE */ 00471 00472 if (!wrapper->isLoaded()) 00473 { 00474 cat->setToError(); 00475 } 00476 else if ( wrapper->getDisplay()->isEnabled() ) 00477 { 00478 switch (wrapper->getDisplay()->getStatus()) 00479 { 00480 case status_levels::Ok: 00481 cat->setToOK(); 00482 break; 00483 case status_levels::Warn: 00484 cat->setToWarn(); 00485 break; 00486 case status_levels::Error: 00487 cat->setToError(); 00488 break; 00489 } 00490 } 00491 else 00492 { 00493 cat->setToDisabled(); 00494 } 00495 } 00496 00497 void DisplaysPanel::onStateChangedTimer(wxTimerEvent& event) 00498 { 00499 S_Display local_displays; 00500 { 00501 boost::mutex::scoped_lock lock(state_changed_displays_mutex_); 00502 local_displays.swap(state_changed_displays_); 00503 } 00504 00505 S_Display::iterator it = local_displays.begin(); 00506 S_Display::iterator end = local_displays.end(); 00507 for (; it != end; ++it) 00508 { 00509 Display* display = *it; 00510 DisplayWrapper* wrapper = manager_->getDisplayWrapper(display); 00511 if (!wrapper) 00512 { 00513 continue; 00514 } 00515 00516 M_DisplayToIndex::iterator it = display_map_.find(wrapper); 00517 if (it == display_map_.end()) 00518 { 00519 continue; 00520 } 00521 00522 int index = it->second; 00523 setDisplayCategoryColor(wrapper); 00524 setDisplayCategoryLabel(wrapper, index); 00525 } 00526 } 00527 00528 void DisplaysPanel::onDisplayStateChanged( Display* display ) 00529 { 00530 // This can be called from different threads, so we have to push this to the GUI update thread 00531 boost::mutex::scoped_lock lock(state_changed_displays_mutex_); 00532 state_changed_displays_.insert(display); 00533 00534 } 00535 00536 void DisplaysPanel::onDisplayCreated( DisplayWrapper* wrapper ) 00537 { 00538 wrapper->getDisplay()->getStateChangedSignal().connect( boost::bind( &DisplaysPanel::onDisplayStateChanged, this, _1 ) ); 00539 00540 setDisplayCategoryColor(wrapper); 00541 00542 Refresh(); 00543 } 00544 00545 void DisplaysPanel::onDisplayDestroyed( DisplayWrapper* wrapper ) 00546 { 00547 M_DisplayToIndex::iterator it = display_map_.find(wrapper); 00548 if (it == display_map_.end()) 00549 { 00550 return; 00551 } 00552 00553 setDisplayCategoryColor(wrapper); 00554 00555 00556 int index = it->second; 00557 setDisplayCategoryLabel(wrapper, index); 00558 00559 Refresh(); 00560 } 00561 00562 void DisplaysPanel::onDisplayAdding( DisplayWrapper* wrapper ) 00563 { 00564 property_grid_->Freeze(); 00565 00566 wrapper->getDisplayCreatedSignal().connect(boost::bind(&DisplaysPanel::onDisplayCreated, this, _1)); 00567 wrapper->getDisplayDestroyedSignal().connect(boost::bind(&DisplaysPanel::onDisplayDestroyed, this, _1)); 00568 } 00569 00570 void DisplaysPanel::onDisplayAdded( DisplayWrapper* wrapper ) 00571 { 00572 int index = display_map_.size(); 00573 bool inserted = display_map_.insert(std::make_pair(wrapper, index)).second; 00574 ROS_ASSERT(inserted); 00575 setDisplayCategoryLabel(wrapper, index); 00576 setDisplayCategoryColor(wrapper); 00577 00578 property_grid_->Refresh(); 00579 property_grid_->Thaw(); 00580 } 00581 00582 void DisplaysPanel::onDisplayRemoving( DisplayWrapper* wrapper ) 00583 { 00584 property_grid_->Freeze(); 00585 } 00586 00587 void DisplaysPanel::onDisplayRemoved( DisplayWrapper* wrapper ) 00588 { 00589 M_DisplayToIndex::iterator it = display_map_.find(wrapper); 00590 ROS_ASSERT(it != display_map_.end()); 00591 00592 uint32_t index = it->second; 00593 00594 display_map_.erase(it); 00595 00596 it = display_map_.begin(); 00597 M_DisplayToIndex::iterator end = display_map_.end(); 00598 for (;it != end; ++it) 00599 { 00600 if (it->second > index) 00601 { 00602 --it->second; 00603 setDisplayCategoryLabel(it->first, it->second); 00604 } 00605 } 00606 00607 sortDisplays(); 00608 00609 property_grid_->Refresh(); 00610 property_grid_->Thaw(); 00611 } 00612 00613 void DisplaysPanel::onDisplaysRemoving( const V_DisplayWrapper& displays ) 00614 { 00615 property_grid_->Freeze(); 00616 } 00617 00618 void DisplaysPanel::onDisplaysRemoved( const V_DisplayWrapper& displays ) 00619 { 00620 property_grid_->Thaw(); 00621 } 00622 00623 void DisplaysPanel::onDisplaysConfigLoaded(const boost::shared_ptr<wxConfigBase>& config) 00624 { 00625 wxString grid_state; 00626 if ( config->Read( PROPERTY_GRID_CONFIG, &grid_state ) ) 00627 { 00628 property_grid_->RestoreEditableState( grid_state ); 00629 } 00630 } 00631 00632 void DisplaysPanel::onDisplaysConfigSaving(const boost::shared_ptr<wxConfigBase>& config) 00633 { 00634 config->Write( PROPERTY_GRID_CONFIG, property_grid_->SaveEditableState() ); 00635 } 00636 00637 } // namespace rviz