<commit_before>// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <cassert>
#include <sstream>
// Boost
#include <boost/make_shared.hpp>
// StdAir
#include <stdair/basic/BasChronometer.hpp>
#include <stdair/bom/BomManager.hpp>
#include <stdair/bom/BookingRequestStruct.hpp>
#include <stdair/bom/TravelSolutionStruct.hpp>
#include <stdair/service/Logger.hpp>
#include <stdair/STDAIR_Service.hpp>
// AirSched
#include <airsched/basic/BasConst_AIRSCHED_Service.hpp>
#include <airsched/factory/FacAIRSCHEDServiceContext.hpp>
#include <airsched/command/Simulator.hpp>
#include <airsched/command/ScheduleParser.hpp>
#include <airsched/command/OnDParser.hpp>
#include <airsched/command/SegmentPathProvider.hpp>
#include <airsched/command/InventoryGenerator.hpp>
#include <airsched/service/AIRSCHED_ServiceContext.hpp>
#include <airsched/AIRSCHED_Service.hpp>

namespace AIRSCHED {

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service() : _airschedServiceContext (NULL) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const AIRSCHED_Service& iService)
    : _airschedServiceContext (NULL) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const stdair::BasLogParams& iLogParams)
    : _airschedServiceContext (NULL) {

    // Initialise the STDAIR service handler
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      initStdAirService (iLogParams);

    // Initialise the service context
    initServiceContext();

    // Add the StdAir service context to the AirSched service context
    // \note AirSched owns the STDAIR service resources here.
    const bool ownStdairService = true;
    addStdAirService (lSTDAIR_Service_ptr, ownStdairService);

    // Initialise the (remaining of the) context
    initAirschedService();
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const stdair::BasLogParams& iLogParams,
                                      const stdair::BasDBParams& iDBParams)
    : _airschedServiceContext (NULL) {

    // Initialise the STDAIR service handler
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      initStdAirService (iLogParams, iDBParams);

    // Initialise the service context
    initServiceContext();

    // Add the StdAir service context to the AirSched service context
    // \note AirSched owns the STDAIR service resources here.
    const bool ownStdairService = true;
    addStdAirService (lSTDAIR_Service_ptr, ownStdairService);

    // Initialise the (remaining of the) context
    initAirschedService();
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::
  AIRSCHED_Service (stdair::STDAIR_ServicePtr_T ioSTDAIRServicePtr)
    : _airschedServiceContext (NULL) {

    // Initialise the service context
    initServiceContext();

    // Add the StdAir service context to the AirSched service context.
    // \note AirSched does not own the STDAIR service resources here.
    const bool doesNotOwnStdairService = false;
    addStdAirService (ioSTDAIRServicePtr, doesNotOwnStdairService);

    // Initialise the context
    initAirschedService();
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::~AIRSCHED_Service() {
    // Delete/Clean all the objects from memory
    finalise();
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::finalise() {
    assert (_airschedServiceContext != NULL);
    // Reset the (Boost.)Smart pointer pointing on the STDAIR_Service object.
    _airschedServiceContext->reset();
  }

  // //////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::initServiceContext() {
    // Initialise the service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      FacAIRSCHEDServiceContext::instance().create();
    _airschedServiceContext = &lAIRSCHED_ServiceContext;
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  addStdAirService (stdair::STDAIR_ServicePtr_T ioSTDAIR_Service_ptr,
                    const bool iOwnStdairService) {

    // Retrieve the AirSched service context
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;

    // Store the STDAIR service object within the (AirSched) service context
    lAIRSCHED_ServiceContext.setSTDAIR_Service (ioSTDAIR_Service_ptr,
                                                iOwnStdairService);
  }

  // //////////////////////////////////////////////////////////////////////
  stdair::STDAIR_ServicePtr_T AIRSCHED_Service::
  initStdAirService (const stdair::BasLogParams& iLogParams) {

    /**
     * Initialise the STDAIR service handler.
     *
     * \note The (Boost.)Smart Pointer keeps track of the references
     *       on the Service object, and deletes that object when it is
     *       no longer referenced (e.g., at the end of the process).
     */
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      boost::make_shared<stdair::STDAIR_Service> (iLogParams);

    return lSTDAIR_Service_ptr;
  }

  // //////////////////////////////////////////////////////////////////////
  stdair::STDAIR_ServicePtr_T AIRSCHED_Service::
  initStdAirService (const stdair::BasLogParams& iLogParams,
                     const stdair::BasDBParams& iDBParams) {

    /**
     * Initialise the STDAIR service handler.
     *
     * \note The (Boost.)Smart Pointer keeps track of the references
     *       on the Service object, and deletes that object when it is
     *       no longer referenced (e.g., at the end of the process).
     */
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      boost::make_shared<stdair::STDAIR_Service> (iLogParams, iDBParams);

    return lSTDAIR_Service_ptr;
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::initAirschedService() {
    // Do nothing at this stage. A sample BOM tree may be built by
    // calling the buildSampleBom() method
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  parseAndLoad (const stdair::Filename_T& iScheduleInputFilename) {

    // Retrieve the BOM root object.
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Parse the schedule input file, and generate the Inventories
    stdair::BasChronometer lINVGeneration; lINVGeneration.start();
    ScheduleParser::generateInventories (iScheduleInputFilename, lBomRoot);
    const double lGenerationMeasure = lINVGeneration.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Inventory generation time: " << lGenerationMeasure);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  parseAndLoad (const stdair::Filename_T& iScheduleInputFilename,
                const stdair::Filename_T& iODInputFilename) {

    // First, build the airline inventories from the schedule file
    parseAndLoad (iScheduleInputFilename);

    // Retrieve the BOM tree root
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Parse the O&D input file, and generate the O&D periods
    stdair::BasChronometer lOnDGeneration; lOnDGeneration.start();
    OnDParser::generateOnDPeriods (iODInputFilename, lBomRoot);
    const double lGenerationMeasure = lOnDGeneration.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("O&D generation time: " << lGenerationMeasure);
  }

  // //////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::buildSampleBom() {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the STDAIR service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the BOM building to the dedicated service
    lSTDAIR_Service.buildSampleBom();
  }

  // ////////////////////////////////////////////////////////////////////
  std::string AIRSCHED_Service::
  jsonExport (const stdair::AirlineCode_T& iAirlineCode,
              const stdair::FlightNumber_T& iFlightNumber,
              const stdair::Date_T& iDepartureDate) const {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service "
                                                    "has not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the StdAir service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the JSON export to the dedicated service
    return lSTDAIR_Service.jsonExport (iAirlineCode, iFlightNumber,
                                       iDepartureDate);
  }

  // //////////////////////////////////////////////////////////////////////
  std::string AIRSCHED_Service::csvDisplay() const {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the STDAIR service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the BOM building to the dedicated service
    return lSTDAIR_Service.csvDisplay();
  }

  // ////////////////////////////////////////////////////////////////////
  std::string AIRSCHED_Service::
  csvDisplay (const stdair::AirlineCode_T& iAirlineCode,
              const stdair::FlightNumber_T& iFlightNumber,
              const stdair::Date_T& iDepartureDate) const {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the STDAIR service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the BOM display to the dedicated service
    return lSTDAIR_Service.csvDisplay (iAirlineCode, iFlightNumber,
                                       iDepartureDate);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::simulate() {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the BOM tree root
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Call the underlying Use Case (command)
    stdair::BasChronometer lSimulateChronometer; lSimulateChronometer.start();
    Simulator::simulate (lBomRoot);
    const double lSimulateMeasure = lSimulateChronometer.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Simulation: " << lSimulateMeasure << " - "
                      << lAIRSCHED_ServiceContext.display());
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  buildSegmentPathList (stdair::TravelSolutionList_T& ioTravelSolutionList,
			const stdair::BookingRequestStruct& iBookingRequest) {

    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the BOM tree root
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Delegate the call to the dedicated command
    stdair::BasChronometer lBuildChronometer; lBuildChronometer.start();
    SegmentPathProvider::buildSegmentPathList (ioTravelSolutionList,
					       lBomRoot, iBookingRequest);
    const double lBuildMeasure = lBuildChronometer.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Segment-path build: " << lBuildMeasure << " - "
                      << lAIRSCHED_ServiceContext.display());
  }

}
<commit_msg>[AirSched][Dev] Rationalised the buildSampleBom() method calls.<commit_after>// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <cassert>
#include <sstream>
// Boost
#include <boost/make_shared.hpp>
// StdAir
#include <stdair/basic/BasChronometer.hpp>
#include <stdair/bom/BomManager.hpp>
#include <stdair/bom/BookingRequestStruct.hpp>
#include <stdair/bom/TravelSolutionStruct.hpp>
#include <stdair/service/Logger.hpp>
#include <stdair/STDAIR_Service.hpp>
// AirSched
#include <airsched/basic/BasConst_AIRSCHED_Service.hpp>
#include <airsched/factory/FacAIRSCHEDServiceContext.hpp>
#include <airsched/command/Simulator.hpp>
#include <airsched/command/ScheduleParser.hpp>
#include <airsched/command/OnDParser.hpp>
#include <airsched/command/SegmentPathProvider.hpp>
#include <airsched/command/InventoryGenerator.hpp>
#include <airsched/command/SegmentPathGenerator.hpp>
#include <airsched/service/AIRSCHED_ServiceContext.hpp>
#include <airsched/AIRSCHED_Service.hpp>

namespace AIRSCHED {

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service() : _airschedServiceContext (NULL) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const AIRSCHED_Service& iService)
    : _airschedServiceContext (NULL) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const stdair::BasLogParams& iLogParams)
    : _airschedServiceContext (NULL) {

    // Initialise the STDAIR service handler
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      initStdAirService (iLogParams);

    // Initialise the service context
    initServiceContext();

    // Add the StdAir service context to the AirSched service context
    // \note AirSched owns the STDAIR service resources here.
    const bool ownStdairService = true;
    addStdAirService (lSTDAIR_Service_ptr, ownStdairService);

    // Initialise the (remaining of the) context
    initAirschedService();
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const stdair::BasLogParams& iLogParams,
                                      const stdair::BasDBParams& iDBParams)
    : _airschedServiceContext (NULL) {

    // Initialise the STDAIR service handler
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      initStdAirService (iLogParams, iDBParams);

    // Initialise the service context
    initServiceContext();

    // Add the StdAir service context to the AirSched service context
    // \note AirSched owns the STDAIR service resources here.
    const bool ownStdairService = true;
    addStdAirService (lSTDAIR_Service_ptr, ownStdairService);

    // Initialise the (remaining of the) context
    initAirschedService();
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::
  AIRSCHED_Service (stdair::STDAIR_ServicePtr_T ioSTDAIRServicePtr)
    : _airschedServiceContext (NULL) {

    // Initialise the service context
    initServiceContext();

    // Add the StdAir service context to the AirSched service context.
    // \note AirSched does not own the STDAIR service resources here.
    const bool doesNotOwnStdairService = false;
    addStdAirService (ioSTDAIRServicePtr, doesNotOwnStdairService);

    // Initialise the context
    initAirschedService();
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::~AIRSCHED_Service() {
    // Delete/Clean all the objects from memory
    finalise();
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::finalise() {
    assert (_airschedServiceContext != NULL);
    // Reset the (Boost.)Smart pointer pointing on the STDAIR_Service object.
    _airschedServiceContext->reset();
  }

  // //////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::initServiceContext() {
    // Initialise the service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      FacAIRSCHEDServiceContext::instance().create();
    _airschedServiceContext = &lAIRSCHED_ServiceContext;
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  addStdAirService (stdair::STDAIR_ServicePtr_T ioSTDAIR_Service_ptr,
                    const bool iOwnStdairService) {

    // Retrieve the AirSched service context
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;

    // Store the STDAIR service object within the (AirSched) service context
    lAIRSCHED_ServiceContext.setSTDAIR_Service (ioSTDAIR_Service_ptr,
                                                iOwnStdairService);
  }

  // //////////////////////////////////////////////////////////////////////
  stdair::STDAIR_ServicePtr_T AIRSCHED_Service::
  initStdAirService (const stdair::BasLogParams& iLogParams) {

    /**
     * Initialise the STDAIR service handler.
     *
     * \note The (Boost.)Smart Pointer keeps track of the references
     *       on the Service object, and deletes that object when it is
     *       no longer referenced (e.g., at the end of the process).
     */
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      boost::make_shared<stdair::STDAIR_Service> (iLogParams);

    return lSTDAIR_Service_ptr;
  }

  // //////////////////////////////////////////////////////////////////////
  stdair::STDAIR_ServicePtr_T AIRSCHED_Service::
  initStdAirService (const stdair::BasLogParams& iLogParams,
                     const stdair::BasDBParams& iDBParams) {

    /**
     * Initialise the STDAIR service handler.
     *
     * \note The (Boost.)Smart Pointer keeps track of the references
     *       on the Service object, and deletes that object when it is
     *       no longer referenced (e.g., at the end of the process).
     */
    stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
      boost::make_shared<stdair::STDAIR_Service> (iLogParams, iDBParams);

    return lSTDAIR_Service_ptr;
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::initAirschedService() {
    // Do nothing at this stage. A sample BOM tree may be built by
    // calling the buildSampleBom() method
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  parseAndLoad (const stdair::Filename_T& iScheduleInputFilename) {

    // Retrieve the BOM root object.
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Parse the schedule input file, and generate the Inventories
    stdair::BasChronometer lINVGeneration; lINVGeneration.start();
    ScheduleParser::generateInventories (iScheduleInputFilename, lBomRoot);
    const double lGenerationMeasure = lINVGeneration.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Inventory generation time: " << lGenerationMeasure);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  parseAndLoad (const stdair::Filename_T& iScheduleInputFilename,
                const stdair::Filename_T& iODInputFilename) {

    // First, build the airline inventories from the schedule file
    parseAndLoad (iScheduleInputFilename);

    // Retrieve the BOM tree root
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Parse the O&D input file, and generate the O&D periods
    stdair::BasChronometer lOnDGeneration; lOnDGeneration.start();
    OnDParser::generateOnDPeriods (iODInputFilename, lBomRoot);
    const double lGenerationMeasure = lOnDGeneration.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("O&D generation time: " << lGenerationMeasure);
  }

  // //////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::buildSampleBom() {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the AirSched service context and whether it owns the Stdair
    // service
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    const bool doesOwnStdairService =
      lAIRSCHED_ServiceContext.getOwnStdairServiceFlag();

    // Retrieve the StdAir service object from the (AirSched) service context
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    /**
     * 1. Have StdAir build the whole BOM tree, only when the StdAir service is
     *    owned by the current component (AirSched here)
     */
    if (doesOwnStdairService == true) {
      //
      lSTDAIR_Service.buildSampleBom();
    }

    /**
     * 2. Delegate the complementary building of objects and links by the
     *    appropriate levels/components
     *
     * \note: Currently, no more things to do by AirSched at that stage,
     *        as there is no child
     */

    /**
     * 3. Build the complementary objects/links for the current component (here,
     *    AirSched)
     *
     *    AirSched has to build the network from the schedule.
     *    \note: that operation is also invoked by the
     *    ScheduleParser::generateInventories() in parseAndLoad().
     */
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();
    SegmentPathGenerator::createSegmentPathNetwork (lBomRoot);
  }

  // ////////////////////////////////////////////////////////////////////
  std::string AIRSCHED_Service::
  jsonExport (const stdair::AirlineCode_T& iAirlineCode,
              const stdair::FlightNumber_T& iFlightNumber,
              const stdair::Date_T& iDepartureDate) const {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service "
                                                    "has not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the StdAir service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the JSON export to the dedicated service
    return lSTDAIR_Service.jsonExport (iAirlineCode, iFlightNumber,
                                       iDepartureDate);
  }

  // //////////////////////////////////////////////////////////////////////
  std::string AIRSCHED_Service::csvDisplay() const {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the STDAIR service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the BOM building to the dedicated service
    return lSTDAIR_Service.csvDisplay();
  }

  // ////////////////////////////////////////////////////////////////////
  std::string AIRSCHED_Service::
  csvDisplay (const stdair::AirlineCode_T& iAirlineCode,
              const stdair::FlightNumber_T& iFlightNumber,
              const stdair::Date_T& iDepartureDate) const {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the STDAIR service object from the (AirSched) service context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();

    // Delegate the BOM display to the dedicated service
    return lSTDAIR_Service.csvDisplay (iAirlineCode, iFlightNumber,
                                       iDepartureDate);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::simulate() {

    // Retrieve the AirSched service context
    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the BOM tree root
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Call the underlying Use Case (command)
    stdair::BasChronometer lSimulateChronometer; lSimulateChronometer.start();
    Simulator::simulate (lBomRoot);
    const double lSimulateMeasure = lSimulateChronometer.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Simulation: " << lSimulateMeasure << " - "
                      << lAIRSCHED_ServiceContext.display());
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  buildSegmentPathList (stdair::TravelSolutionList_T& ioTravelSolutionList,
			const stdair::BookingRequestStruct& iBookingRequest) {

    if (_airschedServiceContext == NULL) {
      throw stdair::NonInitialisedServiceException ("The AirSched service has "
                                                    "not been initialised");
    }
    assert (_airschedServiceContext != NULL);

    // Retrieve the BOM tree root
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      *_airschedServiceContext;
    stdair::STDAIR_Service& lSTDAIR_Service =
      lAIRSCHED_ServiceContext.getSTDAIR_Service();
    stdair::BomRoot& lBomRoot = lSTDAIR_Service.getBomRoot();

    // Delegate the call to the dedicated command
    stdair::BasChronometer lBuildChronometer; lBuildChronometer.start();
    SegmentPathProvider::buildSegmentPathList (ioTravelSolutionList,
					       lBomRoot, iBookingRequest);
    const double lBuildMeasure = lBuildChronometer.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Segment-path build: " << lBuildMeasure << " - "
                      << lAIRSCHED_ServiceContext.display());
  }

}
<|endoftext|>


<commit_before>#include "TileRenderer.h"
#include "components/Options.h"
#include "components/ThreadWorker.h"
#include "graphics/Shader.h"
#include "graphics/ShaderManager.h"
#include "graphics/ViewState.h"
#include "graphics/utils/GLContext.h"
#include "projections/ProjectionSurface.h"
#include "projections/PlanarProjectionSurface.h"
#include "renderers/MapRenderer.h"
#include "renderers/drawdatas/TileDrawData.h"
#include "utils/Log.h"
#include "utils/Const.h"

#include <vt/Label.h>
#include <vt/TileTransformer.h>
#include <vt/GLTileRenderer.h>
#include <vt/GLExtensions.h>

#include <cglib/mat.h>

namespace {

    struct GLTileRendererDeleter : carto::ThreadWorker {
        GLTileRendererDeleter(std::unique_ptr<carto::vt::GLTileRenderer> renderer) : _renderer(std::move(renderer)) { }

        virtual void operator () () {
            _renderer->deinitializeRenderer();
        }

    private:
        std::unique_ptr<carto::vt::GLTileRenderer> _renderer;
    };

}

namespace carto {

    TileRenderer::TileRenderer(const std::weak_ptr<MapRenderer>& mapRenderer, const std::shared_ptr<vt::TileTransformer>& tileTransformer) :
        _mapRenderer(mapRenderer),
        _tileTransformer(tileTransformer),
        _glRenderer(),
        _firstDraw(false),
        _interactionMode(false),
        _subTileBlending(true),
        _labelOrder(0),
        _buildingOrder(1),
        _horizontalLayerOffset(0),
        _viewDir(0, 0, 0),
        _mainLightDir(0, 0, 0),
        _tiles(),
        _options(),
        _mutex()
    {
    }

    TileRenderer::~TileRenderer() {
    }

    void TileRenderer::setOptions(const std::weak_ptr<Options>& options) {
        std::lock_guard<std::mutex> lock(_mutex);
        _options = options;
    }

    void TileRenderer::setInteractionMode(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _interactionMode = enabled;
    }

    void TileRenderer::setSubTileBlending(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _subTileBlending = enabled;
    }

    void TileRenderer::setLabelOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _labelOrder = order;
    }

    void TileRenderer::setBuildingOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _buildingOrder = order;
    }

    void TileRenderer::offsetLayerHorizontally(double offset) {
        std::lock_guard<std::mutex> lock(_mutex);
        _horizontalLayerOffset += offset;
    }

    void TileRenderer::onSurfaceCreated(const std::shared_ptr<ShaderManager>& shaderManager, const std::shared_ptr<TextureManager>& textureManager) {
        std::lock_guard<std::mutex> lock(_mutex);

        Log::Debug("TileRenderer: Surface created");

        boost::optional<vt::GLTileRenderer::LightingShader> lightingShader2D;
        if (auto mapRenderer = _mapRenderer.lock()) {
            if (!std::dynamic_pointer_cast<PlanarProjectionSurface>(mapRenderer->getProjectionSurface())) {
                lightingShader2D = vt::GLTileRenderer::LightingShader(true, LIGHTING_SHADER_2D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _viewDir.data());
                });
            }
        }
        boost::optional<vt::GLTileRenderer::LightingShader> lightingShader3D = vt::GLTileRenderer::LightingShader(true, LIGHTING_SHADER_3D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
            if (auto options = _options.lock()) {
                const Color& ambientLightColor = options->getAmbientLightColor();
                glUniform4f(glGetUniformLocation(shaderProgram, "u_ambientColor"), ambientLightColor.getR() / 255.0f, ambientLightColor.getG() / 255.0f, ambientLightColor.getB() / 255.0f, ambientLightColor.getA() / 255.0f);
                const Color& mainLightColor = options->getMainLightColor();
                glUniform4f(glGetUniformLocation(shaderProgram, "u_lightColor"), mainLightColor.getR() / 255.0f, mainLightColor.getG() / 255.0f, mainLightColor.getB() / 255.0f, mainLightColor.getA() / 255.0f);
                glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data());
            }
        });

        std::weak_ptr<MapRenderer> mapRendererWeak(_mapRenderer);
        auto glRendererDeleter = [mapRendererWeak](vt::GLTileRenderer* rendererPtr) {
            std::unique_ptr<vt::GLTileRenderer> renderer(rendererPtr);
            Log::Debug("TileRenderer: Releasing renderer resources");
            if (auto mapRenderer = mapRendererWeak.lock()) {
                mapRenderer->addRenderThreadCallback(std::make_shared<GLTileRendererDeleter>(std::move(renderer)));
            }
        };
        _glRenderer = std::shared_ptr<vt::GLTileRenderer>(
            new vt::GLTileRenderer(std::make_shared<vt::GLExtensions>(), _tileTransformer, lightingShader2D, lightingShader3D, Const::WORLD_SIZE), glRendererDeleter
        );
        _glRenderer->initializeRenderer();
        _firstDraw = true;
        _horizontalLayerOffset = 0;
        _tiles.clear();
        GLContext::CheckGLError("TileRenderer::onSurfaceCreated");
    }

    bool TileRenderer::onDrawFrame(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return false;
        }

        cglib::mat4x4<double> modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        _glRenderer->setViewState(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        _glRenderer->setInteractionMode(_interactionMode);
        _glRenderer->setSubTileBlending(_subTileBlending);

        if (_firstDraw) {
            _glRenderer->setVisibleTiles(_tiles, _horizontalLayerOffset == 0);
            _glRenderer->cullLabels(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
            _firstDraw = false;
        }

        _viewDir = cglib::unit(viewState.getFocusPosNormal());
        if (auto options = _options.lock()) {
            _mainLightDir = cglib::vec3<float>::convert(cglib::unit(viewState.getProjectionSurface()->calculateVector(MapPos(0, 0), options->getMainLightDirection())));
        }

        _glRenderer->startFrame(deltaSeconds * 3);

        bool refresh = false;
        refresh = _glRenderer->renderGeometry2D() || refresh;
        if (_labelOrder == 0) {
            refresh = _glRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 0) {
            refresh = _glRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 0) {
            refresh = _glRenderer->renderLabels(false, true) || refresh;
        }

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame");
        return refresh;
    }

    bool TileRenderer::onDrawFrame3D(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return false;
        }

        bool refresh = false;
        if (_labelOrder == 1) {
            refresh = _glRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 1) {
            refresh = _glRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 1) {
            refresh = _glRenderer->renderLabels(false, true) || refresh;
        }

        _glRenderer->endFrame();

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame3D");
        return refresh;
    }

    void TileRenderer::onSurfaceDestroyed() {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        Log::Debug("TileRenderer: Surface destroyed");

        _glRenderer->resetRenderer();
        _glRenderer.reset();
    }

    bool TileRenderer::cullLabels(const ViewState& viewState) {
        std::shared_ptr<vt::GLTileRenderer> glRenderer;
        cglib::mat4x4<double> modelViewMat;
        {
            std::lock_guard<std::mutex> lock(_mutex);

            if (!_firstDraw) {
                glRenderer = _glRenderer;
            }
            modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        }

        if (!glRenderer) {
            return false;
        }
        glRenderer->cullLabels(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        return true;
    }

    bool TileRenderer::refreshTiles(const std::vector<std::shared_ptr<TileDrawData> >& drawDatas) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return false;
        }

        std::map<vt::TileId, std::shared_ptr<const vt::Tile> > tiles;
        for (const std::shared_ptr<TileDrawData>& drawData : drawDatas) {
            tiles[drawData->getVTTileId()] = drawData->getVTTile();
        }

        bool changed = tiles != _tiles;
        if (changed) {
            if (!_firstDraw) {
                _glRenderer->setVisibleTiles(tiles, _horizontalLayerOffset == 0);
            }
            _tiles = tiles;
        }
        _horizontalLayerOffset = 0;
        return changed;
    }

    void TileRenderer::calculateRayIntersectedElements(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        float radius = CLICK_RADIUS; // NOTE: the value will be automatically multiplied with DPI factor

        _glRenderer->findGeometryIntersections(ray, results, radius, true, false);
        if (_labelOrder == 0) {
            _glRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 0) {
            _glRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 0) {
            _glRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    void TileRenderer::calculateRayIntersectedBitmaps(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, vt::TileBitmap, cglib::vec2<float> > >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        _glRenderer->findBitmapIntersections(ray, results);
    }

    void TileRenderer::calculateRayIntersectedElements3D(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        float radius = viewState.getUnitToDPCoef() * CLICK_RADIUS;

        if (_labelOrder == 1) {
            _glRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 1) {
            _glRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 1) {
            _glRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    const std::string TileRenderer::LIGHTING_SHADER_2D = R"GLSL(
        uniform vec3 u_lightDir;
        vec4 applyLighting(vec4 color, vec3 normal) {
            float lighting = max(0.0, dot(normal, u_lightDir)) * 0.5 + 0.5;
            return vec4(color.rgb * lighting, color.a);
        }
    )GLSL";

    const std::string TileRenderer::LIGHTING_SHADER_3D = R"GLSL(
        uniform vec4 u_ambientColor;
        uniform vec4 u_lightColor;
        uniform vec3 u_lightDir;
        vec4 applyLighting(vec4 color, vec3 normal) {
            vec3 lighting = max(0.0, dot(normal, u_lightDir)) * u_lightColor.rgb + u_ambientColor.rgb;
            return vec4(color.rgb * lighting, color.a);
        }
    )GLSL";

}
<commit_msg>Better handling of horizontal offsetting in TileRenderer<commit_after>#include "TileRenderer.h"
#include "components/Options.h"
#include "components/ThreadWorker.h"
#include "graphics/Shader.h"
#include "graphics/ShaderManager.h"
#include "graphics/ViewState.h"
#include "graphics/utils/GLContext.h"
#include "projections/ProjectionSurface.h"
#include "projections/PlanarProjectionSurface.h"
#include "renderers/MapRenderer.h"
#include "renderers/drawdatas/TileDrawData.h"
#include "utils/Log.h"
#include "utils/Const.h"

#include <vt/Label.h>
#include <vt/TileTransformer.h>
#include <vt/GLTileRenderer.h>
#include <vt/GLExtensions.h>

#include <cglib/mat.h>

namespace {

    struct GLTileRendererDeleter : carto::ThreadWorker {
        GLTileRendererDeleter(std::unique_ptr<carto::vt::GLTileRenderer> renderer) : _renderer(std::move(renderer)) { }

        virtual void operator () () {
            _renderer->deinitializeRenderer();
        }

    private:
        std::unique_ptr<carto::vt::GLTileRenderer> _renderer;
    };

}

namespace carto {

    TileRenderer::TileRenderer(const std::weak_ptr<MapRenderer>& mapRenderer, const std::shared_ptr<vt::TileTransformer>& tileTransformer) :
        _mapRenderer(mapRenderer),
        _tileTransformer(tileTransformer),
        _glRenderer(),
        _firstDraw(false),
        _interactionMode(false),
        _subTileBlending(true),
        _labelOrder(0),
        _buildingOrder(1),
        _horizontalLayerOffset(0),
        _viewDir(0, 0, 0),
        _mainLightDir(0, 0, 0),
        _tiles(),
        _options(),
        _mutex()
    {
    }

    TileRenderer::~TileRenderer() {
    }

    void TileRenderer::setOptions(const std::weak_ptr<Options>& options) {
        std::lock_guard<std::mutex> lock(_mutex);
        _options = options;
    }

    void TileRenderer::setInteractionMode(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _interactionMode = enabled;
    }

    void TileRenderer::setSubTileBlending(bool enabled) {
        std::lock_guard<std::mutex> lock(_mutex);
        _subTileBlending = enabled;
    }

    void TileRenderer::setLabelOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _labelOrder = order;
    }

    void TileRenderer::setBuildingOrder(int order) {
        std::lock_guard<std::mutex> lock(_mutex);
        _buildingOrder = order;
    }

    void TileRenderer::offsetLayerHorizontally(double offset) {
        std::lock_guard<std::mutex> lock(_mutex);
        _horizontalLayerOffset += offset;
    }

    void TileRenderer::onSurfaceCreated(const std::shared_ptr<ShaderManager>& shaderManager, const std::shared_ptr<TextureManager>& textureManager) {
        std::lock_guard<std::mutex> lock(_mutex);

        Log::Debug("TileRenderer: Surface created");

        boost::optional<vt::GLTileRenderer::LightingShader> lightingShader2D;
        if (auto mapRenderer = _mapRenderer.lock()) {
            if (!std::dynamic_pointer_cast<PlanarProjectionSurface>(mapRenderer->getProjectionSurface())) {
                lightingShader2D = vt::GLTileRenderer::LightingShader(true, LIGHTING_SHADER_2D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
                    glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _viewDir.data());
                });
            }
        }
        boost::optional<vt::GLTileRenderer::LightingShader> lightingShader3D = vt::GLTileRenderer::LightingShader(true, LIGHTING_SHADER_3D, [this](GLuint shaderProgram, const vt::ViewState& viewState) {
            if (auto options = _options.lock()) {
                const Color& ambientLightColor = options->getAmbientLightColor();
                glUniform4f(glGetUniformLocation(shaderProgram, "u_ambientColor"), ambientLightColor.getR() / 255.0f, ambientLightColor.getG() / 255.0f, ambientLightColor.getB() / 255.0f, ambientLightColor.getA() / 255.0f);
                const Color& mainLightColor = options->getMainLightColor();
                glUniform4f(glGetUniformLocation(shaderProgram, "u_lightColor"), mainLightColor.getR() / 255.0f, mainLightColor.getG() / 255.0f, mainLightColor.getB() / 255.0f, mainLightColor.getA() / 255.0f);
                glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data());
            }
        });

        std::weak_ptr<MapRenderer> mapRendererWeak(_mapRenderer);
        auto glRendererDeleter = [mapRendererWeak](vt::GLTileRenderer* rendererPtr) {
            std::unique_ptr<vt::GLTileRenderer> renderer(rendererPtr);
            Log::Debug("TileRenderer: Releasing renderer resources");
            if (auto mapRenderer = mapRendererWeak.lock()) {
                mapRenderer->addRenderThreadCallback(std::make_shared<GLTileRendererDeleter>(std::move(renderer)));
            }
        };
        _glRenderer = std::shared_ptr<vt::GLTileRenderer>(
            new vt::GLTileRenderer(std::make_shared<vt::GLExtensions>(), _tileTransformer, lightingShader2D, lightingShader3D, Const::WORLD_SIZE), glRendererDeleter
        );
        _glRenderer->initializeRenderer();
        _firstDraw = true;
        _horizontalLayerOffset = 0;
        _tiles.clear();
        GLContext::CheckGLError("TileRenderer::onSurfaceCreated");
    }

    bool TileRenderer::onDrawFrame(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return false;
        }

        cglib::mat4x4<double> modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        _glRenderer->setViewState(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        _glRenderer->setInteractionMode(_interactionMode);
        _glRenderer->setSubTileBlending(_subTileBlending);

        if (_firstDraw) {
            _glRenderer->setVisibleTiles(_tiles, _horizontalLayerOffset == 0);
            _glRenderer->cullLabels(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
            _firstDraw = false;
        }

        _viewDir = cglib::unit(viewState.getFocusPosNormal());
        if (auto options = _options.lock()) {
            _mainLightDir = cglib::vec3<float>::convert(cglib::unit(viewState.getProjectionSurface()->calculateVector(MapPos(0, 0), options->getMainLightDirection())));
        }

        _glRenderer->startFrame(deltaSeconds * 3);

        bool refresh = false;
        refresh = _glRenderer->renderGeometry2D() || refresh;
        if (_labelOrder == 0) {
            refresh = _glRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 0) {
            refresh = _glRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 0) {
            refresh = _glRenderer->renderLabels(false, true) || refresh;
        }

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame");
        return refresh;
    }

    bool TileRenderer::onDrawFrame3D(float deltaSeconds, const ViewState& viewState) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return false;
        }

        bool refresh = false;
        if (_labelOrder == 1) {
            refresh = _glRenderer->renderLabels(true, false) || refresh;
        }
        if (_buildingOrder == 1) {
            refresh = _glRenderer->renderGeometry3D() || refresh;
        }
        if (_labelOrder == 1) {
            refresh = _glRenderer->renderLabels(false, true) || refresh;
        }

        _glRenderer->endFrame();

        // Reset GL state to the expected state
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_FALSE);

        GLContext::CheckGLError("TileRenderer::onDrawFrame3D");
        return refresh;
    }

    void TileRenderer::onSurfaceDestroyed() {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        Log::Debug("TileRenderer: Surface destroyed");

        _glRenderer->resetRenderer();
        _glRenderer.reset();
    }

    bool TileRenderer::cullLabels(const ViewState& viewState) {
        std::shared_ptr<vt::GLTileRenderer> glRenderer;
        cglib::mat4x4<double> modelViewMat;
        {
            std::lock_guard<std::mutex> lock(_mutex);

            if (!_firstDraw) {
                glRenderer = _glRenderer;
            }
            modelViewMat = viewState.getModelviewMat() * cglib::translate4_matrix(cglib::vec3<double>(_horizontalLayerOffset, 0, 0));
        }

        if (!glRenderer) {
            return false;
        }
        glRenderer->cullLabels(vt::ViewState(viewState.getProjectionMat(), modelViewMat, viewState.getZoom(), viewState.getAspectRatio(), viewState.getNormalizedResolution()));
        return true;
    }

    bool TileRenderer::refreshTiles(const std::vector<std::shared_ptr<TileDrawData> >& drawDatas) {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return false;
        }

        std::map<vt::TileId, std::shared_ptr<const vt::Tile> > tiles;
        for (const std::shared_ptr<TileDrawData>& drawData : drawDatas) {
            tiles[drawData->getVTTileId()] = drawData->getVTTile();
        }

        bool changed = (tiles != _tiles) || (_horizontalLayerOffset != 0);
        if (changed) {
            if (!_firstDraw) {
                _glRenderer->setVisibleTiles(tiles, _horizontalLayerOffset == 0);
            }
            _tiles = std::move(tiles);
            _horizontalLayerOffset = 0;
        }
        return changed;
    }

    void TileRenderer::calculateRayIntersectedElements(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        float radius = CLICK_RADIUS; // NOTE: the value will be automatically multiplied with DPI factor

        _glRenderer->findGeometryIntersections(ray, results, radius, true, false);
        if (_labelOrder == 0) {
            _glRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 0) {
            _glRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 0) {
            _glRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    void TileRenderer::calculateRayIntersectedBitmaps(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, vt::TileBitmap, cglib::vec2<float> > >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        _glRenderer->findBitmapIntersections(ray, results);
    }

    void TileRenderer::calculateRayIntersectedElements3D(const cglib::ray3<double>& ray, const ViewState& viewState, std::vector<std::tuple<vt::TileId, double, long long> >& results) const {
        std::lock_guard<std::mutex> lock(_mutex);

        if (!_glRenderer) {
            return;
        }

        float radius = viewState.getUnitToDPCoef() * CLICK_RADIUS;

        if (_labelOrder == 1) {
            _glRenderer->findLabelIntersections(ray, results, radius, true, false);
        }
        if (_buildingOrder == 1) {
            _glRenderer->findGeometryIntersections(ray, results, radius, false, true);
        }
        if (_labelOrder == 1) {
            _glRenderer->findLabelIntersections(ray, results, radius, false, true);
        }
    }

    const std::string TileRenderer::LIGHTING_SHADER_2D = R"GLSL(
        uniform vec3 u_lightDir;
        vec4 applyLighting(vec4 color, vec3 normal) {
            float lighting = max(0.0, dot(normal, u_lightDir)) * 0.5 + 0.5;
            return vec4(color.rgb * lighting, color.a);
        }
    )GLSL";

    const std::string TileRenderer::LIGHTING_SHADER_3D = R"GLSL(
        uniform vec4 u_ambientColor;
        uniform vec4 u_lightColor;
        uniform vec3 u_lightDir;
        vec4 applyLighting(vec4 color, vec3 normal) {
            vec3 lighting = max(0.0, dot(normal, u_lightDir)) * u_lightColor.rgb + u_ambientColor.rgb;
            return vec4(color.rgb * lighting, color.a);
        }
    )GLSL";

}
<|endoftext|>


