<commit_before>#include "selfdrive/ui/qt/setup/setup.h"

#include <cstdio>
#include <cstdlib>
#include <sstream>

#include <QApplication>
#include <QLabel>
#include <QVBoxLayout>

#include <curl/curl.h>

#include "selfdrive/hardware/hw.h"
#include "selfdrive/ui/qt/api.h"
#include "selfdrive/ui/qt/qt_window.h"
#include "selfdrive/ui/qt/offroad/networking.h"
#include "selfdrive/ui/qt/widgets/input.h"

const char* USER_AGENT = "AGNOSSetup-0.1";
const QString DASHCAM_URL = "https://dashcam.comma.ai";

void Setup::download(QString url) {
  CURL *curl = curl_easy_init();
  if (!curl) {
    emit finished(false);
    return;
  }

  char tmpfile[] = "/tmp/installer_XXXXXX";
  FILE *fp = fdopen(mkstemp(tmpfile), "w");

  curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
  curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);

  int ret = curl_easy_perform(curl);

  long res_status = 0;
  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status);
  if (ret == CURLE_OK && res_status == 200) {
    rename(tmpfile, "/tmp/installer");
    emit finished(true);
  } else {
    emit finished(false);
  }

  curl_easy_cleanup(curl);
  fclose(fp);
}

QWidget * Setup::low_voltage() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 0, 55, 55);
  main_layout->setSpacing(0);

  // inner text layout: warning icon, title, and body
  QVBoxLayout *inner_layout = new QVBoxLayout();
  inner_layout->setContentsMargins(110, 144, 365, 0);
  main_layout->addLayout(inner_layout);

  QLabel *triangle = new QLabel();
  triangle->setPixmap(QPixmap(ASSET_PATH + "offroad/icon_warning.png"));
  inner_layout->addWidget(triangle, 0, Qt::AlignTop | Qt::AlignLeft);
  inner_layout->addSpacing(80);

  QLabel *title = new QLabel("WARNING: Low Voltage");
  title->setStyleSheet("font-size: 90px; font-weight: 500; color: #FF594F;");
  inner_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);

  inner_layout->addSpacing(25);

  QLabel *body = new QLabel("Power your device in a car with a harness or proceed at your own risk.");
  body->setWordWrap(true);
  body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
  body->setStyleSheet("font-size: 80px; font-weight: 300;");
  inner_layout->addWidget(body);

  inner_layout->addStretch();

  // power off + continue buttons
  QHBoxLayout *blayout = new QHBoxLayout();
  blayout->setSpacing(50);
  main_layout->addLayout(blayout, 0);

  QPushButton *poweroff = new QPushButton("Power off");
  poweroff->setObjectName("navBtn");
  blayout->addWidget(poweroff);
  QObject::connect(poweroff, &QPushButton::clicked, this, [=]() {
    Hardware::poweroff();
  });

  QPushButton *cont = new QPushButton("Continue");
  cont->setObjectName("navBtn");
  blayout->addWidget(cont);
  QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);

  return widget;
}

QWidget * Setup::getting_started() {
  QWidget *widget = new QWidget();

  QHBoxLayout *main_layout = new QHBoxLayout(widget);
  main_layout->setMargin(0);

  QVBoxLayout *vlayout = new QVBoxLayout();
  vlayout->setContentsMargins(165, 280, 100, 0);
  main_layout->addLayout(vlayout);

  QLabel *title = new QLabel("Getting Started");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  vlayout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);

  vlayout->addSpacing(90);
  QLabel *desc = new QLabel("Before we get on the road, let’s finish installation and cover some details.");
  desc->setWordWrap(true);
  desc->setStyleSheet("font-size: 80px; font-weight: 300;");
  vlayout->addWidget(desc, 0, Qt::AlignTop | Qt::AlignLeft);

  vlayout->addStretch();

  QPushButton *btn = new QPushButton();
  btn->setIcon(QIcon(":/img_continue_triangle.svg"));
  btn->setIconSize(QSize(54, 106));
  btn->setFixedSize(310, 1080);
  btn->setProperty("primary", true);
  btn->setStyleSheet("border: none;");
  main_layout->addWidget(btn, 0, Qt::AlignRight);
  QObject::connect(btn, &QPushButton::clicked, this, &Setup::nextPage);

  return widget;
}

QWidget * Setup::network_setup() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 50, 55, 50);

  // title
  QLabel *title = new QLabel("Connect to Wi-Fi");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);

  main_layout->addSpacing(25);

  // wifi widget
  Networking *networking = new Networking(this, false);
  networking->setStyleSheet("Networking {background-color: #292929; border-radius: 13px;}");
  main_layout->addWidget(networking, 1);

  main_layout->addSpacing(35);

  // back + continue buttons
  QHBoxLayout *blayout = new QHBoxLayout;
  main_layout->addLayout(blayout);
  blayout->setSpacing(50);

  QPushButton *back = new QPushButton("Back");
  back->setObjectName("navBtn");
  QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
  blayout->addWidget(back);

  QPushButton *cont = new QPushButton();
  cont->setObjectName("navBtn");
  cont->setProperty("primary", true);
  QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
  blayout->addWidget(cont);

  // setup timer for testing internet connection
  HttpRequest *request = new HttpRequest(this, false, 2500);
  QObject::connect(request, &HttpRequest::requestDone, [=](const QString &, bool success) {
    cont->setEnabled(success);
    if (success) {
      const bool cell = networking->wifi->currentNetworkType() == NetworkType::CELL;
      cont->setText(cell ? "Continue without Wi-Fi" : "Continue");
    } else {
      cont->setText("Waiting for internet");
    }
    repaint();
  });
  request->sendRequest(DASHCAM_URL);
  QTimer *timer = new QTimer(this);
  QObject::connect(timer, &QTimer::timeout, [=]() {
    if (!request->active() && cont->isVisible()) {
      request->sendRequest(DASHCAM_URL);
    }
  });
  timer->start(1000);

  return widget;
}

QWidget * radio_button(QString title, QButtonGroup *group) {
  QPushButton *btn = new QPushButton(title);
  btn->setCheckable(true);
  group->addButton(btn);
  btn->setStyleSheet(R"(
    QPushButton {
      height: 230;
      padding-left: 100px;
      padding-right: 100px;
      text-align: left;
      font-size: 80px;
      font-weight: 400;
      border-radius: 10px;
      background-color: #4F4F4F;
    }
    QPushButton:checked {
      background-color: #465BEA;
    }
  )");

  // checkmark icon
  QPixmap pix(":/img_circled_check.svg");
  btn->setIcon(pix);
  btn->setIconSize(QSize(0, 0));
  btn->setLayoutDirection(Qt::RightToLeft);
  QObject::connect(btn, &QPushButton::toggled, [=](bool checked) {
    btn->setIconSize(checked ? QSize(104, 104) : QSize(0, 0));
  });
  return btn;
}

QWidget * Setup::software_selection() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 50, 55, 50);
  main_layout->setSpacing(0);

  // title
  QLabel *title = new QLabel("Choose Software to Install");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);

  main_layout->addSpacing(50);

  // dashcam + custom radio buttons
  QButtonGroup *group = new QButtonGroup(widget);
  group->setExclusive(true);

  QWidget *dashcam = radio_button("Dashcam", group);
  main_layout->addWidget(dashcam);

  main_layout->addSpacing(30);

  QWidget *custom = radio_button("Custom Software", group);
  main_layout->addWidget(custom);

  main_layout->addStretch();

  // back + continue buttons
  QHBoxLayout *blayout = new QHBoxLayout;
  main_layout->addLayout(blayout);
  blayout->setSpacing(50);

  QPushButton *back = new QPushButton("Back");
  back->setObjectName("navBtn");
  QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
  blayout->addWidget(back);

  QPushButton *cont = new QPushButton("Continue");
  cont->setObjectName("navBtn");
  cont->setEnabled(false);
  cont->setProperty("primary", true);
  blayout->addWidget(cont);

  QObject::connect(cont, &QPushButton::clicked, [=]() {
    auto w = currentWidget();
    QTimer::singleShot(0, [=]() {
      setCurrentWidget(downloading_widget);
    });
    QString url = DASHCAM_URL;
    if (group->checkedButton() != dashcam) {
      url = InputDialog::getText("Enter URL", this, "for Custom Software");
    }
    if (!url.isEmpty()) {
      QTimer::singleShot(1000, this, [=]() {
        download(url);
      });
    } else {
      setCurrentWidget(w);
    }
  });

  connect(group, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *btn) {
    btn->setChecked(true);
    cont->setEnabled(true);
  });

  return widget;
}

QWidget * Setup::downloading() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  QLabel *txt = new QLabel("Downloading...");
  txt->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(txt, 0, Qt::AlignCenter);
  return widget;
}

QWidget * Setup::download_failed() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 225, 55, 55);
  main_layout->setSpacing(0);

  QLabel *title = new QLabel("Download Failed");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);

  main_layout->addSpacing(67);

  QLabel *body = new QLabel("Ensure the entered URL is valid, and the device’s internet connection is good.");
  body->setWordWrap(true);
  body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
  body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;");
  main_layout->addWidget(body);

  main_layout->addStretch();

  // reboot + start over buttons
  QHBoxLayout *blayout = new QHBoxLayout();
  blayout->setSpacing(50);
  main_layout->addLayout(blayout, 0);

  QPushButton *reboot = new QPushButton("Reboot device");
  reboot->setObjectName("navBtn");
  blayout->addWidget(reboot);
  QObject::connect(reboot, &QPushButton::clicked, this, [=]() {
    Hardware::reboot();
  });

  QPushButton *restart = new QPushButton("Start over");
  restart->setObjectName("navBtn");
  restart->setProperty("primary", true);
  blayout->addWidget(restart);
  QObject::connect(restart, &QPushButton::clicked, this, [=]() {
    setCurrentIndex(2);
  });

  widget->setStyleSheet(R"(
    QLabel {
      margin-left: 117;
    }
  )");
  return widget;
}

void Setup::prevPage() {
  setCurrentIndex(currentIndex() - 1);
}

void Setup::nextPage() {
  setCurrentIndex(currentIndex() + 1);
}

