<commit_before>#include "RendererBase.hpp"

#include <iostream>
#include <sstream>
#include <thread>
#include <mutex>
#include <unordered_map>

#include <gtkmm.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <lcm/lcm-cpp.hpp>
#include <drc_utils/Clock.hpp>

#include <lcmtypes/drc/data_request_list_t.hpp>
#include <lcmtypes/drc/twist_timed_t.hpp>
#include <lcmtypes/drc/map_image_t.hpp>

#include <bot_vis/viewer.h>

// TODO: slow sweep commands

using namespace maps;

class DataControlRenderer : public RendererBase {
protected:
  enum ChannelType {
    ChannelTypeAnonymous,
    ChannelTypeDepthImage,
  };

  struct RequestControl {
    const int mId;
    bool mEnabled;
    double mPeriod;
    typedef std::shared_ptr<RequestControl> Ptr;
  };

  struct TimeKeeper {
    int64_t mLastUpdateTime;
    Gtk::Label* mLabel;
    TimeKeeper() : mLastUpdateTime(-1), mLabel(NULL) {}
  };

  struct LastUpdateChecker {
    DataControlRenderer* mRenderer;
    std::thread mThread;
    bool mIsRunning;

    LastUpdateChecker(DataControlRenderer* iRenderer) : mRenderer(iRenderer) {
      mThread = std::thread(std::ref(*this));
    }

    ~LastUpdateChecker() {
      mIsRunning = false;
      mThread.join();
    }

    void operator()() {
      mIsRunning = true;
      while (mIsRunning) {
        int64_t currentTime = drc::Clock::instance()->getCurrentWallTime();
        std::unordered_map<std::string, TimeKeeper>::const_iterator iter;
        {
          std::lock_guard<std::mutex> lock(mRenderer->mTimeKeepersMutex);
          for (iter = mRenderer->mTimeKeepers.begin();
               iter != mRenderer->mTimeKeepers.end(); ++iter) {
            int64_t lastUpdateTime = iter->second.mLastUpdateTime;
            if (lastUpdateTime < 0) continue;
            int dtSec = (currentTime - lastUpdateTime)/1000000;
            if (dtSec > 0) {
              std::string text = static_cast<std::ostringstream*>
                (&(std::ostringstream() << dtSec) )->str();
              text = "(" + text + "s)";
              iter->second.mLabel->set_text(text);
            }
          }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
      }
    }
  };

protected:
  Gtk::VBox* mRequestControlBox;
  std::unordered_map<int, RequestControl::Ptr> mRequestControls;
  int mSpinRate;

  std::shared_ptr<LastUpdateChecker> mUpdateChecker;
  std::unordered_map<std::string, ChannelType> mChannels;
  std::unordered_map<std::string, TimeKeeper> mTimeKeepers;
  std::mutex mTimeKeepersMutex;

public:

  DataControlRenderer(BotViewer* iViewer, const int iPriority,
                      const lcm_t* iLcm,
                      const BotParam* iParam, const BotFrames* iFrames)
    : RendererBase("Data Control", iViewer, iPriority, iLcm,
                   iParam, iFrames, 0) {

    // set up robot time clock
    drc::Clock::instance()->setLcm(getLcm());
    drc::Clock::instance()->setVerbose(false);

    // create and show ui widgets
    setupWidgets();

    // create subscriptions and handlers
    mUpdateChecker.reset(new LastUpdateChecker(this));
  }

  ~DataControlRenderer() {
    mUpdateChecker->mIsRunning = false;
    mUpdateChecker.reset();
  }

  void onMessage(const lcm::ReceiveBuffer* iBuf, const std::string& iChannel) {
    std::unordered_map<std::string, ChannelType>::const_iterator channelItem =
      mChannels.find(iChannel);
    if (channelItem == mChannels.end()) return;
    std::string key = iChannel;
    if (channelItem->second == ChannelTypeDepthImage) {
      drc::map_image_t msg;
      if (msg.decode(iBuf->data, 0, iBuf->data_size) < 0) {
        std::cout << "Error decoding " << iChannel << std::endl;
        return;
      }
      key += static_cast<std::ostringstream*>
        (&(std::ostringstream() << msg.view_id) )->str();
    }
    else {
    }
    {
      std::lock_guard<std::mutex> lock(mTimeKeepersMutex);
      mTimeKeepers[key].mLastUpdateTime =
        drc::Clock::instance()->getCurrentWallTime();
      mTimeKeepers[key].mLabel->set_text("");
    }
  }