<commit_before>#include <rang.hpp>
#include <algorithm>
#include <iostream>
#include <utility>
#include <sstream>
#include <vector>
#include <map>

#include "Tools/general_utils.h"
#include "Tools/Exception/exception.hpp"

#include "Factory.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Factory_name       = "Factory";
const std::string aff3ct::factory::Factory_short_name = "Factory";
const std::string aff3ct::factory::Factory_prefix     = "fac";

Factory::parameters
::parameters(const std::string &name, const std::string &short_name, const std::string &prefix)
: name(name), short_name(short_name), prefix(prefix)
{
}

Factory::parameters
::~parameters()
{
}

std::string Factory::parameters
::get_name() const
{
	return this->name;
}
std::string Factory::parameters
::get_short_name() const
{
	return this->short_name;
}

std::string Factory::parameters
::get_prefix() const
{
	return this->prefix;
}

std::vector<std::string> Factory::parameters
::get_names() const
{
	std::vector<std::string> n;
	n.push_back(this->name);
	return n;
}
std::vector<std::string> Factory::parameters
::get_short_names() const
{
	std::vector<std::string> sn;
	sn.push_back(this->short_name);
	return sn;
}

std::vector<std::string> Factory::parameters
::get_prefixes() const
{
	std::vector<std::string> p;
	p.push_back(this->prefix);
	return p;
}