Setup::Setup(QWidget *parent) : QStackedWidget(parent) {
  std::stringstream buffer;
  buffer << std::ifstream("/sys/class/hwmon/hwmon1/in1_input").rdbuf();
  float voltage = (float)std::atoi(buffer.str().c_str()) / 1000.;
  if (voltage < 7) {
    addWidget(low_voltage());
  }

  addWidget(getting_started());
  addWidget(network_setup());
  addWidget(software_selection());

  downloading_widget = downloading();
  addWidget(downloading_widget);

  failed_widget = download_failed();
  addWidget(failed_widget);

  QObject::connect(this, &Setup::finished, [=](bool success) {
    // hide setup on success
    qDebug() << "finished" << success;
    if (success) {
      QTimer::singleShot(3000, this, &QWidget::hide);
    } else {
      setCurrentWidget(failed_widget);
    }
  });

  // TODO: revisit pressed bg color
  setStyleSheet(R"(
    * {
      color: white;
      font-family: Inter;
    }
    Setup {
      background-color: black;
    }
    QPushButton#navBtn {
      height: 160;
      font-size: 55px;
      font-weight: 400;
      border-radius: 10px;
      background-color: #333333;
    }
    QPushButton#navBtn:disabled, QPushButton[primary='true']:disabled {
      color: #808080;
      background-color: #333333;
    }
    QPushButton#navBtn:pressed {
      background-color: #444444;
    }
    QPushButton[primary='true'], #navBtn[primary='true'] {
      background-color: #465BEA;
    }
    QPushButton[primary='true']:pressed, #navBtn:pressed[primary='true'] {
      background-color: #3049F4;
    }
  )");
}

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  Setup setup;
  setMainWindow(&setup);
  return a.exec();
}
<commit_msg>setup: add OS version to user agent (#23656)<commit_after>#include "selfdrive/ui/qt/setup/setup.h"

#include <cstdio>
#include <cstdlib>
#include <sstream>

#include <QApplication>
#include <QLabel>
#include <QVBoxLayout>

#include <curl/curl.h>

#include "selfdrive/common/util.h"
#include "selfdrive/hardware/hw.h"
#include "selfdrive/ui/qt/api.h"
#include "selfdrive/ui/qt/qt_window.h"
#include "selfdrive/ui/qt/offroad/networking.h"
#include "selfdrive/ui/qt/widgets/input.h"

const std::string USER_AGENT = "AGNOSSetup-";
const QString DASHCAM_URL = "https://dashcam.comma.ai";

void Setup::download(QString url) {
  CURL *curl = curl_easy_init();
  if (!curl) {
    emit finished(false);
    return;
  }

  auto version = util::read_file("/VERSION");

  char tmpfile[] = "/tmp/installer_XXXXXX";
  FILE *fp = fdopen(mkstemp(tmpfile), "w");

  curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
  curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl, CURLOPT_USERAGENT, (USER_AGENT + version).c_str());

  int ret = curl_easy_perform(curl);

  long res_status = 0;
  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status);
  if (ret == CURLE_OK && res_status == 200) {
    rename(tmpfile, "/tmp/installer");
    emit finished(true);
  } else {
    emit finished(false);
  }

  curl_easy_cleanup(curl);
  fclose(fp);
}

QWidget * Setup::low_voltage() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 0, 55, 55);
  main_layout->setSpacing(0);

  // inner text layout: warning icon, title, and body
  QVBoxLayout *inner_layout = new QVBoxLayout();
  inner_layout->setContentsMargins(110, 144, 365, 0);
  main_layout->addLayout(inner_layout);

  QLabel *triangle = new QLabel();
  triangle->setPixmap(QPixmap(ASSET_PATH + "offroad/icon_warning.png"));
  inner_layout->addWidget(triangle, 0, Qt::AlignTop | Qt::AlignLeft);
  inner_layout->addSpacing(80);

  QLabel *title = new QLabel("WARNING: Low Voltage");
  title->setStyleSheet("font-size: 90px; font-weight: 500; color: #FF594F;");
  inner_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);

  inner_layout->addSpacing(25);

  QLabel *body = new QLabel("Power your device in a car with a harness or proceed at your own risk.");
  body->setWordWrap(true);
  body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
  body->setStyleSheet("font-size: 80px; font-weight: 300;");
  inner_layout->addWidget(body);

  inner_layout->addStretch();

  // power off + continue buttons
  QHBoxLayout *blayout = new QHBoxLayout();
  blayout->setSpacing(50);
  main_layout->addLayout(blayout, 0);

  QPushButton *poweroff = new QPushButton("Power off");
  poweroff->setObjectName("navBtn");
  blayout->addWidget(poweroff);
  QObject::connect(poweroff, &QPushButton::clicked, this, [=]() {
    Hardware::poweroff();
  });

  QPushButton *cont = new QPushButton("Continue");
  cont->setObjectName("navBtn");
  blayout->addWidget(cont);
  QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);

  return widget;
}

QWidget * Setup::getting_started() {
  QWidget *widget = new QWidget();

  QHBoxLayout *main_layout = new QHBoxLayout(widget);
  main_layout->setMargin(0);

  QVBoxLayout *vlayout = new QVBoxLayout();
  vlayout->setContentsMargins(165, 280, 100, 0);
  main_layout->addLayout(vlayout);

  QLabel *title = new QLabel("Getting Started");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  vlayout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);

  vlayout->addSpacing(90);
  QLabel *desc = new QLabel("Before we get on the road, let’s finish installation and cover some details.");
  desc->setWordWrap(true);
  desc->setStyleSheet("font-size: 80px; font-weight: 300;");
  vlayout->addWidget(desc, 0, Qt::AlignTop | Qt::AlignLeft);

  vlayout->addStretch();

  QPushButton *btn = new QPushButton();
  btn->setIcon(QIcon(":/img_continue_triangle.svg"));
  btn->setIconSize(QSize(54, 106));
  btn->setFixedSize(310, 1080);
  btn->setProperty("primary", true);
  btn->setStyleSheet("border: none;");
  main_layout->addWidget(btn, 0, Qt::AlignRight);
  QObject::connect(btn, &QPushButton::clicked, this, &Setup::nextPage);

  return widget;
}

QWidget * Setup::network_setup() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 50, 55, 50);

  // title
  QLabel *title = new QLabel("Connect to Wi-Fi");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);

  main_layout->addSpacing(25);

  // wifi widget
  Networking *networking = new Networking(this, false);
  networking->setStyleSheet("Networking {background-color: #292929; border-radius: 13px;}");
  main_layout->addWidget(networking, 1);

  main_layout->addSpacing(35);

  // back + continue buttons
  QHBoxLayout *blayout = new QHBoxLayout;
  main_layout->addLayout(blayout);
  blayout->setSpacing(50);

  QPushButton *back = new QPushButton("Back");
  back->setObjectName("navBtn");
  QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
  blayout->addWidget(back);

  QPushButton *cont = new QPushButton();
  cont->setObjectName("navBtn");
  cont->setProperty("primary", true);
  QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
  blayout->addWidget(cont);

  // setup timer for testing internet connection
  HttpRequest *request = new HttpRequest(this, false, 2500);
  QObject::connect(request, &HttpRequest::requestDone, [=](const QString &, bool success) {
    cont->setEnabled(success);
    if (success) {
      const bool cell = networking->wifi->currentNetworkType() == NetworkType::CELL;
      cont->setText(cell ? "Continue without Wi-Fi" : "Continue");
    } else {
      cont->setText("Waiting for internet");
    }
    repaint();
  });
  request->sendRequest(DASHCAM_URL);
  QTimer *timer = new QTimer(this);
  QObject::connect(timer, &QTimer::timeout, [=]() {
    if (!request->active() && cont->isVisible()) {
      request->sendRequest(DASHCAM_URL);
    }
  });
  timer->start(1000);

  return widget;
}

QWidget * radio_button(QString title, QButtonGroup *group) {
  QPushButton *btn = new QPushButton(title);
  btn->setCheckable(true);
  group->addButton(btn);
  btn->setStyleSheet(R"(
    QPushButton {
      height: 230;
      padding-left: 100px;
      padding-right: 100px;
      text-align: left;
      font-size: 80px;
      font-weight: 400;
      border-radius: 10px;
      background-color: #4F4F4F;
    }
    QPushButton:checked {
      background-color: #465BEA;
    }
  )");

  // checkmark icon
  QPixmap pix(":/img_circled_check.svg");
  btn->setIcon(pix);
  btn->setIconSize(QSize(0, 0));
  btn->setLayoutDirection(Qt::RightToLeft);
  QObject::connect(btn, &QPushButton::toggled, [=](bool checked) {
    btn->setIconSize(checked ? QSize(104, 104) : QSize(0, 0));
  });
  return btn;
}

QWidget * Setup::software_selection() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 50, 55, 50);
  main_layout->setSpacing(0);

  // title
  QLabel *title = new QLabel("Choose Software to Install");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);

  main_layout->addSpacing(50);

  // dashcam + custom radio buttons
  QButtonGroup *group = new QButtonGroup(widget);
  group->setExclusive(true);

  QWidget *dashcam = radio_button("Dashcam", group);
  main_layout->addWidget(dashcam);

  main_layout->addSpacing(30);

  QWidget *custom = radio_button("Custom Software", group);
  main_layout->addWidget(custom);

  main_layout->addStretch();

  // back + continue buttons
  QHBoxLayout *blayout = new QHBoxLayout;
  main_layout->addLayout(blayout);
  blayout->setSpacing(50);

  QPushButton *back = new QPushButton("Back");
  back->setObjectName("navBtn");
  QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
  blayout->addWidget(back);

  QPushButton *cont = new QPushButton("Continue");
  cont->setObjectName("navBtn");
  cont->setEnabled(false);
  cont->setProperty("primary", true);
  blayout->addWidget(cont);

  QObject::connect(cont, &QPushButton::clicked, [=]() {
    auto w = currentWidget();
    QTimer::singleShot(0, [=]() {
      setCurrentWidget(downloading_widget);
    });
    QString url = DASHCAM_URL;
    if (group->checkedButton() != dashcam) {
      url = InputDialog::getText("Enter URL", this, "for Custom Software");
    }
    if (!url.isEmpty()) {
      QTimer::singleShot(1000, this, [=]() {
        download(url);
      });
    } else {
      setCurrentWidget(w);
    }
  });

  connect(group, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *btn) {
    btn->setChecked(true);
    cont->setEnabled(true);
  });

  return widget;
}

QWidget * Setup::downloading() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  QLabel *txt = new QLabel("Downloading...");
  txt->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(txt, 0, Qt::AlignCenter);
  return widget;
}

QWidget * Setup::download_failed() {
  QWidget *widget = new QWidget();
  QVBoxLayout *main_layout = new QVBoxLayout(widget);
  main_layout->setContentsMargins(55, 225, 55, 55);
  main_layout->setSpacing(0);

  QLabel *title = new QLabel("Download Failed");
  title->setStyleSheet("font-size: 90px; font-weight: 500;");
  main_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);

  main_layout->addSpacing(67);

  QLabel *body = new QLabel("Ensure the entered URL is valid, and the device’s internet connection is good.");
  body->setWordWrap(true);
  body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
  body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;");
  main_layout->addWidget(body);

  main_layout->addStretch();

  // reboot + start over buttons
  QHBoxLayout *blayout = new QHBoxLayout();
  blayout->setSpacing(50);
  main_layout->addLayout(blayout, 0);

  QPushButton *reboot = new QPushButton("Reboot device");
  reboot->setObjectName("navBtn");
  blayout->addWidget(reboot);
  QObject::connect(reboot, &QPushButton::clicked, this, [=]() {
    Hardware::reboot();
  });

  QPushButton *restart = new QPushButton("Start over");
  restart->setObjectName("navBtn");
  restart->setProperty("primary", true);
  blayout->addWidget(restart);
  QObject::connect(restart, &QPushButton::clicked, this, [=]() {
    setCurrentIndex(2);
  });

  widget->setStyleSheet(R"(
    QLabel {
      margin-left: 117;
    }
  )");
  return widget;
}

void Setup::prevPage() {
  setCurrentIndex(currentIndex() - 1);
}

void Setup::nextPage() {
  setCurrentIndex(currentIndex() + 1);
}