  void setupWidgets() {
    Gtk::Container* container = getGtkContainer();

    Gtk::Notebook* notebook = Gtk::manage(new Gtk::Notebook());

    // for data requests
    mRequestControlBox = Gtk::manage(new Gtk::VBox());
    typedef drc::data_request_t dr;
    addControl(drc::data_request_t::CAMERA_IMAGE, "Camera Image",
               "CAMERALEFT_COMPRESSED", ChannelTypeAnonymous);
    addControl(drc::data_request_t::MINIMAL_ROBOT_STATE, "Robot State",
               "EST_ROBOT_STATE", ChannelTypeAnonymous);
    addControl(drc::data_request_t::AFFORDANCE_LIST, "Affordance List",
               "AFFORDANCE_LIST", ChannelTypeAnonymous);
    addControl(drc::data_request_t::MAP_CATALOG, "Map Catalog",
               "MAP_CATALOG", ChannelTypeAnonymous);
    addControl(drc::data_request_t::OCTREE_SCENE, "Scene Octree",
               "MAP_OCTREE", ChannelTypeAnonymous);
    addControl(drc::data_request_t::HEIGHT_MAP_SCENE, "Scene Height",
               "MAP_DEPTH", ChannelTypeDepthImage);
    addControl(drc::data_request_t::HEIGHT_MAP_CORRIDOR, "Corridor Height",
               "MAP_DEPTH", ChannelTypeDepthImage);
    addControl(drc::data_request_t::DEPTH_MAP_SCENE, "Scene Depth",
               "MAP_DEPTH", ChannelTypeDepthImage);
    addControl(drc::data_request_t::DEPTH_MAP_WORKSPACE, "Workspace Depth",
               "MAP_DEPTH", ChannelTypeDepthImage);
    Gtk::Button* button = Gtk::manage(new Gtk::Button("Submit Request"));
    button->signal_clicked().connect
      (sigc::mem_fun(*this, &DataControlRenderer::onDataRequestButton));
    mRequestControlBox->add(*button);
    notebook->append_page(*mRequestControlBox, "Data");

    // for sensor control
    Gtk::VBox* sensorControlBox = Gtk::manage(new Gtk::VBox());
    mSpinRate = 15;
    addSpin("Spin Rate (rpm)", mSpinRate, 0, 60, 1, sensorControlBox);
    button = Gtk::manage(new Gtk::Button("Submit Rate"));
    button->signal_clicked().connect
      (sigc::mem_fun(*this, &DataControlRenderer::onRateControlButton));
    sensorControlBox->pack_start(*button, false, false);
    notebook->append_page(*sensorControlBox, "Sensor");
    
    container->add(*notebook);
    container->show_all();
  }