tools::Argument_map_info Factory
::get_description(const std::vector<Factory::parameters*> &params)
{
	tools::Argument_map_info args;

	get_description(params, args);

	return args;
}

void Factory
::get_description(const std::vector<Factory::parameters*> &params,
                     tools::Argument_map_info &args)
{
	for (auto *p : params)
		p->get_description(args);
}

void Factory
::store(std::vector<Factory::parameters*> &params, const tools::Argument_map_value &vals)
{
	for (auto *p : params)
		p->store(vals);
}

tools::Argument_map_group Factory
::create_groups(const std::vector<Factory::parameters*> &params)
{
	// create groups of arguments
	tools::Argument_map_group grps;
	for (auto *p : params)
	{
		auto prefixes    = p->get_prefixes   ();
		auto short_names = p->get_short_names();

		if (prefixes.size() != short_names.size())
		{
			std::stringstream message;
			message << "'prefixes.size()' has to be equal to 'short_names.size()' ('prefixes.size()' = "
			        << prefixes.size() << ", 'short_names.size()' = " << short_names.size() << ").";
			throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
		}

		for (size_t i = 0; i < prefixes.size(); i++)
			grps[prefixes[i]] = short_names[i] + " parameter(s)";
	}

	return grps;
}

void aff3ct::factory::Header::print_parameters(std::string grp_key, std::string grp_name, header_list header,
                                               int max_n_chars, std::ostream& stream)
{
	auto key = tools::split(grp_key, '-');

	if (key.size() == 1)
	{
		stream << "# * " << rang::style::bold << rang::style::underline << grp_name << rang::style::reset << " ";
		for (auto i = 0; i < 46 - (int)grp_name.length(); i++) std::cout << "-";
		stream << std::endl;
	}
	else if (key.size() > 1)
	{
		stream << "#    " << rang::style::bold << rang::style::underline << grp_name << rang::style::reset << " ";
		for (auto i = 0; i < 45 - (int)grp_name.length(); i++) std::cout << "-";
		stream << std::endl;
	}

	std::vector<std::string> dup;
	for (auto i = 0; i < (int)header.size(); i++)
	{
		if (std::find(dup.begin(), dup.end(), header[i].first + header[i].second) == dup.end())
		{
			stream << "#    ** " << rang::style::bold << header[i].first << rang::style::reset;
			for (auto j = 0; j < max_n_chars - (int)header[i].first.length(); j++) stream << " ";
			stream << " = " << header[i].second << std::endl;

			dup.push_back(header[i].first + header[i].second);
		}
	}
}