Setup::Setup(QWidget *parent) : QStackedWidget(parent) {
  std::stringstream buffer;
  buffer << std::ifstream("/sys/class/hwmon/hwmon1/in1_input").rdbuf();
  float voltage = (float)std::atoi(buffer.str().c_str()) / 1000.;
  if (voltage < 7) {
    addWidget(low_voltage());
  }

  addWidget(getting_started());
  addWidget(network_setup());
  addWidget(software_selection());

  downloading_widget = downloading();
  addWidget(downloading_widget);

  failed_widget = download_failed();
  addWidget(failed_widget);

  QObject::connect(this, &Setup::finished, [=](bool success) {
    // hide setup on success
    qDebug() << "finished" << success;
    if (success) {
      QTimer::singleShot(3000, this, &QWidget::hide);
    } else {
      setCurrentWidget(failed_widget);
    }
  });

  // TODO: revisit pressed bg color
  setStyleSheet(R"(
    * {
      color: white;
      font-family: Inter;
    }
    Setup {
      background-color: black;
    }
    QPushButton#navBtn {
      height: 160;
      font-size: 55px;
      font-weight: 400;
      border-radius: 10px;
      background-color: #333333;
    }
    QPushButton#navBtn:disabled, QPushButton[primary='true']:disabled {
      color: #808080;
      background-color: #333333;
    }
    QPushButton#navBtn:pressed {
      background-color: #444444;
    }
    QPushButton[primary='true'], #navBtn[primary='true'] {
      background-color: #465BEA;
    }
    QPushButton[primary='true']:pressed, #navBtn:pressed[primary='true'] {
      background-color: #3049F4;
    }
  )");
}

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  Setup setup;
  setMainWindow(&setup);
  return a.exec();
}
<|endoftext|>


<commit_before>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "tests.hpp"

#include "widgets/ExampleColorWidget.hpp"
#include "widgets/ExampleImagesWidget.hpp"
#include "widgets/ExampleRectanglesWidget.hpp"
#include "widgets/ExampleShapesWidget.hpp"
#ifdef DGL_OPENGL
#include "widgets/ExampleTextWidget.hpp"
#endif

#include "demo_res/DemoArtwork.cpp"
#include "images_res/CatPics.cpp"

#ifdef DGL_CAIRO
#include "../dgl/Cairo.hpp"
typedef DGL_NAMESPACE::CairoImage DemoImage;
#endif
#ifdef DGL_OPENGL
#include "../dgl/OpenGL.hpp"
typedef DGL_NAMESPACE::OpenGLImage DemoImage;
#endif
#ifdef DGL_VULKAN
#include "../dgl/Vulkan.hpp"
typedef DGL_NAMESPACE::VulkanImage DemoImage;
#endif

START_NAMESPACE_DGL

typedef ExampleImagesWidget<SubWidget, DemoImage> ExampleImagesSubWidget;
typedef ExampleImagesWidget<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget;
typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow;

// --------------------------------------------------------------------------------------------------------------------
// Left side tab-like widget

class LeftSideWidget : public SubWidget
{
public:
#ifdef DGL_OPENGL
    static const int kPageCount = 5;
#else
    static const int kPageCount = 4;
#endif

    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void curPageChanged(int curPage) = 0;
    };

    LeftSideWidget(Widget* parent, Callback* const cb)
        : SubWidget(parent),
          callback(cb),
          curPage(0),
          curHover(-1)
    {

        using namespace DemoArtwork;
        img1.loadFromMemory(ico1Data, ico1Width, ico1Height, kImageFormatBGR);
        img2.loadFromMemory(ico2Data, ico2Width, ico2Height, kImageFormatBGR);
        img3.loadFromMemory(ico3Data, ico3Width, ico2Height, kImageFormatBGR);
        img4.loadFromMemory(ico4Data, ico4Width, ico4Height, kImageFormatBGR);

#ifdef DGL_OPENGL
        img5.loadFromMemory(ico5Data, ico5Width, ico5Height, kImageFormatBGR);

        // for text
        nvg.loadSharedResources();
#endif
    }

protected:
    void onDisplay() override
    {
        const GraphicsContext& context(getGraphicsContext());
        const int iconSize = bgIcon.getWidth();

        Color(0.027f, 0.027f, 0.027f).setFor(context);
        Rectangle<uint>(0, 0, getSize()).draw(context);

        bgIcon.setY(curPage*iconSize + curPage*3);

        Color(0.129f, 0.129f, 0.129f).setFor(context);
        bgIcon.draw(context);

        Color(0.184f, 0.184f, 0.184f).setFor(context);
        bgIcon.drawOutline(context);

        if (curHover != curPage && curHover != -1)
        {
            Rectangle<int> rHover(1, curHover*iconSize + curHover*3, iconSize-2, iconSize-2);

            Color(0.071f, 0.071f, 0.071f).setFor(context);
            rHover.draw(context);

            Color(0.102f, 0.102f, 0.102f).setFor(context);
            rHover.drawOutline(context);
        }

        Color(0.184f, 0.184f, 0.184f).setFor(context);
        lineSep.draw(context);

        // reset color
        Color(1.0f, 1.0f, 1.0f, 1.0f).setFor(context, true);

        const int pad = iconSize/2 - DemoArtwork::ico1Width/2;

        img1.drawAt(context, pad, pad);
        img2.drawAt(context, pad, pad + 3 + iconSize);
        img3.drawAt(context, pad, pad + 6 + iconSize*2);
        img4.drawAt(context, pad, pad + 9 + iconSize*3);

#ifdef DGL_OPENGL
        img5.drawAt(context, pad, pad + 12 + iconSize*4);

        // draw some text
        nvg.beginFrame(this);

        nvg.fontSize(23.0f);
        nvg.textAlign(NanoVG::ALIGN_LEFT|NanoVG::ALIGN_TOP);
        //nvg.textLineHeight(20.0f);

        nvg.fillColor(220,220,220,220);
        nvg.textBox(10, 420, iconSize, "Haha,", nullptr);
        nvg.textBox(15, 440, iconSize, "Look!", nullptr);

        nvg.endFrame();
#endif
    }

    bool onMouse(const MouseEvent& ev) override
    {
        if (ev.button != 1 || ! ev.press)
            return false;
        if (! contains(ev.pos))
            return false;

        const int iconSize = bgIcon.getWidth();

        for (int i=0; i<kPageCount; ++i)
        {
            bgIcon.setY(i*iconSize + i*3);

            if (bgIcon.contains(ev.pos))
            {
                curPage = i;
                callback->curPageChanged(i);
                repaint();
                break;
            }
        }

        return true;
    }

    bool onMotion(const MotionEvent& ev) override
    {
        if (contains(ev.pos))
        {
            const int iconSize = bgIcon.getWidth();

            for (int i=0; i<kPageCount; ++i)
            {
                bgIcon.setY(i*iconSize + i*3);

                if (bgIcon.contains(ev.pos))
                {
                    if (curHover == i)
                        return true;

                    curHover = i;
                    repaint();
                    return true;
                }
            }

            if (curHover == -1)
                return true;

            curHover = -1;
            repaint();
            return true;
        }
        else
        {
            if (curHover == -1)
                return false;

            curHover = -1;
            repaint();
            return true;
        }
    }

    void onResize(const ResizeEvent& ev) override
    {
        const uint width  = ev.size.getWidth();
        const uint height = ev.size.getHeight();

        bgIcon.setWidth(width-4);
        bgIcon.setHeight(width-4);

        lineSep.setStartPos(width, 0);
        lineSep.setEndPos(width, height);
    }

private:
    Callback* const callback;
    int curPage, curHover;
    Rectangle<double> bgIcon;
    Line<int> lineSep;
    DemoImage img1, img2, img3, img4, img5;

#ifdef DGL_OPENGL
    // for text
    NanoVG nvg;
#endif
};

// --------------------------------------------------------------------------------------------------------------------
// Main Demo Window, having a left-side tab-like widget and main area for current widget

class DemoWindow : public StandaloneWindow,
                   public LeftSideWidget::Callback
{
    static const int kSidebarWidth = 81;

public:
#ifdef DGL_CAIRO
    static constexpr const char* const kExampleWidgetName = "Demo - Cairo";
#endif
#ifdef DGL_OPENGL
    static constexpr const char* const kExampleWidgetName = "Demo - OpenGL";
#endif
#ifdef DGL_VULKAN
    static constexpr const char* const kExampleWidgetName = "Demo - Vulkan";
#endif

    DemoWindow(Application& app)
        : StandaloneWindow(app),
          wColor(this),
          wImages(this),
          wRects(this),
          wShapes(this),
#ifdef DGL_OPENGL
          wText(this),
#endif
          wLeft(this, this),
          curWidget(nullptr)
    {
        wColor.hide();
        wImages.hide();
        wRects.hide();
        wShapes.hide();
#ifdef DGL_OPENGL
        wText.hide();
#endif

        wColor.setAbsoluteX(kSidebarWidth);
        wImages.setAbsoluteX(kSidebarWidth);
        wRects.setAbsoluteX(kSidebarWidth);
        wShapes.setAbsoluteX(kSidebarWidth);
#ifdef DGL_OPENGL
        wText.setAbsoluteX(kSidebarWidth);
#endif
        wLeft.setAbsolutePos(2, 2);

        curPageChanged(0);
    }

protected:
    void curPageChanged(int curPage) override
    {
        if (curWidget != nullptr)
            curWidget->hide();

        switch (curPage)
        {
        case 0:
            curWidget = &wColor;
            break;
        case 1:
            curWidget = &wImages;
            break;
        case 2:
            curWidget = &wRects;
            break;
        case 3:
            curWidget = &wShapes;
            break;
#ifdef DGL_OPENGL
        case 4:
            curWidget = &wText;
            break;
#endif
        default:
            curWidget = nullptr;
            break;
        }

        if (curWidget != nullptr)
            curWidget->show();
    }

    void onDisplay() override
    {
    }

    void onReshape(uint width, uint height) override
    {
        StandaloneWindow::onReshape(width, height);

        if (width < kSidebarWidth)
            return;

        Size<uint> size(width-kSidebarWidth, height);
        wColor.setSize(size);
        wImages.setSize(size);
        wRects.setSize(size);
        wShapes.setSize(size);
#ifdef DGL_OPENGL
        wText.setSize(size);
#endif
        wLeft.setSize(kSidebarWidth-4, height-4);
    }

private:
    ExampleColorSubWidget wColor;
    ExampleImagesSubWidget wImages;
    ExampleRectanglesSubWidget wRects;
    ExampleShapesSubWidget wShapes;
#ifdef DGL_OPENGL
    ExampleTextSubWidget wText;
#endif
    LeftSideWidget wLeft;

    Widget* curWidget;
};

// --------------------------------------------------------------------------------------------------------------------
// Special handy function that runs a StandaloneWindow inside the function scope

template <class ExampleWidgetStandaloneWindow>
void createAndShowExampleWidgetStandaloneWindow(Application& app)
{
    ExampleWidgetStandaloneWindow swin(app);
    swin.setResizable(true);
    swin.setSize(600, 500);
    swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName);
    swin.show();
    app.exec();
}

// --------------------------------------------------------------------------------------------------------------------

END_NAMESPACE_DGL