  void addControl(const int iId, const std::string& iLabel,
                  const std::string& iChannel, const ChannelType iChannelType) {
    Gtk::HBox* box = Gtk::manage(new Gtk::HBox());
    Gtk::CheckButton* check = Gtk::manage(new Gtk::CheckButton());
    Gtk::Label* label = Gtk::manage(new Gtk::Label(iLabel));
    Gtk::SpinButton* spin = Gtk::manage(new Gtk::SpinButton());
    Gtk::Label* ageLabel = new Gtk::Label("");
    spin->set_range(0, 10);
    spin->set_increments(1, 2);
    spin->set_digits(0);
    box->add(*check);
    box->add(*label);
    box->add(*ageLabel);
    box->add(*spin);
    RequestControl::Ptr group(new RequestControl());
    group->mEnabled = false;
    group->mPeriod = 0;
    bind(check, iLabel + " enable", group->mEnabled);<commit_msg>manage label memory to avoid leak<commit_after>#include "RendererBase.hpp"

#include <iostream>
#include <sstream>
#include <thread>
#include <mutex>
#include <unordered_map>

#include <gtkmm.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <lcm/lcm-cpp.hpp>
#include <drc_utils/Clock.hpp>

#include <lcmtypes/drc/data_request_list_t.hpp>
#include <lcmtypes/drc/twist_timed_t.hpp>
#include <lcmtypes/drc/map_image_t.hpp>

#include <bot_vis/viewer.h>

// TODO: slow sweep commands

using namespace maps;

class DataControlRenderer : public RendererBase {
protected:
  enum ChannelType {
    ChannelTypeAnonymous,
    ChannelTypeDepthImage,
  };

  struct RequestControl {
    const int mId;
    bool mEnabled;
    double mPeriod;
    typedef std::shared_ptr<RequestControl> Ptr;
  };

  struct TimeKeeper {
    int64_t mLastUpdateTime;
    Gtk::Label* mLabel;
    TimeKeeper() : mLastUpdateTime(-1), mLabel(NULL) {}
  };

  struct LastUpdateChecker {
    DataControlRenderer* mRenderer;
    std::thread mThread;
    bool mIsRunning;

    LastUpdateChecker(DataControlRenderer* iRenderer) : mRenderer(iRenderer) {
      mThread = std::thread(std::ref(*this));
    }

    ~LastUpdateChecker() {
      mIsRunning = false;
      mThread.join();
    }

    void operator()() {
      mIsRunning = true;
      while (mIsRunning) {
        int64_t currentTime = drc::Clock::instance()->getCurrentWallTime();
        std::unordered_map<std::string, TimeKeeper>::const_iterator iter;
        {
          std::lock_guard<std::mutex> lock(mRenderer->mTimeKeepersMutex);
          for (iter = mRenderer->mTimeKeepers.begin();
               iter != mRenderer->mTimeKeepers.end(); ++iter) {
            int64_t lastUpdateTime = iter->second.mLastUpdateTime;
            if (lastUpdateTime < 0) continue;
            int dtSec = (currentTime - lastUpdateTime)/1000000;
            if (dtSec > 0) {
              std::string text = static_cast<std::ostringstream*>
                (&(std::ostringstream() << dtSec) )->str();
              text = "(" + text + "s)";
              iter->second.mLabel->set_text(text);
            }
          }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
      }
    }
  };

protected:
  Gtk::VBox* mRequestControlBox;
  std::unordered_map<int, RequestControl::Ptr> mRequestControls;
  int mSpinRate;

  std::shared_ptr<LastUpdateChecker> mUpdateChecker;
  std::unordered_map<std::string, ChannelType> mChannels;
  std::unordered_map<std::string, TimeKeeper> mTimeKeepers;
  std::mutex mTimeKeepersMutex;

public:

  DataControlRenderer(BotViewer* iViewer, const int iPriority,
                      const lcm_t* iLcm,
                      const BotParam* iParam, const BotFrames* iFrames)
    : RendererBase("Data Control", iViewer, iPriority, iLcm,
                   iParam, iFrames, 0) {

    // set up robot time clock
    drc::Clock::instance()->setLcm(getLcm());
    drc::Clock::instance()->setVerbose(false);

    // create and show ui widgets
    setupWidgets();

    // create update timers
    mUpdateChecker.reset(new LastUpdateChecker(this));
  }

  ~DataControlRenderer() {
    mUpdateChecker->mIsRunning = false;
    mUpdateChecker.reset();
  }

  void onMessage(const lcm::ReceiveBuffer* iBuf, const std::string& iChannel) {
    std::unordered_map<std::string, ChannelType>::const_iterator channelItem =
      mChannels.find(iChannel);
    if (channelItem == mChannels.end()) return;
    std::string key = iChannel;
    if (channelItem->second == ChannelTypeDepthImage) {
      drc::map_image_t msg;
      if (msg.decode(iBuf->data, 0, iBuf->data_size) < 0) {
        std::cout << "Error decoding " << iChannel << std::endl;
        return;
      }
      key += static_cast<std::ostringstream*>
        (&(std::ostringstream() << msg.view_id) )->str();
    }
    else {
    }
    {
      std::lock_guard<std::mutex> lock(mTimeKeepersMutex);
      mTimeKeepers[key].mLastUpdateTime =
        drc::Clock::instance()->getCurrentWallTime();
      mTimeKeepers[key].mLabel->set_text("");
    }
  }

  void setupWidgets() {
    Gtk::Container* container = getGtkContainer();

    Gtk::Notebook* notebook = Gtk::manage(new Gtk::Notebook());

    // for data requests
    mRequestControlBox = Gtk::manage(new Gtk::VBox());
    typedef drc::data_request_t dr;
    addControl(drc::data_request_t::CAMERA_IMAGE, "Camera Image",
               "CAMERALEFT_COMPRESSED", ChannelTypeAnonymous);
    addControl(drc::data_request_t::MINIMAL_ROBOT_STATE, "Robot State",
               "EST_ROBOT_STATE", ChannelTypeAnonymous);
    addControl(drc::data_request_t::AFFORDANCE_LIST, "Affordance List",
               "AFFORDANCE_LIST", ChannelTypeAnonymous);
    addControl(drc::data_request_t::MAP_CATALOG, "Map Catalog",
               "MAP_CATALOG", ChannelTypeAnonymous);
    addControl(drc::data_request_t::OCTREE_SCENE, "Scene Octree",
               "MAP_OCTREE", ChannelTypeAnonymous);
    addControl(drc::data_request_t::HEIGHT_MAP_SCENE, "Scene Height",
               "MAP_DEPTH", ChannelTypeDepthImage);
    addControl(drc::data_request_t::HEIGHT_MAP_CORRIDOR, "Corridor Height",
               "MAP_DEPTH", ChannelTypeDepthImage);
    addControl(drc::data_request_t::DEPTH_MAP_SCENE, "Scene Depth",
               "MAP_DEPTH", ChannelTypeDepthImage);
    addControl(drc::data_request_t::DEPTH_MAP_WORKSPACE, "Workspace Depth",
               "MAP_DEPTH", ChannelTypeDepthImage);
    Gtk::Button* button = Gtk::manage(new Gtk::Button("Submit Request"));
    button->signal_clicked().connect
      (sigc::mem_fun(*this, &DataControlRenderer::onDataRequestButton));
    mRequestControlBox->add(*button);
    notebook->append_page(*mRequestControlBox, "Data");

    // for sensor control
    Gtk::VBox* sensorControlBox = Gtk::manage(new Gtk::VBox());
    mSpinRate = 15;
    addSpin("Spin Rate (rpm)", mSpinRate, 0, 60, 1, sensorControlBox);
    button = Gtk::manage(new Gtk::Button("Submit Rate"));
    button->signal_clicked().connect
      (sigc::mem_fun(*this, &DataControlRenderer::onRateControlButton));
    sensorControlBox->pack_start(*button, false, false);
    notebook->append_page(*sensorControlBox, "Sensor");
    
    container->add(*notebook);
    container->show_all();
  }

  void addControl(const int iId, const std::string& iLabel,
                  const std::string& iChannel, const ChannelType iChannelType) {
    Gtk::HBox* box = Gtk::manage(new Gtk::HBox());
    Gtk::CheckButton* check = Gtk::manage(new Gtk::CheckButton());
    Gtk::Label* label = Gtk::manage(new Gtk::Label(iLabel));
    Gtk::SpinButton* spin = Gtk::manage(new Gtk::SpinButton());
    Gtk::Label* ageLabel = Gtk::manage(new Gtk::Label(" "));
    spin->set_range(0, 10);
    spin->set_increments(1, 2);
    spin->set_digits(0);
    box->add(*check);
    box->add(*label);
    box->add(*ageLabel);
    box->add(*spin);
    RequestControl::Ptr group(new RequestControl());
    group->mEnabled = false;
    group->mPeriod = 0;
    bind(check, iLabel + " enable", group->mEnabled);
{'fraction_non_alphanumeric': 0.14064837905236907, 'fraction_numerical': 0.004987531172069825, 'mean_word_length': 3.57496740547588, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 125, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '141478', 'n_tokens_mistral': 4713, 'n_tokens_neox': 4552, 'n_words': 795}