void aff3ct::factory::Header::print_parameters(const std::vector<Factory::parameters*> &params, const bool full,
                                               std::ostream& stream)
{
	int max_n_chars = 0;
	for (auto *p : params)
	{
		std::map<std::string,aff3ct::factory::header_list> headers;
		p->get_headers(headers, full);

		for (auto &h : headers)
			if (full || (!full && h.second.size() && (h.second[0].first != "Type" || h.second[0].second != "NO")))
				aff3ct::factory::Header::compute_max_n_chars(h.second, max_n_chars);
	}

	std::vector<aff3ct::factory::header_list> dup_h;
	std::vector<std::string                 > dup_n;
	for (auto *p : params)
	{
		std::map<std::string,aff3ct::factory::header_list> headers;
		p->get_headers(headers, full);

		auto prefixes = p->get_prefixes();
		auto short_names = p->get_short_names();

		if (prefixes.size() != short_names.size())
		{
			std::stringstream message;
			message << "'prefixes.size()' has to be equal to 'short_names.size()' ('prefixes.size()' = "
			        << prefixes.size() << ", 'short_names.size()' = " << short_names.size() << ").";
			throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
		}

		bool print_first_title = false;
		for (size_t i = 1; i < prefixes.size(); i++)
		{
			auto h = headers[prefixes[i]];
			auto key = tools::split(prefixes[i], '-');

			if (key[0] == prefixes[0] && h.size())
			{
				print_first_title = true;
				break;
			}
		}

		for (size_t i = 0; i < prefixes.size(); i++)
		{
			auto h = headers[prefixes[i]];
			auto print_head = (i == 0) ? print_first_title || h.size() : h.size();

			if (full || (!full && h.size() && (h[0].first != "Type" || h[0].second != "NO")))
			{
				auto n = short_names[i];
				if (print_head && (std::find(dup_h.begin(), dup_h.end(), h) == dup_h.end() ||
				                   std::find(dup_n.begin(), dup_n.end(), n) == dup_n.end()))
				{
					aff3ct::factory::Header::print_parameters(prefixes[i], n, h, max_n_chars);

					dup_h.push_back(h);
					dup_n.push_back(n);
				}
			}
		}
	}
}