int main(int argc, char* argv[])
{
    USE_NAMESPACE_DGL;
    using DGL_NAMESPACE::Window;

    Application app;

    if (argc > 1)
    {
        /**/ if (std::strcmp(argv[1], "color") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleColorStandaloneWindow>(app);
        else if (std::strcmp(argv[1], "images") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleImagesStandaloneWindow>(app);
        else if (std::strcmp(argv[1], "rectangles") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleRectanglesStandaloneWindow>(app);
        else if (std::strcmp(argv[1], "shapes") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleShapesStandaloneWindow>(app);
#ifdef DGL_OPENGL
        else if (std::strcmp(argv[1], "text") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleTextStandaloneWindow>(app);
#endif
        else
            d_stderr2("Invalid demo mode, must be one of: color, images, rectangles or shapes");
    }
    else
    {
        createAndShowExampleWidgetStandaloneWindow<DemoWindow>(app);
    }

    return 0;
}

// --------------------------------------------------------------------------------------------------------------------
<commit_msg>Add a resize handle to test demo<commit_after>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "tests.hpp"

#include "widgets/ExampleColorWidget.hpp"
#include "widgets/ExampleImagesWidget.hpp"
#include "widgets/ExampleRectanglesWidget.hpp"
#include "widgets/ExampleShapesWidget.hpp"
#ifdef DGL_OPENGL
#include "widgets/ExampleTextWidget.hpp"
#endif

#include "demo_res/DemoArtwork.cpp"
#include "images_res/CatPics.cpp"

#ifdef DGL_CAIRO
#include "../dgl/Cairo.hpp"
typedef DGL_NAMESPACE::CairoImage DemoImage;
#endif
#ifdef DGL_OPENGL
#include "../dgl/OpenGL.hpp"
typedef DGL_NAMESPACE::OpenGLImage DemoImage;
#endif
#ifdef DGL_VULKAN
#include "../dgl/Vulkan.hpp"
typedef DGL_NAMESPACE::VulkanImage DemoImage;
#endif

START_NAMESPACE_DGL

typedef ExampleImagesWidget<SubWidget, DemoImage> ExampleImagesSubWidget;
typedef ExampleImagesWidget<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget;
typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow;

// --------------------------------------------------------------------------------------------------------------------
// Left side tab-like widget

class LeftSideWidget : public SubWidget
{
public:
#ifdef DGL_OPENGL
    static const int kPageCount = 5;
#else
    static const int kPageCount = 4;
#endif

    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void curPageChanged(int curPage) = 0;
    };

    LeftSideWidget(Widget* parent, Callback* const cb)
        : SubWidget(parent),
          callback(cb),
          curPage(0),
          curHover(-1)
    {

        using namespace DemoArtwork;
        img1.loadFromMemory(ico1Data, ico1Width, ico1Height, kImageFormatBGR);
        img2.loadFromMemory(ico2Data, ico2Width, ico2Height, kImageFormatBGR);
        img3.loadFromMemory(ico3Data, ico3Width, ico2Height, kImageFormatBGR);
        img4.loadFromMemory(ico4Data, ico4Width, ico4Height, kImageFormatBGR);

#ifdef DGL_OPENGL
        img5.loadFromMemory(ico5Data, ico5Width, ico5Height, kImageFormatBGR);

        // for text
        nvg.loadSharedResources();
#endif
    }

protected:
    void onDisplay() override
    {
        const GraphicsContext& context(getGraphicsContext());
        const int iconSize = bgIcon.getWidth();

        Color(0.027f, 0.027f, 0.027f).setFor(context);
        Rectangle<uint>(0, 0, getSize()).draw(context);

        bgIcon.setY(curPage*iconSize + curPage*3);

        Color(0.129f, 0.129f, 0.129f).setFor(context);
        bgIcon.draw(context);

        Color(0.184f, 0.184f, 0.184f).setFor(context);
        bgIcon.drawOutline(context);

        if (curHover != curPage && curHover != -1)
        {
            Rectangle<int> rHover(1, curHover*iconSize + curHover*3, iconSize-2, iconSize-2);

            Color(0.071f, 0.071f, 0.071f).setFor(context);
            rHover.draw(context);

            Color(0.102f, 0.102f, 0.102f).setFor(context);
            rHover.drawOutline(context);
        }

        Color(0.184f, 0.184f, 0.184f).setFor(context);
        lineSep.draw(context);

        // reset color
        Color(1.0f, 1.0f, 1.0f, 1.0f).setFor(context, true);

        const int pad = iconSize/2 - DemoArtwork::ico1Width/2;

        img1.drawAt(context, pad, pad);
        img2.drawAt(context, pad, pad + 3 + iconSize);
        img3.drawAt(context, pad, pad + 6 + iconSize*2);
        img4.drawAt(context, pad, pad + 9 + iconSize*3);

#ifdef DGL_OPENGL
        img5.drawAt(context, pad, pad + 12 + iconSize*4);

        // draw some text
        nvg.beginFrame(this);

        nvg.fontSize(23.0f);
        nvg.textAlign(NanoVG::ALIGN_LEFT|NanoVG::ALIGN_TOP);
        //nvg.textLineHeight(20.0f);

        nvg.fillColor(220,220,220,220);
        nvg.textBox(10, 420, iconSize, "Haha,", nullptr);
        nvg.textBox(15, 440, iconSize, "Look!", nullptr);

        nvg.endFrame();
#endif
    }

    bool onMouse(const MouseEvent& ev) override
    {
        if (ev.button != 1 || ! ev.press)
            return false;
        if (! contains(ev.pos))
            return false;

        const int iconSize = bgIcon.getWidth();

        for (int i=0; i<kPageCount; ++i)
        {
            bgIcon.setY(i*iconSize + i*3);

            if (bgIcon.contains(ev.pos))
            {
                curPage = i;
                callback->curPageChanged(i);
                repaint();
                break;
            }
        }

        return true;
    }

    bool onMotion(const MotionEvent& ev) override
    {
        if (contains(ev.pos))
        {
            const int iconSize = bgIcon.getWidth();

            for (int i=0; i<kPageCount; ++i)
            {
                bgIcon.setY(i*iconSize + i*3);

                if (bgIcon.contains(ev.pos))
                {
                    if (curHover == i)
                        return true;

                    curHover = i;
                    repaint();
                    return true;
                }
            }

            if (curHover == -1)
                return true;

            curHover = -1;
            repaint();
            return true;
        }
        else
        {
            if (curHover == -1)
                return false;

            curHover = -1;
            repaint();
            return true;
        }
    }

    void onResize(const ResizeEvent& ev) override
    {
        const uint width  = ev.size.getWidth();
        const uint height = ev.size.getHeight();

        bgIcon.setWidth(width-4);
        bgIcon.setHeight(width-4);

        lineSep.setStartPos(width, 0);
        lineSep.setEndPos(width, height);
    }

private:
    Callback* const callback;
    int curPage, curHover;
    Rectangle<double> bgIcon;
    Line<int> lineSep;
    DemoImage img1, img2, img3, img4, img5;

#ifdef DGL_OPENGL
    // for text
    NanoVG nvg;
#endif
};

// --------------------------------------------------------------------------------------------------------------------
// Resize handle widget

class ResizeHandle : public TopLevelWidget
{
    Rectangle<uint> area;
    Line<double> l1, l2, l3;
    uint baseSize;

    // event handling state
    bool resizing;
    Point<double> lastResizePoint;
    Size<double> resizingSize;

public:
    explicit ResizeHandle(TopLevelWidget* const tlw)
        : TopLevelWidget(tlw->getWindow()),
          baseSize(16),
          resizing(false)
    {
        resetArea();
    }

    explicit ResizeHandle(Window& window)
        : TopLevelWidget(window),
          baseSize(16),
          resizing(false)
    {
        resetArea();
    }

    void setBaseSize(const uint size)
    {
        baseSize = std::max(16u, size);
        resetArea();
    }

protected:
    void onDisplay() override
    {
        const GraphicsContext& context(getGraphicsContext());
        const double offset = getScaleFactor();

        // draw white lines, 1px wide
        Color(1.0f, 1.0f, 1.0f).setFor(context);
        l1.draw(context, 1);
        l2.draw(context, 1);
        l3.draw(context, 1);

        // draw black lines, offset by 1px and 2px wide
        Color(0.0f, 0.0f, 0.0f).setFor(context);
        Line<double> l1b(l1), l2b(l2), l3b(l3);
        l1b.moveBy(offset, offset);
        l2b.moveBy(offset, offset);
        l3b.moveBy(offset, offset);
        l1b.draw(context, 1);
        l2b.draw(context, 1);
        l3b.draw(context, 1);
    }

    bool onMouse(const MouseEvent& ev) override
    {
        if (ev.button != 1)
            return false;

        if (ev.press && area.contains(ev.pos))
        {
            resizing = true;
            resizingSize = Size<double>(getWidth(), getHeight());
            lastResizePoint = ev.pos;
            return true;
        }

        if (resizing && ! ev.press)
        {
            resizing = false;
            return true;
        }

        return false;
    }

    bool onMotion(const MotionEvent& ev) override
    {
        if (! resizing)
            return false;

        const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
                                  ev.pos.getY() - lastResizePoint.getY());

        resizingSize += offset;
        lastResizePoint = ev.pos;

        // TODO min width, min height
        const uint minWidth = 16;
        const uint minHeight = 16;

        if (resizingSize.getWidth() < minWidth)
            resizingSize.setWidth(minWidth);
        if (resizingSize.getHeight() < minHeight)
            resizingSize.setHeight(minHeight);

        setSize(resizingSize.getWidth(), resizingSize.getHeight());
        return true;
    }

    void onResize(const ResizeEvent& ev) override
    {
        TopLevelWidget::onResize(ev);
        resetArea();
    }

private:
    void resetArea()
    {
        const double scaleFactor = getScaleFactor();
        const uint margin = 0.0 * scaleFactor;
        const uint size = baseSize * scaleFactor;

        area = Rectangle<uint>(getWidth() - size - margin,
                               getHeight() - size - margin,
                               size, size);

        recreateLines(area.getX(), area.getY(), size);
    }

    void recreateLines(const uint x, const uint y, const uint size)
    {
        uint linesize = size;
        uint offset = 0;

        // 1st line, full diagonal size
        l1.setStartPos(x + size, y);
        l1.setEndPos(x, y + size);

        // 2nd line, bit more to the right and down, cropped
        offset += size / 3;
        linesize -= size / 3;
        l2.setStartPos(x + linesize + offset, y + offset);
        l2.setEndPos(x + offset, y + linesize + offset);

        // 3rd line, even more right and down
        offset += size / 3;
        linesize -= size / 3;
        l3.setStartPos(x + linesize + offset, y + offset);
        l3.setEndPos(x + offset, y + linesize + offset);
    }
};

// --------------------------------------------------------------------------------------------------------------------
// Main Demo Window, having a left-side tab-like widget and main area for current widget

class DemoWindow : public StandaloneWindow,
                   public LeftSideWidget::Callback
{
    static const int kSidebarWidth = 81;

public:
#ifdef DGL_CAIRO
    static constexpr const char* const kExampleWidgetName = "Demo - Cairo";
#endif
#ifdef DGL_OPENGL
    static constexpr const char* const kExampleWidgetName = "Demo - OpenGL";
#endif
#ifdef DGL_VULKAN
    static constexpr const char* const kExampleWidgetName = "Demo - Vulkan";
#endif

    DemoWindow(Application& app)
        : StandaloneWindow(app),
          wColor(this),
          wImages(this),
          wRects(this),
          wShapes(this),
#ifdef DGL_OPENGL
          wText(this),
#endif
          wLeft(this, this),
          resizer(this),
          curWidget(nullptr)
    {
        wColor.hide();
        wImages.hide();
        wRects.hide();
        wShapes.hide();
#ifdef DGL_OPENGL
        wText.hide();
#endif

        wColor.setAbsoluteX(kSidebarWidth);
        wImages.setAbsoluteX(kSidebarWidth);
        wRects.setAbsoluteX(kSidebarWidth);
        wShapes.setAbsoluteX(kSidebarWidth);
#ifdef DGL_OPENGL
        wText.setAbsoluteX(kSidebarWidth);
#endif
        wLeft.setAbsolutePos(2, 2);

        curPageChanged(0);
    }

protected:
    void curPageChanged(int curPage) override
    {
        if (curWidget != nullptr)
            curWidget->hide();

        switch (curPage)
        {
        case 0:
            curWidget = &wColor;
            break;
        case 1:
            curWidget = &wImages;
            break;
        case 2:
            curWidget = &wRects;
            break;
        case 3:
            curWidget = &wShapes;
            break;
#ifdef DGL_OPENGL
        case 4:
            curWidget = &wText;
            break;
#endif
        default:
            curWidget = nullptr;
            break;
        }

        if (curWidget != nullptr)
            curWidget->show();
    }

    void onDisplay() override
    {
    }

    void onReshape(uint width, uint height) override
    {
        StandaloneWindow::onReshape(width, height);

        if (width < kSidebarWidth)
            return;

        Size<uint> size(width-kSidebarWidth, height);
        wColor.setSize(size);
        wImages.setSize(size);
        wRects.setSize(size);
        wShapes.setSize(size);
#ifdef DGL_OPENGL
        wText.setSize(size);
#endif
        wLeft.setSize(kSidebarWidth-4, height-4);
    }

private:
    ExampleColorSubWidget wColor;
    ExampleImagesSubWidget wImages;
    ExampleRectanglesSubWidget wRects;
    ExampleShapesSubWidget wShapes;
#ifdef DGL_OPENGL
    ExampleTextSubWidget wText;
#endif
    LeftSideWidget wLeft;
    ResizeHandle resizer;

    Widget* curWidget;
};

// --------------------------------------------------------------------------------------------------------------------
// Special handy function that runs a StandaloneWindow inside the function scope

template <class ExampleWidgetStandaloneWindow>
void createAndShowExampleWidgetStandaloneWindow(Application& app)
{
    ExampleWidgetStandaloneWindow swin(app);
    swin.setResizable(true);
    swin.setSize(600, 500);
    swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName);
    swin.show();
    app.exec();
}

// --------------------------------------------------------------------------------------------------------------------

END_NAMESPACE_DGL

int main(int argc, char* argv[])
{
    USE_NAMESPACE_DGL;
    using DGL_NAMESPACE::Window;

    Application app;

    if (argc > 1)
    {
        /**/ if (std::strcmp(argv[1], "color") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleColorStandaloneWindow>(app);
        else if (std::strcmp(argv[1], "images") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleImagesStandaloneWindow>(app);
        else if (std::strcmp(argv[1], "rectangles") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleRectanglesStandaloneWindow>(app);
        else if (std::strcmp(argv[1], "shapes") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleShapesStandaloneWindow>(app);
#ifdef DGL_OPENGL
        else if (std::strcmp(argv[1], "text") == 0)
            createAndShowExampleWidgetStandaloneWindow<ExampleTextStandaloneWindow>(app);
#endif
        else
            d_stderr2("Invalid demo mode, must be one of: color, images, rectangles or shapes");
    }
    else
    {
        createAndShowExampleWidgetStandaloneWindow<DemoWindow>(app);
    }

    return 0;
}

// --------------------------------------------------------------------------------------------------------------------
<|endoftext|>


<commit_before><commit_msg>tentatively kill crawlers explicitly (find a better solution via SG_proc).  Don't cancel the crawl thread; let it exit on its own.<commit_after><|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#include <mapnik/markers_symbolizer.hpp>

namespace mapnik {

static const char * marker_placement_strings[] = {
    "point",
    "line",
    ""
};

IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings )

static const char * marker_type_strings[] = {
    "arrow",
    "ellipse",
    ""
};

IMPLEMENT_ENUM( marker_type_e, marker_type_strings )

markers_symbolizer::markers_symbolizer()
    : symbolizer_with_image(path_expression_ptr(new path_expression)),
      symbolizer_base(),
      allow_overlap_(false),
      fill_(color(0,0,255)),
      spacing_(100.0),
      max_error_(0.2),
      width_(5.0),
      height_(5.0),
      stroke_(),
      marker_p_(),
      marker_type_() {}

markers_symbolizer::markers_symbolizer(path_expression_ptr filename)
    : symbolizer_with_image(filename),
      symbolizer_base(),
      allow_overlap_(false),
      fill_(color(0,0,255)),
      spacing_(100.0),
      max_error_(0.2),
      width_(5.0),
      height_(5.0),
      stroke_(),
      marker_p_(),
      marker_type_() {}

markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
    : symbolizer_with_image(rhs),
      symbolizer_base(rhs),
      allow_overlap_(rhs.allow_overlap_),
      fill_(rhs.fill_),
      spacing_(rhs.spacing_),
      max_error_(rhs.max_error_),
      width_(rhs.width_),
      height_(rhs.height_),
      stroke_(rhs.stroke_),
      marker_p_(rhs.marker_p_),
      marker_type_(rhs.marker_type_) {}

void markers_symbolizer::set_allow_overlap(bool overlap)
{
    allow_overlap_ = overlap;
}

bool markers_symbolizer::get_allow_overlap() const
{
    return allow_overlap_;
}

void markers_symbolizer::set_spacing(double spacing)
{
    spacing_ = spacing;
}

double markers_symbolizer::get_spacing() const
{
    return spacing_;
}

void markers_symbolizer::set_max_error(double max_error)
{
    max_error_ = max_error;
}

double markers_symbolizer::get_max_error() const
{
    return max_error_;
}

void markers_symbolizer::set_fill(color fill)
{
    fill_ = fill;
}

color const& markers_symbolizer::get_fill() const
{
    return fill_;
}

void markers_symbolizer::set_width(double width)
{
    width_ = width;
}

double markers_symbolizer::get_width() const
{
    return width_;
}

void markers_symbolizer::set_height(double height)
{
    height_ = height;
}

double markers_symbolizer::get_height() const
{
    return height_;
}

stroke const& markers_symbolizer::get_stroke() const
{
    return stroke_;
}

void markers_symbolizer::set_stroke(stroke const& stroke)
{
    stroke_ = stroke;
}

void markers_symbolizer::set_marker_placement(marker_placement_e marker_p)
{
    marker_p_ = marker_p;
}

marker_placement_e markers_symbolizer::get_marker_placement() const
{
    return marker_p_;
}

void markers_symbolizer::set_marker_type(marker_type_e marker_type)
{
    marker_type_ = marker_type;
}

marker_type_e markers_symbolizer::get_marker_type() const
{
    return marker_type_;
}

}
<commit_msg>correctly initalize markers_symbolizer default values - avoid segfaul in carto-parser<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#include <mapnik/markers_symbolizer.hpp>

namespace mapnik {

static const char * marker_placement_strings[] = {
    "point",
    "line",
    ""
};

IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings )

static const char * marker_type_strings[] = {
    "arrow",
    "ellipse",
    ""
};

IMPLEMENT_ENUM( marker_type_e, marker_type_strings )

markers_symbolizer::markers_symbolizer()
    : symbolizer_with_image(path_expression_ptr(new path_expression)),
      symbolizer_base(),
      allow_overlap_(false),
      fill_(color(0,0,255)),
      spacing_(100.0),
      max_error_(0.2),
      width_(5.0),
      height_(5.0),
      stroke_(),
      marker_p_(MARKER_LINE_PLACEMENT),
      marker_type_(ARROW) {}

markers_symbolizer::markers_symbolizer(path_expression_ptr filename)
    : symbolizer_with_image(filename),
      symbolizer_base(),
      allow_overlap_(false),
      fill_(color(0,0,255)),
      spacing_(100.0),
      max_error_(0.2),
      width_(5.0),
      height_(5.0),
      stroke_(),
      marker_p_(MARKER_LINE_PLACEMENT),
      marker_type_(ARROW) {}

markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
    : symbolizer_with_image(rhs),
      symbolizer_base(rhs),
      allow_overlap_(rhs.allow_overlap_),
      fill_(rhs.fill_),
      spacing_(rhs.spacing_),
      max_error_(rhs.max_error_),
      width_(rhs.width_),
      height_(rhs.height_),
      stroke_(rhs.stroke_),
      marker_p_(rhs.marker_p_),
      marker_type_(rhs.marker_type_) {}

void markers_symbolizer::set_allow_overlap(bool overlap)
{
    allow_overlap_ = overlap;
}

bool markers_symbolizer::get_allow_overlap() const
{
    return allow_overlap_;
}

void markers_symbolizer::set_spacing(double spacing)
{
    spacing_ = spacing;
}

double markers_symbolizer::get_spacing() const
{
    return spacing_;
}

void markers_symbolizer::set_max_error(double max_error)
{
    max_error_ = max_error;
}

double markers_symbolizer::get_max_error() const
{
    return max_error_;
}

void markers_symbolizer::set_fill(color fill)
{
    fill_ = fill;
}

color const& markers_symbolizer::get_fill() const
{
    return fill_;
}

void markers_symbolizer::set_width(double width)
{
    width_ = width;
}

double markers_symbolizer::get_width() const
{
    return width_;
}

void markers_symbolizer::set_height(double height)
{
    height_ = height;
}

double markers_symbolizer::get_height() const
{
    return height_;
}

stroke const& markers_symbolizer::get_stroke() const
{
    return stroke_;
}

void markers_symbolizer::set_stroke(stroke const& stroke)
{
    stroke_ = stroke;
}

void markers_symbolizer::set_marker_placement(marker_placement_e marker_p)
{
    marker_p_ = marker_p;
}

marker_placement_e markers_symbolizer::get_marker_placement() const
{
    return marker_p_;
}

void markers_symbolizer::set_marker_type(marker_type_e marker_type)
{
    marker_type_ = marker_type;
}

marker_type_e markers_symbolizer::get_marker_type() const
{
    return marker_type_;
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
#include <math.h>
#include <random>

#include <winsock2.h>
#include <ws2tcpip.h>

#include "CPositionSensor.h"
#include "CCrazyflie.h"
#include "CPositionControllerSimple.h"

#include "clockgettime.h"
#include "CLogs.h"

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77

#define DEFAULT_PORT "26517"  // GamesOnTrack TCP connection

typedef std::numeric_limits< double > dbl;

int main(int argc, char **argv) {

	double sensor_XYZ[3] = { 0,0,0 };   /* meters, meters, meters, meters */
	double ctrl_ref_XYZ[4] = { 0,0,0,0 };  /* meters, meters, meters, meters */
	double ctrl_cmd_RPYT[4] = { 0,0,0,0 }; /* degrees, degrees, degress, ? */
	double dt;
	bool MissingGoT = FALSE;

	CLogs *log = new CLogs();

	double scale_ref = 0.1;

	// Initialize the quadrotor
	CCrazyRadio *crRadio = new CCrazyRadio("radio://0/80/250K"); // Address does not matter for now
	if (!crRadio->startRadio())
	{
		std::cerr << "Could not connect to dongle. Did you plug it in?" << std::endl;
		exit(-1);
	}
	CCrazyflie *cflieCopter = new CCrazyflie(crRadio);
    std::cout << "Initializing connection. ";
	cflieCopter->setSendSetpoints(true);
	cflieCopter->setSendExtPosition(true); // if, for example, we want to make position control on the quad, instead of in this program

	// First command
	cflieCopter->setRoll(0);
	cflieCopter->setPitch(0);
	cflieCopter->setYaw(0);
	cflieCopter->setThrust(0);

	// Make sure to check the Crazyflie library for initialization settings
	// such as logging and parameters:
	// CCrazyflie::startLogging()
	// CCrazyflie::sendFlightModeParameters()
	while (!cflieCopter->isInitialized())
	{
		cflieCopter->cycle();
	}

// Quick loop to test external position data communication
//---------------------------------------------------------
	//float fX, fY, fZ;

	//bool exit_loop_x = false;
	//while ((cflieCopter->cycle()) && (!exit_loop_x))
	//{
	//
	//	fX = rand()/1000.0;
	//	fY = rand()/1000.0;
	//	fZ = rand()/1000.0;

	//	cflieCopter->setExtPosition(fX, fY, fZ);
	//	std::cout << fX << " " << fY << " " << fZ << std::endl;

	//	log->CF(cflieCopter);
	//	if (_kbhit())
	//	{
	//		exit_loop_x = true;
	//	}
	//
	//}

	//delete cflieCopter;
	//delete crRadio;
    //delete log;

	//exit(0);
// -----------------------------------------------------------

	// Initialize the GoT connection
	CPositionSensor *GoT = new CPositionSensor("localhost", DEFAULT_PORT, log);
	GoT->init();
	GoT->giveP(ctrl_ref_XYZ);

	// Initialize the position controller
	ctrl_ref_XYZ[2] = ctrl_ref_XYZ[2] - 0.25; // take off to x meters
	CPositionController *posController = new CPositionController(ctrl_ref_XYZ, log);

	double mylogtime = currentTime();
	bool exit_loop = false;
	int ch;
	std::cout.precision(dbl::max_digits10);
	std::cout << " \n Ok. Started! (Pressing any other keys than arrows and q/a and k/l will stop.) \n";

    // The main control loop
 	while ((cflieCopter->cycle()) && (!exit_loop))
		{
			if (GoT->readNewData() && (GoT->giveTimestamp() - GoT->giveTimestampOld() > 0.0001))
			{
				dt = GoT->giveP(sensor_XYZ);

				// Example of how to send external position data to the Crazyflie
				// cflieCopter->setExtPosition(ctrl_ref_XYZ[0]-sensor_XYZ[0], ctrl_ref_XYZ[1]-sensor_XYZ[1], ctrl_ref_XYZ[2] - sensor_XYZ[2]);

				posController->update(sensor_XYZ, dt);
				posController->giveCmd(ctrl_cmd_RPYT);

				cflieCopter->setRoll(ctrl_cmd_RPYT[0]);
				cflieCopter->setPitch(-ctrl_cmd_RPYT[1]);
				cflieCopter->setYaw(ctrl_cmd_RPYT[2]);
				cflieCopter->setThrust(ctrl_cmd_RPYT[3]);

                if (sensor_XYZ[2] < -2.0)
                {
					cflieCopter->setThrust(_PID_THRUST_OFFSET*0.95);
					std::cout << "---- HEIGHT SAFETY: " << sensor_XYZ[2] << " \n";
				}
			}

			if (currentTime() - GoT->giveTimestampOld() > 1)
			{
				cflieCopter->setRoll(0);
				cflieCopter->setPitch(0);
				cflieCopter->setYaw(0);
				cflieCopter->setThrust(_PID_THRUST_OFFSET*0.95);
				std::cout << "-------------Safety----------------" << std::endl;
			}

			// Change the control reference  from the keyboard
			if (_kbhit())
			{
				ch = _getch();
				if (ch == 224)
				{
					ch = _getch();
					switch (ch)
					{
					case KEY_UP:
						ctrl_ref_XYZ[0] = ctrl_ref_XYZ[0] + scale_ref; // x position meters
						break;
					case KEY_DOWN:
						ctrl_ref_XYZ[0] = ctrl_ref_XYZ[0] - scale_ref;
						break;
					case KEY_LEFT:
						ctrl_ref_XYZ[1] = ctrl_ref_XYZ[1] - scale_ref; // y position meters
						break;
					case KEY_RIGHT:
						ctrl_ref_XYZ[1] = ctrl_ref_XYZ[1] + scale_ref;
						break;
					default:
						exit_loop = true;
					}
				}
				else
				{
					switch (ch)
					{
					case 113: // q
						ctrl_ref_XYZ[2] = ctrl_ref_XYZ[2] - scale_ref; // z position meters
						break;
					case 97: // a
						ctrl_ref_XYZ[2] = ctrl_ref_XYZ[2] + scale_ref;
						break;
					case 107: // k
						ctrl_ref_XYZ[3] = ctrl_ref_XYZ[3] - 5; // the yaw angle
						break;
					case 108: // l
						ctrl_ref_XYZ[3] = ctrl_ref_XYZ[3] + 5; // the yaw angle
						break;
					default:
						exit_loop = true;
					}
				}

				posController->setRef(ctrl_ref_XYZ);
			}

			// Logging
			log->CF(cflieCopter);

		}
    // ----------- END MAIN CONTROL LOOP ---------------------

	// Send quadrotor stop
	cflieCopter->setRoll(0);
	cflieCopter->setPitch(0);
	cflieCopter->setYaw(0);
	cflieCopter->setThrust(0);

    // Do a small loop to make sure the kill engine command is sent
	exit_loop = false;
	double time1=currentTime(); // seconds
	while ( (cflieCopter->cycle()) && (!exit_loop) )
	{
		if (currentTime() - time1 > 1.0)
		{
			exit_loop = true;
		}
	}

	mylogtime = currentTime() - mylogtime - 1;
	std::cout << "Run time was:" << mylogtime << " [sec].";

	delete GoT;
	delete posController;
	delete cflieCopter;
	delete crRadio;

	delete log;

	return 0;
}
<commit_msg>Added user question for GoT transmitter ID filtering<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
#include <math.h>
#include <random>

#include <winsock2.h>
#include <ws2tcpip.h>

#include "CPositionSensor.h"
#include "CCrazyflie.h"
#include "CPositionControllerSimple.h"

#include "clockgettime.h"
#include "CLogs.h"

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77

#define DEFAULT_PORT "26517"  // GamesOnTrack TCP connection

typedef std::numeric_limits< double > dbl;

int main(int argc, char **argv) {

	double sensor_XYZ[3] = { 0,0,0 };   /* meters, meters, meters, meters */
	double ctrl_ref_XYZ[4] = { 0,0,0,0 };  /* meters, meters, meters, meters */
	double ctrl_cmd_RPYT[4] = { 0,0,0,0 }; /* degrees, degrees, degress, ? */
	double dt;
	bool MissingGoT = FALSE;

	CLogs *log = new CLogs();

	double scale_ref = 0.1;

	// Initialize the quadrotor
	CCrazyRadio *crRadio = new CCrazyRadio("radio://0/80/250K"); // Address does not matter for now
	if (!crRadio->startRadio())
	{
		std::cerr << "Could not connect to dongle. Did you plug it in?" << std::endl;
		exit(-1);
	}
	CCrazyflie *cflieCopter = new CCrazyflie(crRadio);
    std::cout << "Initializing connection. ";
	cflieCopter->setSendSetpoints(true);
	cflieCopter->setSendExtPosition(true); // if, for example, we want to make position control on the quad, instead of in this program

	// First command
	cflieCopter->setRoll(0);
	cflieCopter->setPitch(0);
	cflieCopter->setYaw(0);
	cflieCopter->setThrust(0);

	// Make sure to check the Crazyflie library for initialization settings
	// such as logging and parameters:
	// CCrazyflie::startLogging()
	// CCrazyflie::sendFlightModeParameters()
	while (!cflieCopter->isInitialized())
	{
		cflieCopter->cycle();
	}

// Quick loop to test external position data communication
//---------------------------------------------------------
	//float fX, fY, fZ;

	//bool exit_loop_x = false;
	//while ((cflieCopter->cycle()) && (!exit_loop_x))
	//{
	//
	//	fX = rand()/1000.0;
	//	fY = rand()/1000.0;
	//	fZ = rand()/1000.0;

	//	cflieCopter->setExtPosition(fX, fY, fZ);
	//	std::cout << fX << " " << fY << " " << fZ << std::endl;

	//	log->CF(cflieCopter);
	//	if (_kbhit())
	//	{
	//		exit_loop_x = true;
	//	}
	//
	//}

	//delete cflieCopter;
	//delete crRadio;
    //delete log;

	//exit(0);
// -----------------------------------------------------------

	// Initialize the GoT connection
	CPositionSensor *GoT = new CPositionSensor("localhost", DEFAULT_PORT, log);

	int tID=0;
	printf_s("\n GoT Transmitter ID (leave 0 to receive all packets): ");
	scanf_s("%d", &tID);
	GoT->init(tID);

	GoT->giveP(ctrl_ref_XYZ);

	// Initialize the position controller
	ctrl_ref_XYZ[2] = ctrl_ref_XYZ[2] - 0.25; // take off to x meters
	CPositionController *posController = new CPositionController(ctrl_ref_XYZ, log);

	double mylogtime = currentTime();
	bool exit_loop = false;
	int ch;
	std::cout.precision(dbl::max_digits10);
	std::cout << " \n Ok. Started! (Pressing any other keys than arrows and q/a and k/l will stop.) \n";

    // The main control loop
 	while ((cflieCopter->cycle()) && (!exit_loop))
		{
			if (GoT->readNewData() && (GoT->giveTimestamp() - GoT->giveTimestampOld() > 0.0001))
			{
				dt = GoT->giveP(sensor_XYZ);

				// Example of how to send external position data to the Crazyflie
				// cflieCopter->setExtPosition(ctrl_ref_XYZ[0]-sensor_XYZ[0], ctrl_ref_XYZ[1]-sensor_XYZ[1], ctrl_ref_XYZ[2] - sensor_XYZ[2]);

				posController->update(sensor_XYZ, dt);
				posController->giveCmd(ctrl_cmd_RPYT);

				cflieCopter->setRoll(ctrl_cmd_RPYT[0]);
				cflieCopter->setPitch(-ctrl_cmd_RPYT[1]);
				cflieCopter->setYaw(ctrl_cmd_RPYT[2]);
				cflieCopter->setThrust(ctrl_cmd_RPYT[3]);

                if (sensor_XYZ[2] < -2.0)
                {
					cflieCopter->setThrust(_PID_THRUST_OFFSET*0.95);
					std::cout << "---- HEIGHT SAFETY: " << sensor_XYZ[2] << " \n";
				}
			}

			if (currentTime() - GoT->giveTimestampOld() > 1)
			{
				cflieCopter->setRoll(0);
				cflieCopter->setPitch(0);
				cflieCopter->setYaw(0);
				cflieCopter->setThrust(_PID_THRUST_OFFSET*0.95);
				std::cout << "-------------Safety----------------" << std::endl;
			}

			// Change the control reference  from the keyboard
			if (_kbhit())
			{
				ch = _getch();
				if (ch == 224)
				{
					ch = _getch();
					switch (ch)
					{
					case KEY_UP:
						ctrl_ref_XYZ[0] = ctrl_ref_XYZ[0] + scale_ref; // x position meters
						break;
					case KEY_DOWN:
						ctrl_ref_XYZ[0] = ctrl_ref_XYZ[0] - scale_ref;
						break;
					case KEY_LEFT:
						ctrl_ref_XYZ[1] = ctrl_ref_XYZ[1] - scale_ref; // y position meters
						break;
					case KEY_RIGHT:
						ctrl_ref_XYZ[1] = ctrl_ref_XYZ[1] + scale_ref;
						break;
					default:
						exit_loop = true;
					}
				}
				else
				{
					switch (ch)
					{
					case 113: // q
						ctrl_ref_XYZ[2] = ctrl_ref_XYZ[2] - scale_ref; // z position meters
						break;
					case 97: // a
						ctrl_ref_XYZ[2] = ctrl_ref_XYZ[2] + scale_ref;
						break;
					case 107: // k
						ctrl_ref_XYZ[3] = ctrl_ref_XYZ[3] - 5; // the yaw angle
						break;
					case 108: // l
						ctrl_ref_XYZ[3] = ctrl_ref_XYZ[3] + 5; // the yaw angle
						break;
					default:
						exit_loop = true;
					}
				}

				posController->setRef(ctrl_ref_XYZ);
			}

			// Logging
			log->CF(cflieCopter);

		}
    // ----------- END MAIN CONTROL LOOP ---------------------

	// Send quadrotor stop
	cflieCopter->setRoll(0);
	cflieCopter->setPitch(0);
	cflieCopter->setYaw(0);
	cflieCopter->setThrust(0);

    // Do a small loop to make sure the kill engine command is sent
	exit_loop = false;
	double time1=currentTime(); // seconds
	while ( (cflieCopter->cycle()) && (!exit_loop) )
	{
		if (currentTime() - time1 > 1.0)
		{
			exit_loop = true;
		}
	}

	mylogtime = currentTime() - mylogtime - 1;
	std::cout << "Run time was:" << mylogtime << " [sec].";

	delete GoT;
	delete posController;
	delete cflieCopter;
	delete crRadio;

	delete log;

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Erik Hallnor
 */

/** @file
 * Definitions of a simple cache block class.
 */

#ifndef __CACHE_BLK_HH__
#define __CACHE_BLK_HH__

#include "sim/root.hh"		// for Tick
#include "arch/isa_traits.hh"	// for Addr

/**
 * Cache block status bit assignments
 */
enum CacheBlkStatusBits {
    /** valid, readable */
    BlkValid =		0x01,
    /** write permission */
    BlkWritable =	0x02,
    /** dirty (modified) */
    BlkDirty =		0x04,
    /** compressed */
    BlkCompressed =	0x08,
    /** block was referenced */
    BlkReferenced =	0x10,
    /** block was a hardware prefetch yet unaccessed*/
    BlkHWPrefetched =	0x20
};

/**
 * A Basic Cache block.
 * Contains the tag, status, and a pointer to data.
 */
class CacheBlk
{
  public:
    /** The address space ID of this block. */
    int asid;
    /** Data block tag value. */
    Addr tag;
    /**
     * Contains a copy of the data in this block for easy access. This is used
     * for efficient execution when the data could be actually stored in
     * another format (COW, compressed, sub-blocked, etc). In all cases the
     * data stored here should be kept consistant with the actual data
     * referenced by this block.
     */
    uint8_t *data;
    /** the number of bytes stored in this block. */
    int size;

    /** block state: OR of CacheBlkStatusBit */
    typedef unsigned State;

    /** The current status of this block. @sa CacheBlockStatusBits */
    State status;

    /** Which curTick will this block be accessable */
    Tick whenReady;

    /**
     * The set this block belongs to.
     * @todo Move this into subclasses when we fix CacheTags to use them.
     */
    int set;

    /** Number of references to this block since it was brought in. */
    int refCount;

    CacheBlk()
        : asid(-1), tag(0), data(0) ,size(0), status(0), whenReady(0),
          set(-1), refCount(0)
    {}

    /**
     * Copy the state of the given block into this one.
     * @param rhs The block to copy.
     * @return a const reference to this block.
     */
    const CacheBlk& operator=(const CacheBlk& rhs)
    {
        asid = rhs.asid;
        tag = rhs.tag;
        data = rhs.data;
        size = rhs.size;
        status = rhs.status;
        whenReady = rhs.whenReady;
        set = rhs.set;
        refCount = rhs.refCount;
        return *this;
    }

    /**
     * Checks the write permissions of this block.
     * @return True if the block is writable.
     */
    bool isWritable() const
    {
        const int needed_bits = BlkWritable | BlkValid;
        return (status & needed_bits) == needed_bits;
    }

    /**
     * Checks that a block is valid (readable).
     * @return True if the block is valid.
     */
    bool isValid() const
    {
        return (status & BlkValid) != 0;
    }

    /**
     * Check to see if a block has been written.
     * @return True if the block is dirty.
     */
    bool isModified() const
    {
        return (status & BlkDirty) != 0;
    }

    /**
     * Check to see if this block contains compressed data.
     * @return True iF the block's data is compressed.
     */
    bool isCompressed() const
    {
        return (status & BlkCompressed) != 0;
    }

    /**
     * Check if this block has been referenced.
     * @return True if the block has been referenced.
     */
    bool isReferenced() const
    {
        return (status & BlkReferenced) != 0;
    }

    /**
     * Check if this block was the result of a hardware prefetch, yet to
     * be touched.
     * @return True if the block was a hardware prefetch, unaccesed.
     */
    bool isPrefetch() const
    {
        return (status & BlkHWPrefetched) != 0;
    }

};

/**
 * Output a CacheBlk to the given ostream.
 * @param out The stream for the output.
 * @param blk The cache block to print.
 *
 * @return The output stream.
 */
inline std::ostream &
operator<<(std::ostream &out, const CacheBlk &blk)
{
    out << std::hex << std::endl;
    out << "  Tag: " << blk.tag << std::endl;
    out << "  Status: " <<  blk.status << std::endl;

    return(out << std::dec);
}

#endif //__CACHE_BLK_HH__
<commit_msg>#include of iostream needed.<commit_after>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Erik Hallnor
 */

/** @file
 * Definitions of a simple cache block class.
 */

#ifndef __CACHE_BLK_HH__
#define __CACHE_BLK_HH__

#include "sim/root.hh"		// for Tick
#include "arch/isa_traits.hh"	// for Addr

#include <iostream>

/**
 * Cache block status bit assignments
 */
enum CacheBlkStatusBits {
    /** valid, readable */
    BlkValid =		0x01,
    /** write permission */
    BlkWritable =	0x02,
    /** dirty (modified) */
    BlkDirty =		0x04,
    /** compressed */
    BlkCompressed =	0x08,
    /** block was referenced */
    BlkReferenced =	0x10,
    /** block was a hardware prefetch yet unaccessed*/
    BlkHWPrefetched =	0x20
};

/**
 * A Basic Cache block.
 * Contains the tag, status, and a pointer to data.
 */
class CacheBlk
{
  public:
    /** The address space ID of this block. */
    int asid;
    /** Data block tag value. */
    Addr tag;
    /**
     * Contains a copy of the data in this block for easy access. This is used
     * for efficient execution when the data could be actually stored in
     * another format (COW, compressed, sub-blocked, etc). In all cases the
     * data stored here should be kept consistant with the actual data
     * referenced by this block.
     */
    uint8_t *data;
    /** the number of bytes stored in this block. */
    int size;

    /** block state: OR of CacheBlkStatusBit */
    typedef unsigned State;

    /** The current status of this block. @sa CacheBlockStatusBits */
    State status;

    /** Which curTick will this block be accessable */
    Tick whenReady;

    /**
     * The set this block belongs to.
     * @todo Move this into subclasses when we fix CacheTags to use them.
     */
    int set;

    /** Number of references to this block since it was brought in. */
    int refCount;

    CacheBlk()
        : asid(-1), tag(0), data(0) ,size(0), status(0), whenReady(0),
          set(-1), refCount(0)
    {}

    /**
     * Copy the state of the given block into this one.
     * @param rhs The block to copy.
     * @return a const reference to this block.
     */
    const CacheBlk& operator=(const CacheBlk& rhs)
    {
        asid = rhs.asid;
        tag = rhs.tag;
        data = rhs.data;
        size = rhs.size;
        status = rhs.status;
        whenReady = rhs.whenReady;
        set = rhs.set;
        refCount = rhs.refCount;
        return *this;
    }

    /**
     * Checks the write permissions of this block.
     * @return True if the block is writable.
     */
    bool isWritable() const
    {
        const int needed_bits = BlkWritable | BlkValid;
        return (status & needed_bits) == needed_bits;
    }

    /**
     * Checks that a block is valid (readable).
     * @return True if the block is valid.
     */
    bool isValid() const
    {
        return (status & BlkValid) != 0;
    }

    /**
     * Check to see if a block has been written.
     * @return True if the block is dirty.
     */
    bool isModified() const
    {
        return (status & BlkDirty) != 0;
    }

    /**
     * Check to see if this block contains compressed data.
     * @return True iF the block's data is compressed.
     */
    bool isCompressed() const
    {
        return (status & BlkCompressed) != 0;
    }

    /**
     * Check if this block has been referenced.
     * @return True if the block has been referenced.
     */
    bool isReferenced() const
    {
        return (status & BlkReferenced) != 0;
    }

    /**
     * Check if this block was the result of a hardware prefetch, yet to
     * be touched.
     * @return True if the block was a hardware prefetch, unaccesed.
     */
    bool isPrefetch() const
    {
        return (status & BlkHWPrefetched) != 0;
    }

};

/**
 * Output a CacheBlk to the given ostream.
 * @param out The stream for the output.
 * @param blk The cache block to print.
 *
 * @return The output stream.
 */
inline std::ostream &
operator<<(std::ostream &out, const CacheBlk &blk)
{
    out << std::hex << std::endl;
    out << "  Tag: " << blk.tag << std::endl;
    out << "  Status: " <<  blk.status << std::endl;

    return(out << std::dec);
}

#endif //__CACHE_BLK_HH__
<|endoftext|>


<commit_before>#include "gameitem.h"

#include <QGraphicsScene>

GameItem::GameItem(QObject *parent) : QObject(parent)
{
}

QPointF GameItem::tryMove(const QPointF &requestedPosition, QLineF *collidedLine,
                          QGraphicsItem **collidedItem) const
{
    QLineF movementPath(pos(), requestedPosition);

    qreal cannonLength = 0.0;
    {
        QPointF p1 = boundingRect().center();
        QPointF p2 = QPointF(boundingRect().right() + 10.0, p1.y());

        cannonLength = QLineF(mapToScene(p1), mapToScene(p2)).length();
    }

    movementPath.setLength(movementPath.length() + cannonLength);

    QRectF boundingRectPath(QPointF(qMin(movementPath.x1(), movementPath.x2()), qMin(movementPath.y1(), movementPath.y2())),
                            QPointF(qMax(movementPath.x1(), movementPath.x2()), qMax(movementPath.y1(), movementPath.y2())));

    QList<QGraphicsItem *> itemsInRect = scene()->items(boundingRectPath, Qt::IntersectsItemBoundingRect);

    QPointF nextPoint = requestedPosition;
    QRectF sceneRect = scene()->sceneRect();

    foreach (QGraphicsItem *item, itemsInRect) {
        if (item == static_cast<const QGraphicsItem *>(this))
            continue;

        QPolygonF mappedBoundingRect = item->mapToScene(item->boundingRect());
        for (int i=0; i<mappedBoundingRect.size(); ++i) {
            QPointF p1 = mappedBoundingRect.at(i == 0 ? mappedBoundingRect.size()-1 : i-1);
            QPointF p2 = mappedBoundingRect.at(i);

            QLineF rectLine(p1, p2);
            QPointF intersectionPoint;
            QLineF::IntersectType intersectType = movementPath.intersect(rectLine, &intersectionPoint);

            if (intersectType == QLineF::BoundedIntersection) {
                movementPath.setP2(intersectionPoint);
                movementPath.setLength(movementPath.length() - cannonLength);
                nextPoint = movementPath.p2();

                if (collidedLine != 0)
                    *collidedLine = rectLine;

                if (collidedItem != 0)
                    *collidedItem = item;
            }
        }
    }

    // Don't go outside of map
    if (nextPoint.x() < sceneRect.left())
        nextPoint.rx() = sceneRect.left();
    if (nextPoint.x() > sceneRect.right())
        nextPoint.rx() = sceneRect.right();
    if (nextPoint.y() < sceneRect.top())
        nextPoint.ry() = sceneRect.top();
    if (nextPoint.y() > sceneRect.bottom())
        nextPoint.ry() = sceneRect.bottom();

    return nextPoint;
}

<commit_msg>Set collidedLine for the implicit walls around the scene to allow for collision response.<commit_after>#include "gameitem.h"

#include <QGraphicsScene>
#include <QDebug>

GameItem::GameItem(QObject *parent) : QObject(parent)
{
}

QPointF GameItem::tryMove(const QPointF &requestedPosition, QLineF *collidedLine,
                          QGraphicsItem **collidedItem) const
{
    QLineF movementPath(pos(), requestedPosition);

    qreal cannonLength = 0.0;
    {
        QPointF p1 = boundingRect().center();
        QPointF p2 = QPointF(boundingRect().right() + 10.0, p1.y());

        cannonLength = QLineF(mapToScene(p1), mapToScene(p2)).length();
    }

    movementPath.setLength(movementPath.length() + cannonLength);

    QRectF boundingRectPath(QPointF(qMin(movementPath.x1(), movementPath.x2()), qMin(movementPath.y1(), movementPath.y2())),
                            QPointF(qMax(movementPath.x1(), movementPath.x2()), qMax(movementPath.y1(), movementPath.y2())));

    QList<QGraphicsItem *> itemsInRect = scene()->items(boundingRectPath, Qt::IntersectsItemBoundingRect);

    QPointF nextPoint = requestedPosition;
    QRectF sceneRect = scene()->sceneRect();

    foreach (QGraphicsItem *item, itemsInRect) {
        if (item == static_cast<const QGraphicsItem *>(this))
            continue;

        QPolygonF mappedBoundingRect = item->mapToScene(item->boundingRect());
        for (int i=0; i<mappedBoundingRect.size(); ++i) {
            QPointF p1 = mappedBoundingRect.at(i == 0 ? mappedBoundingRect.size()-1 : i-1);
            QPointF p2 = mappedBoundingRect.at(i);

            QLineF rectLine(p1, p2);
            QPointF intersectionPoint;
            QLineF::IntersectType intersectType = movementPath.intersect(rectLine, &intersectionPoint);

            if (intersectType == QLineF::BoundedIntersection) {
                movementPath.setP2(intersectionPoint);
                movementPath.setLength(movementPath.length() - cannonLength);
                nextPoint = movementPath.p2();

                if (collidedLine != 0)
                    *collidedLine = rectLine;

                if (collidedItem != 0)
                    *collidedItem = item;
            }
        }
    }

    // Don't go outside of map
    if (nextPoint.x() < sceneRect.left()) {
        nextPoint.rx() = sceneRect.left();
        if (collidedLine != 0)
            *collidedLine = QLineF(scene()->sceneRect().topLeft(), scene()->sceneRect().bottomLeft());
    }

    if (nextPoint.x() > sceneRect.right()) {
        nextPoint.rx() = sceneRect.right();
        if (collidedLine != 0)
            *collidedLine = QLineF(scene()->sceneRect().topRight(), scene()->sceneRect().bottomRight());
    }

    if (nextPoint.y() < sceneRect.top()) {
        nextPoint.ry() = sceneRect.top();
        if (collidedLine != 0)
            *collidedLine = QLineF(scene()->sceneRect().topLeft(), scene()->sceneRect().topRight());
    }

    if (nextPoint.y() > sceneRect.bottom()) {
        nextPoint.ry() = sceneRect.bottom();
        if (collidedLine != 0)
            *collidedLine = QLineF(scene()->sceneRect().bottomLeft(), scene()->sceneRect().bottomRight());
    }

    return nextPoint;
}

<|endoftext|>


<commit_before>/* OpenHoW
 * Copyright (C) 2017-2019 Mark Sowden <markelswo@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <PL/platform_graphics_camera.h>

#include "../engine.h"
#include "../frontend.h"
#include "../audio.h"

#include "SPGameMode.h"
#include "ActorManager.h"

SPGameMode::SPGameMode() {
    players_.resize(4);
}

SPGameMode::~SPGameMode() {
    AudioManager::GetInstance()->FreeSources();
    AudioManager::GetInstance()->FreeSamples();

    DestroyActors();
}

void SPGameMode::StartRound() {
    if(HasRoundStarted()) {
        Error("Attempted to change map in the middle of a round, aborting!\n");
    }

    SpawnActors();

    round_started_ = true;
}

void SPGameMode::RestartRound() {
    DestroyActors();
    SpawnActors();
}

void SPGameMode::EndRound() {
    DestroyActors();
}

void SPGameMode::Tick() {
    if(!HasRoundStarted()) {
        // still setting the game up...
        return;
    }

    Actor* slave = GetCurrentPlayer()->input_target;
    if(slave != nullptr) {
        slave->HandleInput();

        // temp: force the camera at the actor pos
        g_state.camera->position = slave->GetPosition();
        g_state.camera->angles = slave->GetAngles();
    }

    ActorManager::GetInstance()->TickActors();
}

void SPGameMode::SpawnActors() {
    Map* map = GameManager::GetInstance()->GetCurrentMap();
    u_assert(map != nullptr);

    std::vector<MapSpawn> spawns = map->GetSpawns();
    for(auto spawn : spawns) {
        Actor* actor = ActorManager::GetInstance()->SpawnMapActor(spawn.name);
        if(actor == nullptr) {
            continue;
        }

        actor->SetPosition(PLVector3(spawn.position[0], spawn.position[1], spawn.position[2]));
        actor->SetAngles(PLVector3(spawn.angles[0] / 360, spawn.angles[1] / 360, spawn.angles[2] / 360));

        // todo: assign player pigs etc., temp hack
        if(strcmp(spawn.name, "GR_ME") == 0) {
            players_[0].input_target = actor;
        }
    }
}

void SPGameMode::DestroyActors() {
    ActorManager::GetInstance()->DestroyActors();
}

void SPGameMode::StartTurn() {
    Player *player = GetCurrentPlayer();
    if(player->input_target == nullptr) {
        LogWarn("No valid control target for player \"%s\"!\n", player->name.c_str());
        EndTurn();
        return;
    }
}

void SPGameMode::EndTurn() {
    // move onto the next player
    if(++current_player_ >= players_.size()) {
        current_player_ = 0;
    }
}

void SPGameMode::PlayerJoined(Player *player) {

}

void SPGameMode::PlayerLeft(Player *player) {

}

unsigned int SPGameMode::GetMaxSpectators() const {
    return 0;
}

void SPGameMode::SpectatorJoined(Player *player) {

}

void SPGameMode::SpectatorLeft(Player *player) {

}

unsigned int SPGameMode::GetMaxPlayers() const {
    return 0;
}
<commit_msg>fixed minor warnings<commit_after>/* OpenHoW
 * Copyright (C) 2017-2019 Mark Sowden <markelswo@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <PL/platform_graphics_camera.h>

#include "../engine.h"
#include "../frontend.h"
#include "../audio.h"

#include "SPGameMode.h"
#include "ActorManager.h"

SPGameMode::SPGameMode() {
    players_.resize(4);
}

SPGameMode::~SPGameMode() {
    AudioManager::GetInstance()->FreeSources();
    AudioManager::GetInstance()->FreeSamples();

    DestroyActors();
}

void SPGameMode::StartRound() {
    if(HasRoundStarted()) {
        Error("Attempted to change map in the middle of a round, aborting!\n");
    }

    SpawnActors();

    round_started_ = true;
}

void SPGameMode::RestartRound() {
    DestroyActors();
    SpawnActors();
}

void SPGameMode::EndRound() {
    DestroyActors();
}

void SPGameMode::Tick() {
    if(!HasRoundStarted()) {
        // still setting the game up...
        return;
    }

    Actor* slave = GetCurrentPlayer()->input_target;
    if(slave != nullptr) {
        slave->HandleInput();

        // temp: force the camera at the actor pos
        g_state.camera->position = slave->GetPosition();
        g_state.camera->angles = slave->GetAngles();
    }

    ActorManager::GetInstance()->TickActors();
}

void SPGameMode::SpawnActors() {
    Map* map = GameManager::GetInstance()->GetCurrentMap();
    if(map == nullptr) {
        Error("Attempted to spawn actors without having loaded a map!\n");
    }

    std::vector<MapSpawn> spawns = map->GetSpawns();
    for(auto spawn : spawns) {
        Actor* actor = ActorManager::GetInstance()->SpawnMapActor(spawn.name);
        if(actor == nullptr) {
            continue;
        }

        actor->SetPosition(PLVector3(spawn.position[0], spawn.position[1], spawn.position[2]));
        actor->SetAngles(PLVector3(spawn.angles[0] / 360.f, spawn.angles[1] / 360.f, spawn.angles[2] / 360.f));

        // todo: assign player pigs etc., temp hack
        if(strcmp(spawn.name, "GR_ME") == 0) {
            players_[0].input_target = actor;
        }
    }
}

void SPGameMode::DestroyActors() {
    ActorManager::GetInstance()->DestroyActors();
}

void SPGameMode::StartTurn() {
    Player *player = GetCurrentPlayer();
    if(player->input_target == nullptr) {
        LogWarn("No valid control target for player \"%s\"!\n", player->name.c_str());
        EndTurn();
        return;
    }
}

void SPGameMode::EndTurn() {
    // move onto the next player
    if(++current_player_ >= players_.size()) {
        current_player_ = 0;
    }
}

void SPGameMode::PlayerJoined(Player *player) {

}

void SPGameMode::PlayerLeft(Player *player) {

}

unsigned int SPGameMode::GetMaxSpectators() const {
    return 0;
}

void SPGameMode::SpectatorJoined(Player *player) {

}

void SPGameMode::SpectatorLeft(Player *player) {

}

unsigned int SPGameMode::GetMaxPlayers() const {
    return 0;
}
<|endoftext|>