void aff3ct::factory::Header::compute_max_n_chars(const header_list& header, int& max_n_chars)
{
	for (unsigned i = 0; i < header.size(); i++)
		max_n_chars = std::max(max_n_chars, (int)header[i].first.length());
}
<commit_msg>Try to fix MSVC compilation error.<commit_after>#include <rang.hpp>
#include <algorithm>
#include <iostream>
#include <utility>
#include <sstream>
#include <vector>
#include <map>

#include "Tools/general_utils.h"
#include "Tools/Exception/exception.hpp"

#include "Factory.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Factory_name       = "Factory";
const std::string aff3ct::factory::Factory_short_name = "Factory";
const std::string aff3ct::factory::Factory_prefix     = "fac";

Factory::parameters
::parameters(const std::string &name, const std::string &short_name, const std::string &prefix)
: name(name), short_name(short_name), prefix(prefix)
{
}

Factory::parameters
::~parameters()
{
}

std::string Factory::parameters
::get_name() const
{
	return this->name;
}
std::string Factory::parameters
::get_short_name() const
{
	return this->short_name;
}

std::string Factory::parameters
::get_prefix() const
{
	return this->prefix;
}

std::vector<std::string> Factory::parameters
::get_names() const
{
	std::vector<std::string> n;
	n.push_back(this->name);
	return n;
}
std::vector<std::string> Factory::parameters
::get_short_names() const
{
	std::vector<std::string> sn;
	sn.push_back(this->short_name);
	return sn;
}

std::vector<std::string> Factory::parameters
::get_prefixes() const
{
	std::vector<std::string> p;
	p.push_back(this->prefix);
	return p;
}

tools::Argument_map_info Factory
::get_description(const std::vector<Factory::parameters*> &params)
{
	tools::Argument_map_info args;

	get_description(params, args);

	return args;
}

void Factory
::get_description(const std::vector<Factory::parameters*> &params,
                     tools::Argument_map_info &args)
{
	for (auto *p : params)
		p->get_description(args);
}

void Factory
::store(std::vector<Factory::parameters*> &params, const tools::Argument_map_value &vals)
{
	for (auto *p : params)
		p->store(vals);
}

tools::Argument_map_group Factory
::create_groups(const std::vector<Factory::parameters*> &params)
{
	// create groups of arguments
	tools::Argument_map_group grps;
	for (auto *p : params)
	{
		auto prefixes    = p->get_prefixes   ();
		auto short_names = p->get_short_names();

		if (prefixes.size() != short_names.size())
		{
			std::stringstream message;
			message << "'prefixes.size()' has to be equal to 'short_names.size()' ('prefixes.size()' = "
			        << prefixes.size() << ", 'short_names.size()' = " << short_names.size() << ").";
			throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
		}

		for (size_t i = 0; i < prefixes.size(); i++)
			grps[prefixes[i]] = short_names[i] + " parameter(s)";
	}

	return grps;
}

void aff3ct::factory::Header::print_parameters(std::string grp_key, std::string grp_name, header_list header,
                                               int max_n_chars, std::ostream& stream)
{
	auto key = tools::split(grp_key, '-');

	if (key.size() == 1)
	{
		stream << "# * " << rang::style::bold << rang::style::underline << grp_name << rang::style::reset << " ";
		for (auto i = 0; i < 46 - (int)grp_name.length(); i++) std::cout << "-";
		stream << std::endl;
	}
	else if (key.size() > 1)
	{
		stream << "#    " << rang::style::bold << rang::style::underline << grp_name << rang::style::reset << " ";
		for (auto i = 0; i < 45 - (int)grp_name.length(); i++) std::cout << "-";
		stream << std::endl;
	}

	std::vector<std::string> dup;
	for (auto i = 0; i < (int)header.size(); i++)
	{
		if (std::find(dup.begin(), dup.end(), header[i].first + header[i].second) == dup.end())
		{
			stream << "#    ** " << rang::style::bold << header[i].first << rang::style::reset;
			for (auto j = 0; j < max_n_chars - (int)header[i].first.length(); j++) stream << " ";
			stream << " = " << header[i].second << std::endl;

			dup.push_back(header[i].first + header[i].second);
		}
	}
}

void aff3ct::factory::Header::print_parameters(const std::vector<Factory::parameters*> &params, const bool full,
                                               std::ostream& stream)
{
	int max_n_chars = 0;
	for (auto *p : params)
	{
		std::map<std::string,aff3ct::factory::header_list> headers;
		p->get_headers(headers, full);

		for (auto &h : headers)
			if (full || (!full && h.second.size() && (h.second[0].first != "Type" || h.second[0].second != "NO")))
				aff3ct::factory::Header::compute_max_n_chars(h.second, max_n_chars);
	}

	std::vector<aff3ct::factory::header_list> dup_h;
	std::vector<std::string                 > dup_n;
	for (auto *p : params)
	{
		std::map<std::string,aff3ct::factory::header_list> headers;
		p->get_headers(headers, full);

		auto prefixes = p->get_prefixes();
		auto short_names = p->get_short_names();

		if (prefixes.size() != short_names.size())
		{
			std::stringstream message;
			message << "'prefixes.size()' has to be equal to 'short_names.size()' ('prefixes.size()' = "
			        << prefixes.size() << ", 'short_names.size()' = " << short_names.size() << ").";
			throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
		}

		bool print_first_title = false;
		for (size_t i = 1; i < prefixes.size(); i++)
		{
			auto h = headers[prefixes[i]];
			auto key = tools::split(prefixes[i], '-');

			if (key[0] == prefixes[0] && h.size())
			{
				print_first_title = true;
				break;
			}
		}

		for (size_t i = 0; i < prefixes.size(); i++)
		{
			auto h = headers[prefixes[i]];
			auto print_head = (i == 0) ? print_first_title || h.size() : h.size();

			if (full || (!full && h.size() && (h[0].first != "Type" || h[0].second != "NO")))
			{
				auto n = short_names[i];
				if (print_head && (std::find(dup_h.begin(), dup_h.end(), h) == dup_h.end() ||
				                   std::find(dup_n.begin(), dup_n.end(), n) == dup_n.end()))
				{
					aff3ct::factory::Header::print_parameters(prefixes[i], n, h, max_n_chars);

					dup_h.push_back(h);
					dup_n.push_back(n);
				}
			}
		}
	}
}

#undef max
void aff3ct::factory::Header::compute_max_n_chars(const header_list& header, int& max_n_chars)
{
	for (unsigned i = 0; i < header.size(); i++)
		max_n_chars = std::max(max_n_chars, (int)header[i].first.length());
}
<|endoftext|>


<commit_before>#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){
	// Load a CSV File.
	csv.loadFile(ofToDataPath("file.csv"));

	// Check how many rows exist.
	cout << "csv rows: " << csv.numRows << endl;

	// Print out all rows and cols.
	for(int i=0; i<csv.numRows; i++) {
		for(int j=0; j<csv.data[i].size(); j++) {
			cout << csv.data[i][j] << endl;
		}
	}

	// Print out the first value
	cout << csv.data[0].front() << endl;

	// Print out a specific CSV value.
	cout << csv.data[0][1] << endl;
	// or
	cout << csv.data[0].at(1) << endl;

	// misc...
	cout << csv.data[0].max_size() << endl;

	// read a CSV row as simple String.
	vector<string> dataExample = csv.getFromString("0x11120119,100,40,445,23,543,46,24,56,14,964, 12", ",");
	cout << "dataExample[0]" << dataExample[0] << endl;
	// print the hole csv data string to console.
	for(int i=0; i<dataExample.size(); i++) {
		cout << "\tdataExample[" << i << "]: " << dataExample[i] << endl;
	}

	// Get a specific value as int, float, string etc.
	cout << "getInt: " << csv.getInt(0, 0) << endl;
	cout << "getFloat: " << csv.getFloat(0, 1) << endl;
	cout << "getString: " << csv.getString(0, 2) << endl;
	cout << "getBool: " << csv.getBool(0, 3) << endl;
}

//--------------------------------------------------------------
void testApp::update(){

}

//--------------------------------------------------------------
void testApp::draw(){

}

//--------------------------------------------------------------
void testApp::keyPressed(int key){

}

//--------------------------------------------------------------
void testApp::keyReleased(int key){

}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void testApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void testApp::dragEvent(ofDragInfo dragInfo){

}<commit_msg>add numCols example.<commit_after>#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){
	// Load a CSV File.
	csv.loadFile(ofToDataPath("file.csv"));

	// Check how many rows exist.
	cout << "csv rows: " << csv.numRows << endl;
	// Check how many columnss exist.
	cout << "csv cols: " << csv.numCols << endl;

	// Print out all rows and cols.
	for(int i=0; i<csv.numRows; i++) {
		for(int j=0; j<csv.data[i].size(); j++) {
			cout << csv.data[i][j] << endl;
		}
	}

	// Print out the first value
	cout << csv.data[0].front() << endl;

	// Print out a specific CSV value.
	cout << csv.data[0][1] << endl;
	// or
	cout << csv.data[0].at(1) << endl;

	// misc...
	cout << csv.data[0].max_size() << endl;

	// read a CSV row as simple String.
	vector<string> dataExample = csv.getFromString("0x11120119,100,40,445,23,543,46,24,56,14,964, 12", ",");
	cout << "dataExample[0]" << dataExample[0] << endl;
	// print the hole csv data string to console.
	for(int i=0; i<dataExample.size(); i++) {
		cout << "\tdataExample[" << i << "]: " << dataExample[i] << endl;
	}

	// Get a specific value as int, float, string etc.
	cout << "getInt: " << csv.getInt(0, 0) << endl;
	cout << "getFloat: " << csv.getFloat(0, 1) << endl;
	cout << "getString: " << csv.getString(0, 2) << endl;
	cout << "getBool: " << csv.getBool(0, 3) << endl;
}

//--------------------------------------------------------------
void testApp::update(){

}

//--------------------------------------------------------------
void testApp::draw(){

}

//--------------------------------------------------------------
void testApp::keyPressed(int key){

}

//--------------------------------------------------------------
void testApp::keyReleased(int key){

}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void testApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void testApp::dragEvent(ofDragInfo dragInfo){

}<|endoftext|>


<commit_before>// Copyright 2022 Michael Fisher <mfisher@lvtk.org>
// SPDX-License-Identifier: ISC

#include <algorithm>

#include "lvtk/ui/input.hpp"
#include "lvtk/ui/main.hpp"
#include "lvtk/ui/view.hpp"
#include "lvtk/ui/widget.hpp"

#define PUGL_DISABLE_DEPRECATED
#include <pugl/pugl.h>

// flip these for verbose logging
// #define VIEW_DBG(x) std::clog << x << std::endl;
#define VIEW_DBG(x)

namespace lvtk {
namespace detail {
template <typename Tp, class Ev>
static inline Point<Tp> point (const Ev& ev) {
    return {
        static_cast<Tp> (ev.x),
        static_cast<Tp> (ev.y)
    };
}

template <typename Tp, class Ev>
static inline Rectangle<Tp> rect (const Ev& ev) {
    return {
        static_cast<Tp> (ev.x),
        static_cast<Tp> (ev.y),
        static_cast<Tp> (ev.width),
        static_cast<Tp> (ev.height)
    };
}

template <typename Rect>
static inline PuglRect frame (const Rect& r) {
    return {
        static_cast<PuglCoord> (r.x),
        static_cast<PuglCoord> (r.y),
        static_cast<PuglSpan> (r.width),
        static_cast<PuglSpan> (r.height)
    };
}

inline static void erase (std::vector<View*>& views, View* view) {
    auto it = std::find (views.begin(), views.end(), view);
    if (it != views.end())
        views.erase (it);
}

} // namespace detail

struct View::EventHandler {
    static PuglStatus configure (View& view, const PuglConfigureEvent& ev) {
        if (ev.flags & PUGL_IS_HINT) {
            VIEW_DBG ("configure: hint");
            return PUGL_SUCCESS;
        }

        auto& w = view._widget;
        w.set_bounds (w.x(), w.y(), ev.width / view.scale_factor(), ev.height / view.scale_factor());
        VIEW_DBG ("pugl: configure: " << w.bounds().str());
        return PUGL_SUCCESS;
    }

    static PuglStatus expose (View& view, const PuglExposeEvent& ev) {
        if (ev.flags & PUGL_IS_HINT) {
            VIEW_DBG ("expose: hint");
            return PUGL_SUCCESS;
        }

        auto x = (float) ev.x / (float) view.scale_factor();
        auto y = (float) ev.y / (float) view.scale_factor();
        auto w = (float) ev.width / (float) view.scale_factor();
        auto h = (float) ev.height / (float) view.scale_factor();
        view.expose (Rectangle<float> { x, y, w, h }.as<int>());
        return PUGL_SUCCESS;
    }

    static PuglStatus create (View& view, const PuglCreateEvent& ev) {
        view.created();
        return PUGL_SUCCESS;
    }

    static PuglStatus destroy (View& view, const PuglDestroyEvent& ev) {
        view.destroyed();
        return PUGL_SUCCESS;
    }

    static PuglStatus map (View& view, const PuglMapEvent& ev) {
        return PUGL_SUCCESS;
    }

    static PuglStatus unmap (View& view, const PuglUnmapEvent& ev) {
        return PUGL_SUCCESS;
    }

    static PuglStatus update (View& view, const PuglUpdateEvent& ev) {
        return PUGL_SUCCESS;
    }

    static PuglStatus close (View& view, const PuglCloseEvent& ev) {
        // dirty setup so the demo can at least quit...
        if (view._main.mode() == Mode::PROGRAM)
            view._main.quit();
        return PUGL_SUCCESS;
    }

    static PuglStatus focus_in (View& view, const PuglFocusEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus focus_out (View& view, const PuglFocusEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus key_press (View& view, const PuglKeyEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus key_release (View& view, const PuglKeyEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus text (View& view, const PuglTextEvent& ev) { return PUGL_SUCCESS; }

    static PuglStatus pointer_in (View& view, const PuglCrossingEvent& ev) {
        VIEW_DBG ("pointer in")
        return PUGL_SUCCESS;
    }

    static PuglStatus pointer_out (View& view, const PuglCrossingEvent& ev) {
        VIEW_DBG ("pointer out")
        return PUGL_SUCCESS;
    }

    static PuglStatus motion (View& view, const PuglMotionEvent& ev) {
        auto pos      = detail::point<float> (ev) / view.scale_factor();
        WidgetRef ref = view._widget.widget_at (pos);

        InputEvent event;

        if (ref.valid()) {
            event.pos = ref->convert (&view._widget, pos);
            if (view._hovered != ref) {
                VIEW_DBG ("hovered changed: " << ref->__name);
                ref->pointer_in (event);
                view._hovered = ref;
            }

            ref->motion (event);
        } else if (view._hovered) {
            VIEW_DBG ("hovered cleared");

            if (auto h = view._hovered.lock()) {
                event.pos = h->convert (&view._widget, pos);
                h->pointer_out (event);
            }
            view._hovered = nullptr;
        }

        return PUGL_SUCCESS;
    }

    static PuglStatus button_press (View& view, const PuglButtonEvent& ev) {
        InputEvent event;
        event.pos = detail::point<float> (ev) / view.scale_factor();

        if (auto w = view._hovered.lock()) {
            event.pos = w->convert (&view._widget, event.pos);
            // VIEW_DBG("widget:" << w->__name << " bounds: " << w->bounds().str());
            // VIEW_DBG("ev pos: " << event.pos.str());
            if (w->contains (event.pos))
                w->pressed (event);
        }

        return PUGL_SUCCESS;
    }

    static PuglStatus button_release (View& view, const PuglButtonEvent& ev) {
        InputEvent event;
        event.pos    = detail::point<float> (ev) / view.scale_factor();
        auto hovered = view._hovered;

        if (auto w = hovered.lock()) {
            event.pos = hovered->convert (&view._widget, event.pos);
            if (w->contains (event.pos))
                w->released (event);
        }

        return PUGL_SUCCESS;
    }

    static PuglStatus scroll (View& view, const PuglScrollEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus client (View& view, const PuglClientEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus timer (View& view, const PuglTimerEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus loop_enter (View& view, const PuglLoopEnterEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus loop_leave (View& view, const PuglLoopLeaveEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus data_offer (View& view, const PuglDataOfferEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus data (View& view, const PuglDataEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus nothing (View&, const PuglAnyEvent&) { return PUGL_SUCCESS; }

    static inline PuglStatus dispatch (PuglView* v, const PuglEvent* ev) {
        auto view         = static_cast<View*> (puglGetHandle (v));
        PuglStatus status = PUGL_SUCCESS;

#define CASE3(t, fn, arg)         \
    case t:                       \
        status = fn (*view, arg); \
        break;
#define CASE2(t, fn) CASE3 (t, fn, ev->fn)
#define CASEA(t, fn) CASE3 (t, fn, ev->any)
        switch (ev->type) {
            CASE2 (PUGL_CONFIGURE, configure)                       //< View moved/resized, a #PuglConfigureEvent
            CASEA (PUGL_UPDATE, update)                             //< View ready to draw, a #PuglUpdateEvent
            CASE2 (PUGL_EXPOSE, expose)                             //< View must be drawn, a #PuglExposeEvent
            CASEA (PUGL_CREATE, create)                             //< View created, a #PuglCreateEvent
            CASEA (PUGL_DESTROY, destroy)                           ///< View destroyed, a #PuglDestroyEvent
            CASEA (PUGL_MAP, map)                                   ///< View made visible, a #PuglMapEvent
            CASEA (PUGL_UNMAP, unmap)                               ///< View made invisible, a #PuglUnmapEvent
            CASEA (PUGL_CLOSE, close)                               ///< View will be closed, a #PuglCloseEvent
            CASE3 (PUGL_FOCUS_IN, focus_in, ev->focus)              ///< Keyboard focus entered view, a #PuglFocusEvent
            CASE3 (PUGL_FOCUS_OUT, focus_out, ev->focus)            ///< Keyboard focus left view, a #PuglFocusEvent
            CASE3 (PUGL_KEY_PRESS, key_press, ev->key)              ///< Key pressed, a #PuglKeyEvent
            CASE3 (PUGL_KEY_RELEASE, key_release, ev->key)          ///< Key released, a #PuglKeyEvent
            CASE2 (PUGL_TEXT, text)                                 ///< Character entered, a #PuglTextEvent
            CASE3 (PUGL_POINTER_IN, pointer_in, ev->crossing)       ///< Pointer entered view, a #PuglCrossingEvent
            CASE3 (PUGL_POINTER_OUT, pointer_out, ev->crossing)     ///< Pointer left view, a #PuglCrossingEvent
            CASE3 (PUGL_BUTTON_PRESS, button_press, ev->button)     ///< Mouse button pressed, a #PuglButtonEvent
            CASE3 (PUGL_BUTTON_RELEASE, button_release, ev->button) ///< Mouse button released, a #PuglButtonEvent
            CASE2 (PUGL_MOTION, motion)                             ///< Pointer moved, a #PuglMotionEvent
            CASE2 (PUGL_SCROLL, scroll)                             ///< Scrolled, a #PuglScrollEvent
            CASE2 (PUGL_CLIENT, client)                             ///< Custom client message, a #PuglClientEvent
            CASE2 (PUGL_TIMER, timer)                               ///< Timer triggered, a #PuglTimerEvent
            CASEA (PUGL_LOOP_ENTER, loop_enter)                     ///< Recursive loop entered, a #PuglLoopEnterEvent
            CASEA (PUGL_LOOP_LEAVE, loop_leave)                     ///< Recursive loop left, a #PuglLoopLeaveEvent
            CASE3 (PUGL_DATA_OFFER, data_offer, ev->offer)          ///< Data offered from clipboard, a #PuglDataOfferEvent
            CASE2 (PUGL_DATA, data)                                 ///< Data available from clipboard, a #PuglDataEvent
            CASE3 (PUGL_NOTHING, nothing, ev->any)                  ///< No event
            default:
                break;
        }
#undef CASE2
#undef CASE3
#undef CASEA
        return status;
    }
};

View::View (Main& m, Widget& w)
    : _main (m),
      _widget (w) {
    _view  = (uintptr_t) puglNewView ((PuglWorld*) m.world());
    auto v = (PuglView*) _view;
    puglSetHandle (v, this);
    puglSetEventFunc (v, EventHandler::dispatch);
    _weak_status.reset (this);
    _main._views.push_back (this);
}

View::~View() {
    detail::erase (_main._views, this);
    _weak_status.reset();
    puglFreeView ((PuglView*) _view);
    _view = (uintptr_t) nullptr;
}

void View::set_backend (uintptr_t b) {
    puglSetBackend ((PuglView*) _view, (PuglBackend*) b);
}

void View::set_view_hint (int hint, int value) {
    puglSetViewHint ((PuglView*) _view, static_cast<PuglViewHint> (hint), value);
}

uintptr_t View::handle() { return puglGetNativeView ((PuglView*) _view); }
float View::scale_factor() const noexcept { return static_cast<float> (puglGetScaleFactor ((PuglView*) _view)); }

void View::set_visible (bool visible) {
    if (visible)
        puglShow ((PuglView*) _view);
    else
        puglHide ((PuglView*) _view);
}

bool View::visible() const { return puglGetVisible ((PuglView*) _view); }

void View::set_size (int width, int height) {
    puglSetSize ((PuglView*) _view, width * scale_factor(), height * scale_factor());
}

Rectangle<int> View::bounds() const {
    auto f = puglGetFrame ((PuglView*) _view);
    return {
        static_cast<int> ((float) f.x / scale_factor()),
        static_cast<int> ((float) f.y / scale_factor()),
        static_cast<int> ((float) f.width / scale_factor()),
        static_cast<int> ((float) f.height / scale_factor())
    };
}

void View::set_bounds (Bounds b) {
    b *= scale_factor();
    puglSetFrame ((PuglView*) _view, detail::frame (b));
}

void View::realize() {
    puglRealize ((PuglView*) _view);
}

Style& View::style() noexcept { return _main.style(); }
const Style& View::style() const noexcept { return _main.style(); }

void View::elevate (Widget& widget, ViewFlags flags) {
    _main.elevate (widget, flags, *this);
}

//==
void View::render (Surface& ctx) {
    Graphics g (ctx);
    _widget.render (g);
}

void View::set_parent (uintptr_t parent, bool transient) {
    if (! parent)
        return;
    if (transient)
        puglSetTransientParent ((PuglView*) _view, parent);
    else
        puglSetParentWindow ((PuglView*) _view, parent);
}

void View::__pugl_post_redisplay() {
    puglPostRedisplay ((PuglView*) _view);
}

} // namespace lvtk
<commit_msg>remove un-needed casting<commit_after>// Copyright 2022 Michael Fisher <mfisher@lvtk.org>
// SPDX-License-Identifier: ISC

#include <algorithm>

#include "lvtk/ui/input.hpp"
#include "lvtk/ui/main.hpp"
#include "lvtk/ui/view.hpp"
#include "lvtk/ui/widget.hpp"

#define PUGL_DISABLE_DEPRECATED
#include <pugl/pugl.h>

// flip these for verbose logging
// #define VIEW_DBG(x) std::clog << x << std::endl;
#define VIEW_DBG(x)

namespace lvtk {
namespace detail {
template <typename Tp, class Ev>
static inline Point<Tp> point (const Ev& ev) {
    return {
        static_cast<Tp> (ev.x),
        static_cast<Tp> (ev.y)
    };
}

template <typename Tp, class Ev>
static inline Rectangle<Tp> rect (const Ev& ev) {
    return {
        static_cast<Tp> (ev.x),
        static_cast<Tp> (ev.y),
        static_cast<Tp> (ev.width),
        static_cast<Tp> (ev.height)
    };
}

template <typename Rect>
static inline PuglRect frame (const Rect& r) {
    return {
        static_cast<PuglCoord> (r.x),
        static_cast<PuglCoord> (r.y),
        static_cast<PuglSpan> (r.width),
        static_cast<PuglSpan> (r.height)
    };
}

inline static void erase (std::vector<View*>& views, View* view) {
    auto it = std::find (views.begin(), views.end(), view);
    if (it != views.end())
        views.erase (it);
}

} // namespace detail

struct View::EventHandler {
    static PuglStatus configure (View& view, const PuglConfigureEvent& ev) {
        if (ev.flags & PUGL_IS_HINT) {
            VIEW_DBG ("configure: hint");
            return PUGL_SUCCESS;
        }

        auto& w = view._widget;
        w.set_bounds (w.x(), w.y(), ev.width / view.scale_factor(), ev.height / view.scale_factor());
        VIEW_DBG ("pugl: configure: " << w.bounds().str());
        return PUGL_SUCCESS;
    }

    static PuglStatus expose (View& view, const PuglExposeEvent& ev) {
        if (ev.flags & PUGL_IS_HINT) {
            VIEW_DBG ("expose: hint");
            return PUGL_SUCCESS;
        }

        auto x = (float) ev.x / view.scale_factor();
        auto y = (float) ev.y / view.scale_factor();
        auto w = (float) ev.width / view.scale_factor();
        auto h = (float) ev.height / view.scale_factor();
        view.expose (Rectangle<float> { x, y, w, h }.as<int>());
        return PUGL_SUCCESS;
    }

    static PuglStatus create (View& view, const PuglCreateEvent& ev) {
        view.created();
        return PUGL_SUCCESS;
    }

    static PuglStatus destroy (View& view, const PuglDestroyEvent& ev) {
        view.destroyed();
        return PUGL_SUCCESS;
    }

    static PuglStatus map (View& view, const PuglMapEvent& ev) {
        return PUGL_SUCCESS;
    }

    static PuglStatus unmap (View& view, const PuglUnmapEvent& ev) {
        return PUGL_SUCCESS;
    }

    static PuglStatus update (View& view, const PuglUpdateEvent& ev) {
        return PUGL_SUCCESS;
    }

    static PuglStatus close (View& view, const PuglCloseEvent& ev) {
        // dirty setup so the demo can at least quit...
        if (view._main.mode() == Mode::PROGRAM)
            view._main.quit();
        return PUGL_SUCCESS;
    }

    static PuglStatus focus_in (View& view, const PuglFocusEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus focus_out (View& view, const PuglFocusEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus key_press (View& view, const PuglKeyEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus key_release (View& view, const PuglKeyEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus text (View& view, const PuglTextEvent& ev) { return PUGL_SUCCESS; }

    static PuglStatus pointer_in (View& view, const PuglCrossingEvent& ev) {
        VIEW_DBG ("pointer in")
        return PUGL_SUCCESS;
    }

    static PuglStatus pointer_out (View& view, const PuglCrossingEvent& ev) {
        VIEW_DBG ("pointer out")
        return PUGL_SUCCESS;
    }

    static PuglStatus motion (View& view, const PuglMotionEvent& ev) {
        auto pos      = detail::point<float> (ev) / view.scale_factor();
        WidgetRef ref = view._widget.widget_at (pos);

        InputEvent event;

        if (ref.valid()) {
            event.pos = ref->convert (&view._widget, pos);
            if (view._hovered != ref) {
                VIEW_DBG ("hovered changed: " << ref->__name);
                ref->pointer_in (event);
                view._hovered = ref;
            }

            ref->motion (event);
        } else if (view._hovered) {
            VIEW_DBG ("hovered cleared");

            if (auto h = view._hovered.lock()) {
                event.pos = h->convert (&view._widget, pos);
                h->pointer_out (event);
            }
            view._hovered = nullptr;
        }

        return PUGL_SUCCESS;
    }

    static PuglStatus button_press (View& view, const PuglButtonEvent& ev) {
        InputEvent event;
        event.pos = detail::point<float> (ev) / view.scale_factor();

        if (auto w = view._hovered.lock()) {
            event.pos = w->convert (&view._widget, event.pos);
            // VIEW_DBG("widget:" << w->__name << " bounds: " << w->bounds().str());
            // VIEW_DBG("ev pos: " << event.pos.str());
            if (w->contains (event.pos))
                w->pressed (event);
        }

        return PUGL_SUCCESS;
    }

    static PuglStatus button_release (View& view, const PuglButtonEvent& ev) {
        InputEvent event;
        event.pos    = detail::point<float> (ev) / view.scale_factor();
        auto hovered = view._hovered;

        if (auto w = hovered.lock()) {
            event.pos = hovered->convert (&view._widget, event.pos);
            if (w->contains (event.pos))
                w->released (event);
        }

        return PUGL_SUCCESS;
    }

    static PuglStatus scroll (View& view, const PuglScrollEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus client (View& view, const PuglClientEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus timer (View& view, const PuglTimerEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus loop_enter (View& view, const PuglLoopEnterEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus loop_leave (View& view, const PuglLoopLeaveEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus data_offer (View& view, const PuglDataOfferEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus data (View& view, const PuglDataEvent& ev) { return PUGL_SUCCESS; }
    static PuglStatus nothing (View&, const PuglAnyEvent&) { return PUGL_SUCCESS; }

    static inline PuglStatus dispatch (PuglView* v, const PuglEvent* ev) {
        auto view         = static_cast<View*> (puglGetHandle (v));
        PuglStatus status = PUGL_SUCCESS;

#define CASE3(t, fn, arg)         \
    case t:                       \
        status = fn (*view, arg); \
        break;
#define CASE2(t, fn) CASE3 (t, fn, ev->fn)
#define CASEA(t, fn) CASE3 (t, fn, ev->any)
        switch (ev->type) {
            CASE2 (PUGL_CONFIGURE, configure)                       //< View moved/resized, a #PuglConfigureEvent
            CASEA (PUGL_UPDATE, update)                             //< View ready to draw, a #PuglUpdateEvent
            CASE2 (PUGL_EXPOSE, expose)                             //< View must be drawn, a #PuglExposeEvent
            CASEA (PUGL_CREATE, create)                             //< View created, a #PuglCreateEvent
            CASEA (PUGL_DESTROY, destroy)                           ///< View destroyed, a #PuglDestroyEvent
            CASEA (PUGL_MAP, map)                                   ///< View made visible, a #PuglMapEvent
            CASEA (PUGL_UNMAP, unmap)                               ///< View made invisible, a #PuglUnmapEvent
            CASEA (PUGL_CLOSE, close)                               ///< View will be closed, a #PuglCloseEvent
            CASE3 (PUGL_FOCUS_IN, focus_in, ev->focus)              ///< Keyboard focus entered view, a #PuglFocusEvent
            CASE3 (PUGL_FOCUS_OUT, focus_out, ev->focus)            ///< Keyboard focus left view, a #PuglFocusEvent
            CASE3 (PUGL_KEY_PRESS, key_press, ev->key)              ///< Key pressed, a #PuglKeyEvent
            CASE3 (PUGL_KEY_RELEASE, key_release, ev->key)          ///< Key released, a #PuglKeyEvent
            CASE2 (PUGL_TEXT, text)                                 ///< Character entered, a #PuglTextEvent
            CASE3 (PUGL_POINTER_IN, pointer_in, ev->crossing)       ///< Pointer entered view, a #PuglCrossingEvent
            CASE3 (PUGL_POINTER_OUT, pointer_out, ev->crossing)     ///< Pointer left view, a #PuglCrossingEvent
            CASE3 (PUGL_BUTTON_PRESS, button_press, ev->button)     ///< Mouse button pressed, a #PuglButtonEvent
            CASE3 (PUGL_BUTTON_RELEASE, button_release, ev->button) ///< Mouse button released, a #PuglButtonEvent
            CASE2 (PUGL_MOTION, motion)                             ///< Pointer moved, a #PuglMotionEvent
            CASE2 (PUGL_SCROLL, scroll)                             ///< Scrolled, a #PuglScrollEvent
            CASE2 (PUGL_CLIENT, client)                             ///< Custom client message, a #PuglClientEvent
            CASE2 (PUGL_TIMER, timer)                               ///< Timer triggered, a #PuglTimerEvent
            CASEA (PUGL_LOOP_ENTER, loop_enter)                     ///< Recursive loop entered, a #PuglLoopEnterEvent
            CASEA (PUGL_LOOP_LEAVE, loop_leave)                     ///< Recursive loop left, a #PuglLoopLeaveEvent
            CASE3 (PUGL_DATA_OFFER, data_offer, ev->offer)          ///< Data offered from clipboard, a #PuglDataOfferEvent
            CASE2 (PUGL_DATA, data)                                 ///< Data available from clipboard, a #PuglDataEvent
            CASE3 (PUGL_NOTHING, nothing, ev->any)                  ///< No event
            default:
                break;
        }
#undef CASE2
#undef CASE3
#undef CASEA
        return status;
    }
};

View::View (Main& m, Widget& w)
    : _main (m),
      _widget (w) {
    _view  = (uintptr_t) puglNewView ((PuglWorld*) m.world());
    auto v = (PuglView*) _view;
    puglSetHandle (v, this);
    puglSetEventFunc (v, EventHandler::dispatch);
    _weak_status.reset (this);
    _main._views.push_back (this);
}

View::~View() {
    detail::erase (_main._views, this);
    _weak_status.reset();
    puglFreeView ((PuglView*) _view);
    _view = (uintptr_t) nullptr;
}

void View::set_backend (uintptr_t b) {
    puglSetBackend ((PuglView*) _view, (PuglBackend*) b);
}

void View::set_view_hint (int hint, int value) {
    puglSetViewHint ((PuglView*) _view, static_cast<PuglViewHint> (hint), value);
}

uintptr_t View::handle() { return puglGetNativeView ((PuglView*) _view); }
float View::scale_factor() const noexcept { return static_cast<float> (puglGetScaleFactor ((PuglView*) _view)); }

void View::set_visible (bool visible) {
    if (visible)
        puglShow ((PuglView*) _view);
    else
        puglHide ((PuglView*) _view);
}

bool View::visible() const { return puglGetVisible ((PuglView*) _view); }

void View::set_size (int width, int height) {
    puglSetSize ((PuglView*) _view, width * scale_factor(), height * scale_factor());
}

Rectangle<int> View::bounds() const {
    auto f = puglGetFrame ((PuglView*) _view);
    return {
        static_cast<int> ((float) f.x / scale_factor()),
        static_cast<int> ((float) f.y / scale_factor()),
        static_cast<int> ((float) f.width / scale_factor()),
        static_cast<int> ((float) f.height / scale_factor())
    };
}

void View::set_bounds (Bounds b) {
    b *= scale_factor();
    puglSetFrame ((PuglView*) _view, detail::frame (b));
}

void View::realize() {
    puglRealize ((PuglView*) _view);
}

Style& View::style() noexcept { return _main.style(); }
const Style& View::style() const noexcept { return _main.style(); }

void View::elevate (Widget& widget, ViewFlags flags) {
    _main.elevate (widget, flags, *this);
}

//==
void View::render (Surface& ctx) {
    Graphics g (ctx);
    _widget.render (g);
}

void View::set_parent (uintptr_t parent, bool transient) {
    if (! parent)
        return;
    if (transient)
        puglSetTransientParent ((PuglView*) _view, parent);
    else
        puglSetParentWindow ((PuglView*) _view, parent);
}

void View::__pugl_post_redisplay() {
    puglPostRedisplay ((PuglView*) _view);
}

} // namespace lvtk
<|endoftext|>