<commit_before>
#include "ksp_plugin/pile_up.hpp"

#include <list>
#include <map>

#include "geometry/identity.hpp"
#include "ksp_plugin/part.hpp"
#include "physics/rigid_motion.hpp"

namespace principia {
namespace ksp_plugin {
namespace internal_pile_up {

using base::FindOrDie;
using base::make_not_null_unique;
using geometry::AngularVelocity;
using geometry::BarycentreCalculator;
using geometry::Identity;
using geometry::OrthogonalMap;
using geometry::Position;
using geometry::Velocity;
using physics::DegreesOfFreedom;
using physics::RigidMotion;
using physics::RigidTransformation;

PileUp::PileUp(std::list<not_null<Part*>>&& parts, Instant const& t)
    : parts_(std::move(parts)),
      psychohistory_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {
  BarycentreCalculator<DegreesOfFreedom<Barycentric>, Mass> calculator;
  Vector<Force, Barycentric> total_intrinsic_force;
  for (not_null<Part*> const part : parts_) {
    total_intrinsic_force += part->intrinsic_force();
    calculator.Add(part->degrees_of_freedom(), part->mass());
  }
  mass_ = calculator.weight();
  intrinsic_force_ = total_intrinsic_force;
  DegreesOfFreedom<Barycentric> const barycentre = calculator.Get();
  psychohistory_->Append(t, barycentre);

  RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up{
      RigidTransformation<Barycentric, RigidPileUp>{
          barycentre.position(),
          RigidPileUp::origin,
          Identity<Barycentric, RigidPileUp>().Forget()},
      AngularVelocity<Barycentric>{},
      barycentre.velocity()};
  for (not_null<Part*> const part : parts_) {
    actual_part_degrees_of_freedom_.emplace(
        part,
        barycentric_to_pile_up(part->degrees_of_freedom()));
  }
}

void PileUp::set_mass(Mass const& mass) {
  mass_ = mass;
}

void PileUp::set_intrinsic_force(
    Vector<Force, Barycentric> const& intrinsic_force) {
  intrinsic_force_ = intrinsic_force;
}

std::list<not_null<Part*>> const& PileUp::parts() const {
  return parts_;
}

void PileUp::SetPartApparentDegreesOfFreedom(
    not_null<Part*> const part,
    DegreesOfFreedom<ApparentBubble> const& degrees_of_freedom) {
  std::map<not_null<Part*>, DegreesOfFreedom<ApparentBubble>>::iterator it;
  bool inserted;
  std::tie(it, inserted) =
      apparent_part_degrees_of_freedom_.emplace(part, degrees_of_freedom);
  CHECK(inserted) << "Duplicate part " << part << " at "
                  << degrees_of_freedom;
}

void PileUp::DeformPileUpIfNeeded() {
  if (apparent_part_degrees_of_freedom_.empty()) {
    return;
  }
  // A consistency check that |SetPartApparentDegreesOfFreedom| was called for
  // all the parts.
  CHECK_EQ(parts_.size(), apparent_part_degrees_of_freedom_.size());
  for (not_null<Part*> const part : parts_) {
    CHECK_GT(apparent_part_degrees_of_freedom_.count(part), 0);
  }

  // Compute the apparent centre of mass of the parts.
  BarycentreCalculator<DegreesOfFreedom<ApparentBubble>, Mass> calculator;
  for (auto const& pair : apparent_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& apparent_part_degrees_of_freedom = pair.second;
    calculator.Add(apparent_part_degrees_of_freedom, part->mass());
  }
  auto const apparent_centre_of_mass = calculator.Get();

  // A motion that maps the apparent centre of mass of the parts to the actual
  // centre of mass of the pile-up.
  RigidTransformation<ApparentBubble, RigidPileUp> const
      apparent_bubble_to_pile_up_transformation(
          apparent_centre_of_mass.position(),
          RigidPileUp::origin,
          Identity<ApparentBubble, RigidPileUp>().Forget());
  RigidMotion<ApparentBubble, RigidPileUp> const
      apparent_bubble_to_pile_up_motion(
          apparent_bubble_to_pile_up_transformation,
          AngularVelocity<ApparentBubble>(),
          apparent_centre_of_mass.velocity());

  // Now update the positions of the parts in the pile-up frame.
  actual_part_degrees_of_freedom_.clear();
  for (auto const& pair : apparent_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& apparent_part_degrees_of_freedom = pair.second;
    actual_part_degrees_of_freedom_.emplace(
        part,
        apparent_bubble_to_pile_up_motion(apparent_part_degrees_of_freedom));
  }
  apparent_part_degrees_of_freedom_.clear();
}

void PileUp::AdvanceTime(
    Ephemeris<Barycentric>& ephemeris,
    Instant const& t,
    Ephemeris<Barycentric>::FixedStepParameters const& fixed_step_parameters,
    Ephemeris<Barycentric>::AdaptiveStepParameters const&
        adaptive_step_parameters) {
  CHECK_GE(psychohistory_->Size(), 1);
  CHECK_LE(psychohistory_->Size(), 2);

  // Remove the non-authoritative point.
  psychohistory_->ForgetAfter(last_authoritative().time());
  bool last_point_is_authoritative = true;

  CHECK_EQ(psychohistory_->Size(), 1);
  if (intrinsic_force_ == Vector<Force, Barycentric>{}) {
    ephemeris.FlowWithFixedStep(
        {psychohistory_.get()},
        Ephemeris<Barycentric>::NoIntrinsicAccelerations,
        t,
        fixed_step_parameters);
    if (psychohistory_->last().time() < t) {
      CHECK(ephemeris.FlowWithAdaptiveStep(
                psychohistory_.get(),
                Ephemeris<Barycentric>::NoIntrinsicAcceleration,
                t,
                adaptive_step_parameters,
                Ephemeris<Barycentric>::unlimited_max_ephemeris_steps,
                /*last_point_only=*/true));
      last_point_is_authoritative = false;
    }
  } else {
    auto const a = intrinsic_force_ / mass_;
    auto const intrinsic_acceleration = [a](Instant const& t) { return a; };
    CHECK(ephemeris.FlowWithAdaptiveStep(
              psychohistory_.get(),
              intrinsic_acceleration,
              t,
              adaptive_step_parameters,
              Ephemeris<Barycentric>::unlimited_max_ephemeris_steps,
              /*last_point_only=*/false));
  }
  auto it = psychohistory_->Begin();
  ++it;
  for (; it != psychohistory_->End(); ++it) {
    AppendToPartTails(it,
                      /*authoritative=*/it != psychohistory_->last() ||
                                        last_point_is_authoritative);
  }
  psychohistory_->ForgetBefore(last_point_is_authoritative
                                   ? psychohistory_->last().time()
                                   : (--psychohistory_->last()).time());
  CHECK(last_point_is_authoritative ? psychohistory_->Size() == 1
                                    : psychohistory_->Size() == 2)
      << NAMED(last_point_is_authoritative) << ", "
      << NAMED(psychohistory_->Size());
}

void PileUp::NudgeParts() const {
  auto const actual_centre_of_mass =
      psychohistory_->last().degrees_of_freedom();

  RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up{
      RigidTransformation<Barycentric, RigidPileUp>{
          actual_centre_of_mass.position(),
          RigidPileUp::origin,
          Identity<Barycentric, RigidPileUp>().Forget()},
      AngularVelocity<Barycentric>(),
      actual_centre_of_mass.velocity()};
  auto const pile_up_to_barycentric = barycentric_to_pile_up.Inverse();
  for (not_null<Part*> const part : parts_) {
    part->set_degrees_of_freedom(pile_up_to_barycentric(
        FindOrDie(actual_part_degrees_of_freedom_, part)));
  }
}

void PileUp::WriteToMessage(not_null<serialization::PileUp*> message) const {
  for (auto const part : parts_) {
    message->add_part_id(part->part_id());
  }
  mass_.WriteToMessage(message->mutable_mass());
  intrinsic_force_.WriteToMessage(message->mutable_intrinsic_force());
  psychohistory_->WriteToMessage(message->mutable_psychohistory(),
                                 /*forks=*/{});
  for (auto const& pair : actual_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& degrees_of_freedom = pair.second;
    degrees_of_freedom.WriteToMessage(&(
        (*message->mutable_actual_part_degrees_of_freedom())[part->part_id()]));
  }
  for (auto const& pair : apparent_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& degrees_of_freedom = pair.second;
    degrees_of_freedom.WriteToMessage(&(
        (*message
              ->mutable_apparent_part_degrees_of_freedom())[part->part_id()]));
  }
}

not_null<std::unique_ptr<PileUp>> PileUp::ReadFromMessage(
    serialization::PileUp const& message,
    std::function<not_null<Part*>(PartId)> const& part_id_to_part) {
  std::list<not_null<Part*>> parts;
  for (auto const part_id : message.part_id()) {
    parts.push_back(part_id_to_part(part_id));
  }
  not_null<std::unique_ptr<PileUp>> pile_up =
      std::unique_ptr<PileUp>(new PileUp(std::move(parts)));
  pile_up->mass_ = Mass::ReadFromMessage(message.mass());
  pile_up->intrinsic_force_ =
      Vector<Force, Barycentric>::ReadFromMessage(message.intrinsic_force());
  pile_up->psychohistory_ =
      DiscreteTrajectory<Barycentric>::ReadFromMessage(message.psychohistory(),
                                                       /*forks=*/{});
  for (auto const& pair : message.actual_part_degrees_of_freedom()) {
    std::uint32_t const part_id = pair.first;
    serialization::Pair const& degrees_of_freedom = pair.second;
    pile_up->actual_part_degrees_of_freedom_.emplace(
        part_id_to_part(part_id),
        DegreesOfFreedom<RigidPileUp>::ReadFromMessage(degrees_of_freedom));
  }
  for (auto const& pair : message.apparent_part_degrees_of_freedom()) {
    std::uint32_t const part_id = pair.first;
    serialization::Pair const& degrees_of_freedom = pair.second;
    pile_up->apparent_part_degrees_of_freedom_.emplace(
        part_id_to_part(part_id),
        DegreesOfFreedom<ApparentBubble>::ReadFromMessage(degrees_of_freedom));
  }
  return pile_up;
}

PileUp::PileUp(std::list<not_null<Part*>>&& parts)
    : parts_(std::move(parts)),
      psychohistory_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {}

void PileUp::AppendToPartTails(
    DiscreteTrajectory<Barycentric>::Iterator const it,
    bool const authoritative) const {
  auto const& pile_up_dof = it.degrees_of_freedom();
  RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up(
      RigidTransformation<Barycentric, RigidPileUp>(
          pile_up_dof.position(),
          RigidPileUp::origin,
          Identity<Barycentric, RigidPileUp>().Forget()),
      AngularVelocity<Barycentric>{},
      pile_up_dof.velocity());
  auto const pile_up_to_barycentric = barycentric_to_pile_up.Inverse();
  for (not_null<Part*> const part : parts_) {
    part->tail().Append(it.time(),
                        pile_up_to_barycentric(
                            FindOrDie(actual_part_degrees_of_freedom_, part)));
    part->set_tail_is_authoritative(authoritative);
  }
}

DiscreteTrajectory<Barycentric>::Iterator PileUp::last_authoritative() const {
  return (psychohistory_->Size() == 1) ? psychohistory_->last()
                                       : --psychohistory_->last();
}

}  // namespace internal_pile_up
}  // namespace ksp_plugin
}  // namespace principia
<commit_msg>It would.<commit_after>
#include "ksp_plugin/pile_up.hpp"

#include <list>
#include <map>

#include "geometry/identity.hpp"
#include "ksp_plugin/part.hpp"
#include "physics/rigid_motion.hpp"

namespace principia {
namespace ksp_plugin {
namespace internal_pile_up {

using base::FindOrDie;
using base::make_not_null_unique;
using geometry::AngularVelocity;
using geometry::BarycentreCalculator;
using geometry::Identity;
using geometry::OrthogonalMap;
using geometry::Position;
using geometry::Velocity;
using physics::DegreesOfFreedom;
using physics::RigidMotion;
using physics::RigidTransformation;

PileUp::PileUp(std::list<not_null<Part*>>&& parts, Instant const& t)
    : parts_(std::move(parts)),
      psychohistory_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {
  BarycentreCalculator<DegreesOfFreedom<Barycentric>, Mass> calculator;
  Vector<Force, Barycentric> total_intrinsic_force;
  for (not_null<Part*> const part : parts_) {
    total_intrinsic_force += part->intrinsic_force();
    calculator.Add(part->degrees_of_freedom(), part->mass());
  }
  mass_ = calculator.weight();
  intrinsic_force_ = total_intrinsic_force;
  DegreesOfFreedom<Barycentric> const barycentre = calculator.Get();
  psychohistory_->Append(t, barycentre);

  RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up{
      RigidTransformation<Barycentric, RigidPileUp>{
          barycentre.position(),
          RigidPileUp::origin,
          Identity<Barycentric, RigidPileUp>().Forget()},
      AngularVelocity<Barycentric>{},
      barycentre.velocity()};
  for (not_null<Part*> const part : parts_) {
    actual_part_degrees_of_freedom_.emplace(
        part,
        barycentric_to_pile_up(part->degrees_of_freedom()));
  }
}

void PileUp::set_mass(Mass const& mass) {
  mass_ = mass;
}

void PileUp::set_intrinsic_force(
    Vector<Force, Barycentric> const& intrinsic_force) {
  intrinsic_force_ = intrinsic_force;
}

std::list<not_null<Part*>> const& PileUp::parts() const {
  return parts_;
}

void PileUp::SetPartApparentDegreesOfFreedom(
    not_null<Part*> const part,
    DegreesOfFreedom<ApparentBubble> const& degrees_of_freedom) {
  std::map<not_null<Part*>, DegreesOfFreedom<ApparentBubble>>::iterator it;
  bool inserted;
  std::tie(it, inserted) =
      apparent_part_degrees_of_freedom_.emplace(part, degrees_of_freedom);
  CHECK(inserted) << "Duplicate part " << part << " at "
                  << degrees_of_freedom;
}

void PileUp::DeformPileUpIfNeeded() {
  if (apparent_part_degrees_of_freedom_.empty()) {
    return;
  }
  // A consistency check that |SetPartApparentDegreesOfFreedom| was called for
  // all the parts.
  CHECK_EQ(parts_.size(), apparent_part_degrees_of_freedom_.size());
  for (not_null<Part*> const part : parts_) {
    CHECK_GT(apparent_part_degrees_of_freedom_.count(part), 0);
  }

  // Compute the apparent centre of mass of the parts.
  BarycentreCalculator<DegreesOfFreedom<ApparentBubble>, Mass> calculator;
  for (auto const& pair : apparent_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& apparent_part_degrees_of_freedom = pair.second;
    calculator.Add(apparent_part_degrees_of_freedom, part->mass());
  }
  auto const apparent_centre_of_mass = calculator.Get();

  // A motion that maps the apparent centre of mass of the parts to the actual
  // centre of mass of the pile-up.
  RigidTransformation<ApparentBubble, RigidPileUp> const
      apparent_bubble_to_pile_up_transformation(
          apparent_centre_of_mass.position(),
          RigidPileUp::origin,
          Identity<ApparentBubble, RigidPileUp>().Forget());
  RigidMotion<ApparentBubble, RigidPileUp> const
      apparent_bubble_to_pile_up_motion(
          apparent_bubble_to_pile_up_transformation,
          AngularVelocity<ApparentBubble>(),
          apparent_centre_of_mass.velocity());

  // Now update the positions of the parts in the pile-up frame.
  actual_part_degrees_of_freedom_.clear();
  for (auto const& pair : apparent_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& apparent_part_degrees_of_freedom = pair.second;
    actual_part_degrees_of_freedom_.emplace(
        part,
        apparent_bubble_to_pile_up_motion(apparent_part_degrees_of_freedom));
  }
  apparent_part_degrees_of_freedom_.clear();
}

void PileUp::AdvanceTime(
    Ephemeris<Barycentric>& ephemeris,
    Instant const& t,
    Ephemeris<Barycentric>::FixedStepParameters const& fixed_step_parameters,
    Ephemeris<Barycentric>::AdaptiveStepParameters const&
        adaptive_step_parameters) {
  CHECK_GE(psychohistory_->Size(), 1);
  CHECK_LE(psychohistory_->Size(), 2);

  bool last_point_is_authoritative = true;

  if (intrinsic_force_ == Vector<Force, Barycentric>{}) {
    // Remove the non-authoritative point.
    psychohistory_->ForgetAfter(last_authoritative().time());
    CHECK_EQ(psychohistory_->Size(), 1);
    ephemeris.FlowWithFixedStep(
        {psychohistory_.get()},
        Ephemeris<Barycentric>::NoIntrinsicAccelerations,
        t,
        fixed_step_parameters);
    if (psychohistory_->last().time() < t) {
      CHECK(ephemeris.FlowWithAdaptiveStep(
                psychohistory_.get(),
                Ephemeris<Barycentric>::NoIntrinsicAcceleration,
                t,
                adaptive_step_parameters,
                Ephemeris<Barycentric>::unlimited_max_ephemeris_steps,
                /*last_point_only=*/true));
      last_point_is_authoritative = false;
    }
  } else {
    // We make the existing last point authoritative, i.e. we do not remove it.
    // If it was already authoritative nothing happen, if it was not, we
    // integrate on top of it, and it gets appended authoritatively to the part
    // tails.
    auto const a = intrinsic_force_ / mass_;
    auto const intrinsic_acceleration = [a](Instant const& t) { return a; };
    CHECK(ephemeris.FlowWithAdaptiveStep(
              psychohistory_.get(),
              intrinsic_acceleration,
              t,
              adaptive_step_parameters,
              Ephemeris<Barycentric>::unlimited_max_ephemeris_steps,
              /*last_point_only=*/false));
  }
  auto it = psychohistory_->Begin();
  ++it;
  for (; it != psychohistory_->End(); ++it) {
    AppendToPartTails(it,
                      /*authoritative=*/it != psychohistory_->last() ||
                                        last_point_is_authoritative);
  }
  psychohistory_->ForgetBefore(last_point_is_authoritative
                                   ? psychohistory_->last().time()
                                   : (--psychohistory_->last()).time());
  CHECK(last_point_is_authoritative ? psychohistory_->Size() == 1
                                    : psychohistory_->Size() == 2)
      << NAMED(last_point_is_authoritative) << ", "
      << NAMED(psychohistory_->Size());
}

void PileUp::NudgeParts() const {
  auto const actual_centre_of_mass =
      psychohistory_->last().degrees_of_freedom();

  RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up{
      RigidTransformation<Barycentric, RigidPileUp>{
          actual_centre_of_mass.position(),
          RigidPileUp::origin,
          Identity<Barycentric, RigidPileUp>().Forget()},
      AngularVelocity<Barycentric>(),
      actual_centre_of_mass.velocity()};
  auto const pile_up_to_barycentric = barycentric_to_pile_up.Inverse();
  for (not_null<Part*> const part : parts_) {
    part->set_degrees_of_freedom(pile_up_to_barycentric(
        FindOrDie(actual_part_degrees_of_freedom_, part)));
  }
}

void PileUp::WriteToMessage(not_null<serialization::PileUp*> message) const {
  for (auto const part : parts_) {
    message->add_part_id(part->part_id());
  }
  mass_.WriteToMessage(message->mutable_mass());
  intrinsic_force_.WriteToMessage(message->mutable_intrinsic_force());
  psychohistory_->WriteToMessage(message->mutable_psychohistory(),
                                 /*forks=*/{});
  for (auto const& pair : actual_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& degrees_of_freedom = pair.second;
    degrees_of_freedom.WriteToMessage(&(
        (*message->mutable_actual_part_degrees_of_freedom())[part->part_id()]));
  }
  for (auto const& pair : apparent_part_degrees_of_freedom_) {
    auto const part = pair.first;
    auto const& degrees_of_freedom = pair.second;
    degrees_of_freedom.WriteToMessage(&(
        (*message
              ->mutable_apparent_part_degrees_of_freedom())[part->part_id()]));
  }
}

not_null<std::unique_ptr<PileUp>> PileUp::ReadFromMessage(
    serialization::PileUp const& message,
    std::function<not_null<Part*>(PartId)> const& part_id_to_part) {
  std::list<not_null<Part*>> parts;
  for (auto const part_id : message.part_id()) {
    parts.push_back(part_id_to_part(part_id));
  }
  not_null<std::unique_ptr<PileUp>> pile_up =
      std::unique_ptr<PileUp>(new PileUp(std::move(parts)));
  pile_up->mass_ = Mass::ReadFromMessage(message.mass());
  pile_up->intrinsic_force_ =
      Vector<Force, Barycentric>::ReadFromMessage(message.intrinsic_force());
  pile_up->psychohistory_ =
      DiscreteTrajectory<Barycentric>::ReadFromMessage(message.psychohistory(),
                                                       /*forks=*/{});
  for (auto const& pair : message.actual_part_degrees_of_freedom()) {
    std::uint32_t const part_id = pair.first;
    serialization::Pair const& degrees_of_freedom = pair.second;
    pile_up->actual_part_degrees_of_freedom_.emplace(
        part_id_to_part(part_id),
        DegreesOfFreedom<RigidPileUp>::ReadFromMessage(degrees_of_freedom));
  }
  for (auto const& pair : message.apparent_part_degrees_of_freedom()) {
    std::uint32_t const part_id = pair.first;
    serialization::Pair const& degrees_of_freedom = pair.second;
    pile_up->apparent_part_degrees_of_freedom_.emplace(
        part_id_to_part(part_id),
        DegreesOfFreedom<ApparentBubble>::ReadFromMessage(degrees_of_freedom));
  }
  return pile_up;
}

PileUp::PileUp(std::list<not_null<Part*>>&& parts)
    : parts_(std::move(parts)),
      psychohistory_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {}

void PileUp::AppendToPartTails(
    DiscreteTrajectory<Barycentric>::Iterator const it,
    bool const authoritative) const {
  auto const& pile_up_dof = it.degrees_of_freedom();
  RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up(
      RigidTransformation<Barycentric, RigidPileUp>(
          pile_up_dof.position(),
          RigidPileUp::origin,
          Identity<Barycentric, RigidPileUp>().Forget()),
      AngularVelocity<Barycentric>{},
      pile_up_dof.velocity());
  auto const pile_up_to_barycentric = barycentric_to_pile_up.Inverse();
  for (not_null<Part*> const part : parts_) {
    part->tail().Append(it.time(),
                        pile_up_to_barycentric(
                            FindOrDie(actual_part_degrees_of_freedom_, part)));
    part->set_tail_is_authoritative(authoritative);
  }
}

DiscreteTrajectory<Barycentric>::Iterator PileUp::last_authoritative() const {
  return (psychohistory_->Size() == 1) ? psychohistory_->last()
                                       : --psychohistory_->last();
}

}  // namespace internal_pile_up
}  // namespace ksp_plugin
}  // namespace principia
<|endoftext|>


<commit_before>// @(#)root/editline:$Id$
// Author: Mary-Louise Gill, 2009

/*************************************************************************
 * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Getline_color.h"

#include <stack>
#include <string>

#include "TROOT.h"
#include "TInterpreter.h"
#include "textinput/Range.h"
#include "textinput/Text.h"

using namespace std;
using namespace textinput;

namespace {

   Color ColorFromName(const char* name) {
      // Convert a color name to a Color.
      Color ret;

      std::string lowname(name);
      size_t lenname = strlen(name);
      for (size_t i = 0; i < lenname; ++i)
         lowname[i] = tolower(lowname[i]);

      if (lowname.find("bold") != std::string::npos
          || lowname.find("light") != std::string::npos)
         ret.fModifiers |= Color::kModBold;
      if (lowname.find("under") != std::string::npos)
         ret.fModifiers |= Color::kModUnderline;

      size_t poshash = lowname.find('#');
      size_t lenrgb = 0;
      if (poshash != std::string::npos) {
         int endrgb = poshash + 1;
         while ((lowname[endrgb] >= '0' && lowname[endrgb] <= '9')
                || (lowname[endrgb] >= 'a' && lowname[endrgb] <= 'f')) {
            ++endrgb;
         }
         lenrgb = endrgb - poshash - 1;
      }

      int rgb[3] = {0};
      if (lenrgb == 3) {
         for (int i = 0; i < 3; ++i) {
            rgb[i] = lowname[poshash + 1 + i] - '0';
            if (rgb[i] > 9) {
               rgb[i] = rgb[i] + '0' - 'a' + 10;
            }
            rgb[i] *= 16; // only upper 4 bits are set.
         }
         return ret;
      } else if (lenrgb == 6) {
         for (int i = 0; i < 6; ++i) {
            int v = lowname[poshash + 1 + i] - '0';
            if (v > 9) {
               v = v + '0' - 'a' + 10;
            }
            if (i % 2 == 0) {
               v *= 16;
            }
            rgb[i / 2] += v;
         }
         ret.fR = rgb[0];
         ret.fG = rgb[1];
         ret.fB = rgb[2];
         return ret;
      } else {
         if (lowname.find("default") != std::string::npos) {
            return ret;
         }

         static const char* colornames[] = {
            "black", "red", "green", "yellow",
            "blue", "magenta", "cyan", "white", 0
         };
         static const unsigned char colorrgb[][3] = {
            {0,0,0}, {127,0,0}, {0,127,0}, {127,127,0},
            {0,0,127}, {127,0,127}, {0,127,127}, {127,127,127},
            {0}
         };

         for (int i = 0; colornames[i]; ++i) {
            if (lowname.find(colornames[i]) != std::string::npos) {
               int boldify = 0;
               if (ret.fModifiers & Color::kModBold)
                  boldify = 64;
               ret.fR = colorrgb[i][0] + boldify;
               ret.fG = colorrgb[i][1] + boldify;
               ret.fB = colorrgb[i][2] + boldify;
               return ret;
            }
         }
      }
      fprintf(stderr, "Getline_color/ColorFromName: cannot parse color %s!\n", name);
      return Color();
   } // ColorFromName()

   bool IsAlnum_(char c) { return c == '_' || isalnum(c); }
   bool IsAlpha_(char c) { return c == '_' || isalpha(c); }
} // unnamed namespace

ROOT::TextInputColorizer::TextInputColorizer():
   fColorIsDefault(), fPrevBracketColor(kColorNone) {
   // Set the default colors.
   // fColors[kColorNone] stays default initialized.
   fColors[kColorType] = ColorFromName("blue");
   fColors[kColorTabComp] = ColorFromName("magenta");
   fColors[kColorBracket] = ColorFromName("green");
   fColors[kColorBadBracket] = ColorFromName("red");
   fColors[kColorPrompt] = ColorFromName("default");
   fColorIsDefault[kColorPrompt] = true;
}

ROOT::TextInputColorizer::~TextInputColorizer() {
   // pin vtable
}

void ROOT::TextInputColorizer::ExtendRangeAndSetColor(Text& input,
                                                      size_t idx, char col,
                                                      Range& disp) {
   // Utility function that updates the display modification range if the
   // color at index idx is different from what it was before.

   if (fColorIsDefault[(int)col]) {
      // Never mind the color: use use default.
      col = 0;
   }
   if (input.GetColor(idx) != col) {
      input.SetColor(idx, col);
      disp.Extend(idx);
   }
}

bool ROOT::TextInputColorizer::GetColor(char type, Color& col) {
   // Set the Color corresponding to an entry in EColorTypes.
   // Returns false if the type index is out of range.

   if (type < (int)kNumColors) {
      col = fColors[(size_t)type];
      return true;
   }
   col = Color();
   return false;
}

void ROOT::TextInputColorizer::SetColors(const char* colorType,
                                         const char* colorTabComp,
                                         const char* colorBracket,
                                         const char* colorBadBracket,
                                         const char* colorPrompt) {
   // Set the colors of the different items as either
   // #RGB
   // #RRGGBB or
   // color name, optionally prepended by "underline" or "bold"

   fColors[kColorType] = ColorFromName(colorType);
   fColorIsDefault[kColorType] = (fColors[kColorType] == Color());
   fColors[kColorTabComp] = ColorFromName(colorTabComp);
   fColorIsDefault[kColorTabComp] = (fColors[kColorTabComp] == Color());
   fColors[kColorBracket] = ColorFromName(colorBracket);
   fColorIsDefault[kColorBracket] = (fColors[kColorBracket] == Color());
   fColors[kColorBadBracket] = ColorFromName(colorBadBracket);
   fColorIsDefault[kColorBadBracket] = (fColors[kColorBadBracket] == Color());
   fColors[kColorPrompt] = ColorFromName(colorPrompt);
   fColorIsDefault[kColorPrompt] = (fColors[kColorPrompt] == Color());
}

void ROOT::TextInputColorizer::ProcessTextChange(EditorRange& Modification,
                                                 Text& input) {
   // The text has changed; look for word that are types.

   const std::string& text = input.GetText();

   size_t modStart = Modification.fEdit.fStart;
   size_t inputLength = input.length();

   // Find end of modified word:
   size_t modEnd = Modification.fEdit.fLength;
   if (modEnd == (size_t) -1) {
      modEnd = inputLength;
   } else {
      modEnd += modStart;
      if (modEnd > inputLength) {
         modEnd = inputLength;
      } else {
         while (modEnd < inputLength && IsAlnum_(text[modEnd]))
            ++modEnd;
      }
   }

   // Find beginning of modified word. Don't treat
   // "12ull" specially, it will fall out below.
   while (modStart && IsAlnum_(text[modStart])) --modStart;

   // Ignore spaces
   while (modStart < modEnd && isspace(text[modStart]))
      ++modStart;
   while (modEnd > modStart && isspace(text[modEnd]))
      --modStart;

   for (size_t i = modStart; i < modEnd;) {
      // i points to beginning of word here.
      if (isdigit(text[i])) {
         // "12", or "12ull". Default color.
         ExtendRangeAndSetColor(input, i, 0, Modification.fDisplay);
         ++i;
         while (i < modEnd && IsAlnum_(text[i])) {
            ExtendRangeAndSetColor(input, i, 0, Modification.fDisplay);
            ++i;
         }
      } else if (IsAlpha_(text[i])) {
         // identifier, but is it a type?
         size_t wordLen = 1;
         while (i + wordLen < modEnd && IsAlnum_(text[i + wordLen])) {
            ++wordLen;
         }
         std::string word = text.substr(i, wordLen);
         char color = kColorNone;
         if (gROOT->GetListOfTypes()->FindObject(word.c_str())
             || gInterpreter->CheckClassInfo(word.c_str(), kFALSE)) {
            color = kColorType;
         }
         for (size_t ic = i; ic < i + wordLen; ++ic) {
            ExtendRangeAndSetColor(input, ic, color, Modification.fDisplay);
         }
         i += wordLen;
      } else {
         size_t wordLen = 1;
         while (i + wordLen < modEnd && !IsAlnum_(text[i + wordLen]))
            ++wordLen;
         for (size_t ic = i; ic < i + wordLen; ++ic) {
            // protect colored parens
            char oldColor = input.GetColor(ic);
            if (oldColor != kColorBracket && oldColor != kColorBadBracket) {
               ExtendRangeAndSetColor(input, ic, kColorNone, Modification.fDisplay);
            }
         }
         i += wordLen;
      }

      // skip trailing whitespace.
      while (i < modEnd && isspace(text[i])) {
         ExtendRangeAndSetColor(input, i, kColorNone, Modification.fDisplay);
         ++i;
      }
   }
}

void ROOT::TextInputColorizer::ProcessPromptChange(Text& prompt) {
   int idx = kColorPrompt;
   if (fColorIsDefault[kColorPrompt]) {
      idx = 0;
   }
   prompt.SetColor(Range::AllText(), idx);
}

void ROOT::TextInputColorizer::ProcessCursorChange(size_t Cursor,
                                                   Text& input,
                                                   Range& DisplayR) {
   // Check each char to see if it is an opening bracket,
   // if so, check for its closing one and color them green.

   static const int numBrackets = 3;
   static const char bTypes[numBrackets][3] = {"()", "{}", "[]"};

   if (input.empty()) return;

   if (fPrevBracketColor != kColorNone) {
      // Remove previous bracket coloring.
      const char* colors = &input.GetColors()[0];
      const char* prevBracket = (const char*) memchr(colors, fPrevBracketColor,
                                                     input.length());
      if (prevBracket) {
         ExtendRangeAndSetColor(input, prevBracket - colors, kColorNone, DisplayR);
         if (fPrevBracketColor == kColorBracket) {
            // There will be two.
            prevBracket = (const char*) memchr(prevBracket, fPrevBracketColor,
                                               input.length() - (prevBracket - colors));
            if (prevBracket) {
               ExtendRangeAndSetColor(input, prevBracket - colors, kColorNone,
                                      DisplayR);
            }
         }
      }
   }

   // locations of brackets
   stack<size_t> locBrackets;
   int foundParenIdx = -1;
   int parenType = 0;
   const std::string& text = input.GetText();

   if (Cursor < input.length()) {
      // check against each bracket type
      for (; parenType < numBrackets; parenType++) {
         // if current char is equal to opening bracket, push onto stack
         if (text[Cursor] == bTypes[parenType][0]) {
            locBrackets.push(Cursor);
            foundParenIdx = 0;
            break;
         } else if (text[Cursor] == bTypes[parenType][1]) {
            locBrackets.push(Cursor);
            foundParenIdx = 1;
            break;
         }
      }
   }

   // current cursor char is not an open bracket, and there is a previous char
   // to check
   if (foundParenIdx == -1 && Cursor > 0) {
      // check previously typed char for being a closing bracket
      --Cursor;
      // check against each bracket type
      parenType = 0;

      for (; parenType < numBrackets; parenType++) {
         // if current char is equal to closing bracket, push onto stack
         if (text[Cursor] == bTypes[parenType][1]) {
            locBrackets.push(Cursor);
            foundParenIdx = 1;
            break;
         }
      }
   }
   // no bracket found on either current or previous char, return.
   if (foundParenIdx == -1) {
      return;
   }

   // terate through remaining letters until find a matching closing bracket
   // if another open bracket of the same type is found, push onto stack
   // and pop on next closing bracket match
   int direction = 1;

   if (foundParenIdx == 1) {
      direction = -1;
   }

   size_t lenLine = input.length();
   // direction == -1: Cursor - 1 to front.
   size_t scanBegin = (Cursor > 0) ? Cursor - 1 : 0;
   size_t scanLast = 0;
   if (direction == 1) {
      // direction == 1: Cursor + 1 to end.
      scanBegin = Cursor + 1;
      scanLast = lenLine - 1;
      if (scanBegin > scanLast) return;
   }
   for (size_t i = scanBegin; true /*avoid "unsigned >= 0" condition*/; i += direction) {
      // if current char is equal to another opening bracket, push onto stack
      if (text[i] == bTypes[parenType][foundParenIdx]) {
         // push index of bracket
         locBrackets.push(i);
      }
      // if current char is equal to closing bracket
      else if (text[i] == bTypes[parenType][1 - foundParenIdx]) {
         // pop previous opening bracket off stack
         locBrackets.pop();
         // if previous opening was the last entry and we are at the cursor, then highlight match
         if (locBrackets.empty()) {
            ExtendRangeAndSetColor(input, i, kColorBracket, DisplayR);
            ExtendRangeAndSetColor(input, Cursor, kColorBracket, DisplayR);
            fPrevBracketColor = kColorBracket;
            break;
         }
      }
      // loop termination check before possible underflow ("--0")
      if (i == scanLast) break;
   }

   if (!locBrackets.empty()) {
      ExtendRangeAndSetColor(input, Cursor, kColorBadBracket, DisplayR);
      fPrevBracketColor = kColorBadBracket;
   }

} // matchParentheses
<commit_msg>Don't use CheckClassInfo() which might trigger autoloading. Instead, use GetListOfClasses() for classes that don't have a rootmap file but are loaded, and TInterpreter::GetClassSharedLibs() for classes that are not yet loaded but have a rootmap entry.<commit_after>// @(#)root/editline:$Id$
// Author: Mary-Louise Gill, 2009

/*************************************************************************
 * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Getline_color.h"

#include <stack>
#include <string>

#include "TROOT.h"
#include "TInterpreter.h"
#include "textinput/Range.h"
#include "textinput/Text.h"

using namespace std;
using namespace textinput;

namespace {

   Color ColorFromName(const char* name) {
      // Convert a color name to a Color.
      Color ret;

      std::string lowname(name);
      size_t lenname = strlen(name);
      for (size_t i = 0; i < lenname; ++i)
         lowname[i] = tolower(lowname[i]);

      if (lowname.find("bold") != std::string::npos
          || lowname.find("light") != std::string::npos)
         ret.fModifiers |= Color::kModBold;
      if (lowname.find("under") != std::string::npos)
         ret.fModifiers |= Color::kModUnderline;

      size_t poshash = lowname.find('#');
      size_t lenrgb = 0;
      if (poshash != std::string::npos) {
         int endrgb = poshash + 1;
         while ((lowname[endrgb] >= '0' && lowname[endrgb] <= '9')
                || (lowname[endrgb] >= 'a' && lowname[endrgb] <= 'f')) {
            ++endrgb;
         }
         lenrgb = endrgb - poshash - 1;
      }

      int rgb[3] = {0};
      if (lenrgb == 3) {
         for (int i = 0; i < 3; ++i) {
            rgb[i] = lowname[poshash + 1 + i] - '0';
            if (rgb[i] > 9) {
               rgb[i] = rgb[i] + '0' - 'a' + 10;
            }
            rgb[i] *= 16; // only upper 4 bits are set.
         }
         return ret;
      } else if (lenrgb == 6) {
         for (int i = 0; i < 6; ++i) {
            int v = lowname[poshash + 1 + i] - '0';
            if (v > 9) {
               v = v + '0' - 'a' + 10;
            }
            if (i % 2 == 0) {
               v *= 16;
            }
            rgb[i / 2] += v;
         }
         ret.fR = rgb[0];
         ret.fG = rgb[1];
         ret.fB = rgb[2];
         return ret;
      } else {
         if (lowname.find("default") != std::string::npos) {
            return ret;
         }

         static const char* colornames[] = {
            "black", "red", "green", "yellow",
            "blue", "magenta", "cyan", "white", 0
         };
         static const unsigned char colorrgb[][3] = {
            {0,0,0}, {127,0,0}, {0,127,0}, {127,127,0},
            {0,0,127}, {127,0,127}, {0,127,127}, {127,127,127},
            {0}
         };

         for (int i = 0; colornames[i]; ++i) {
            if (lowname.find(colornames[i]) != std::string::npos) {
               int boldify = 0;
               if (ret.fModifiers & Color::kModBold)
                  boldify = 64;
               ret.fR = colorrgb[i][0] + boldify;
               ret.fG = colorrgb[i][1] + boldify;
               ret.fB = colorrgb[i][2] + boldify;
               return ret;
            }
         }
      }
      fprintf(stderr, "Getline_color/ColorFromName: cannot parse color %s!\n", name);
      return Color();
   } // ColorFromName()

   bool IsAlnum_(char c) { return c == '_' || isalnum(c); }
   bool IsAlpha_(char c) { return c == '_' || isalpha(c); }
} // unnamed namespace

ROOT::TextInputColorizer::TextInputColorizer():
   fColorIsDefault(), fPrevBracketColor(kColorNone) {
   // Set the default colors.
   // fColors[kColorNone] stays default initialized.
   fColors[kColorType] = ColorFromName("blue");
   fColors[kColorTabComp] = ColorFromName("magenta");
   fColors[kColorBracket] = ColorFromName("green");
   fColors[kColorBadBracket] = ColorFromName("red");
   fColors[kColorPrompt] = ColorFromName("default");
   fColorIsDefault[kColorPrompt] = true;
}

ROOT::TextInputColorizer::~TextInputColorizer() {
   // pin vtable
}

void ROOT::TextInputColorizer::ExtendRangeAndSetColor(Text& input,
                                                      size_t idx, char col,
                                                      Range& disp) {
   // Utility function that updates the display modification range if the
   // color at index idx is different from what it was before.

   if (fColorIsDefault[(int)col]) {
      // Never mind the color: use use default.
      col = 0;
   }
   if (input.GetColor(idx) != col) {
      input.SetColor(idx, col);
      disp.Extend(idx);
   }
}

bool ROOT::TextInputColorizer::GetColor(char type, Color& col) {
   // Set the Color corresponding to an entry in EColorTypes.
   // Returns false if the type index is out of range.

   if (type < (int)kNumColors) {
      col = fColors[(size_t)type];
      return true;
   }
   col = Color();
   return false;
}

void ROOT::TextInputColorizer::SetColors(const char* colorType,
                                         const char* colorTabComp,
                                         const char* colorBracket,
                                         const char* colorBadBracket,
                                         const char* colorPrompt) {
   // Set the colors of the different items as either
   // #RGB
   // #RRGGBB or
   // color name, optionally prepended by "underline" or "bold"

   fColors[kColorType] = ColorFromName(colorType);
   fColorIsDefault[kColorType] = (fColors[kColorType] == Color());
   fColors[kColorTabComp] = ColorFromName(colorTabComp);
   fColorIsDefault[kColorTabComp] = (fColors[kColorTabComp] == Color());
   fColors[kColorBracket] = ColorFromName(colorBracket);
   fColorIsDefault[kColorBracket] = (fColors[kColorBracket] == Color());
   fColors[kColorBadBracket] = ColorFromName(colorBadBracket);
   fColorIsDefault[kColorBadBracket] = (fColors[kColorBadBracket] == Color());
   fColors[kColorPrompt] = ColorFromName(colorPrompt);
   fColorIsDefault[kColorPrompt] = (fColors[kColorPrompt] == Color());
}

void ROOT::TextInputColorizer::ProcessTextChange(EditorRange& Modification,
                                                 Text& input) {
   // The text has changed; look for word that are types.

   const std::string& text = input.GetText();

   size_t modStart = Modification.fEdit.fStart;
   size_t inputLength = input.length();

   // Find end of modified word:
   size_t modEnd = Modification.fEdit.fLength;
   if (modEnd == (size_t) -1) {
      modEnd = inputLength;
   } else {
      modEnd += modStart;
      if (modEnd > inputLength) {
         modEnd = inputLength;
      } else {
         while (modEnd < inputLength && IsAlnum_(text[modEnd]))
            ++modEnd;
      }
   }

   // Find beginning of modified word. Don't treat
   // "12ull" specially, it will fall out below.
   while (modStart && IsAlnum_(text[modStart])) --modStart;

   // Ignore spaces
   while (modStart < modEnd && isspace(text[modStart]))
      ++modStart;
   while (modEnd > modStart && isspace(text[modEnd]))
      --modStart;

   for (size_t i = modStart; i < modEnd;) {
      // i points to beginning of word here.
      if (isdigit(text[i])) {
         // "12", or "12ull". Default color.
         ExtendRangeAndSetColor(input, i, 0, Modification.fDisplay);
         ++i;
         while (i < modEnd && IsAlnum_(text[i])) {
            ExtendRangeAndSetColor(input, i, 0, Modification.fDisplay);
            ++i;
         }
      } else if (IsAlpha_(text[i])) {
         // identifier, but is it a type?
         size_t wordLen = 1;
         while (i + wordLen < modEnd && IsAlnum_(text[i + wordLen])) {
            ++wordLen;
         }
         std::string word = text.substr(i, wordLen);
         char color = kColorNone;
         if (gROOT->GetListOfTypes()->FindObject(word.c_str())
             || gROOT->GetListOfClasses()->FindObject(word.c_str())
             || gInterpreter->GetClassSharedLibs(word.c_str())) {
            color = kColorType;
         }
         for (size_t ic = i; ic < i + wordLen; ++ic) {
            ExtendRangeAndSetColor(input, ic, color, Modification.fDisplay);
         }
         i += wordLen;
      } else {
         size_t wordLen = 1;
         while (i + wordLen < modEnd && !IsAlnum_(text[i + wordLen]))
            ++wordLen;
         for (size_t ic = i; ic < i + wordLen; ++ic) {
            // protect colored parens
            char oldColor = input.GetColor(ic);
            if (oldColor != kColorBracket && oldColor != kColorBadBracket) {
               ExtendRangeAndSetColor(input, ic, kColorNone, Modification.fDisplay);
            }
         }
         i += wordLen;
      }

      // skip trailing whitespace.
      while (i < modEnd && isspace(text[i])) {
         ExtendRangeAndSetColor(input, i, kColorNone, Modification.fDisplay);
         ++i;
      }
   }
}

void ROOT::TextInputColorizer::ProcessPromptChange(Text& prompt) {
   int idx = kColorPrompt;
   if (fColorIsDefault[kColorPrompt]) {
      idx = 0;
   }
   prompt.SetColor(Range::AllText(), idx);
}

void ROOT::TextInputColorizer::ProcessCursorChange(size_t Cursor,
                                                   Text& input,
                                                   Range& DisplayR) {
   // Check each char to see if it is an opening bracket,
   // if so, check for its closing one and color them green.

   static const int numBrackets = 3;
   static const char bTypes[numBrackets][3] = {"()", "{}", "[]"};

   if (input.empty()) return;

   if (fPrevBracketColor != kColorNone) {
      // Remove previous bracket coloring.
      const char* colors = &input.GetColors()[0];
      const char* prevBracket = (const char*) memchr(colors, fPrevBracketColor,
                                                     input.length());
      if (prevBracket) {
         ExtendRangeAndSetColor(input, prevBracket - colors, kColorNone, DisplayR);
         if (fPrevBracketColor == kColorBracket) {
            // There will be two.
            prevBracket = (const char*) memchr(prevBracket, fPrevBracketColor,
                                               input.length() - (prevBracket - colors));
            if (prevBracket) {
               ExtendRangeAndSetColor(input, prevBracket - colors, kColorNone,
                                      DisplayR);
            }
         }
      }
   }

   // locations of brackets
   stack<size_t> locBrackets;
   int foundParenIdx = -1;
   int parenType = 0;
   const std::string& text = input.GetText();

   if (Cursor < input.length()) {
      // check against each bracket type
      for (; parenType < numBrackets; parenType++) {
         // if current char is equal to opening bracket, push onto stack
         if (text[Cursor] == bTypes[parenType][0]) {
            locBrackets.push(Cursor);
            foundParenIdx = 0;
            break;
         } else if (text[Cursor] == bTypes[parenType][1]) {
            locBrackets.push(Cursor);
            foundParenIdx = 1;
            break;
         }
      }
   }

   // current cursor char is not an open bracket, and there is a previous char
   // to check
   if (foundParenIdx == -1 && Cursor > 0) {
      // check previously typed char for being a closing bracket
      --Cursor;
      // check against each bracket type
      parenType = 0;

      for (; parenType < numBrackets; parenType++) {
         // if current char is equal to closing bracket, push onto stack
         if (text[Cursor] == bTypes[parenType][1]) {
            locBrackets.push(Cursor);
            foundParenIdx = 1;
            break;
         }
      }
   }
   // no bracket found on either current or previous char, return.
   if (foundParenIdx == -1) {
      return;
   }

   // terate through remaining letters until find a matching closing bracket
   // if another open bracket of the same type is found, push onto stack
   // and pop on next closing bracket match
   int direction = 1;

   if (foundParenIdx == 1) {
      direction = -1;
   }

   size_t lenLine = input.length();
   // direction == -1: Cursor - 1 to front.
   size_t scanBegin = (Cursor > 0) ? Cursor - 1 : 0;
   size_t scanLast = 0;
   if (direction == 1) {
      // direction == 1: Cursor + 1 to end.
      scanBegin = Cursor + 1;
      scanLast = lenLine - 1;
      if (scanBegin > scanLast) return;
   }
   for (size_t i = scanBegin; true /*avoid "unsigned >= 0" condition*/; i += direction) {
      // if current char is equal to another opening bracket, push onto stack
      if (text[i] == bTypes[parenType][foundParenIdx]) {
         // push index of bracket
         locBrackets.push(i);
      }
      // if current char is equal to closing bracket
      else if (text[i] == bTypes[parenType][1 - foundParenIdx]) {
         // pop previous opening bracket off stack
         locBrackets.pop();
         // if previous opening was the last entry and we are at the cursor, then highlight match
         if (locBrackets.empty()) {
            ExtendRangeAndSetColor(input, i, kColorBracket, DisplayR);
            ExtendRangeAndSetColor(input, Cursor, kColorBracket, DisplayR);
            fPrevBracketColor = kColorBracket;
            break;
         }
      }
      // loop termination check before possible underflow ("--0")
      if (i == scanLast) break;
   }

   if (!locBrackets.empty()) {
      ExtendRangeAndSetColor(input, Cursor, kColorBadBracket, DisplayR);
      fPrevBracketColor = kColorBadBracket;
   }

} // matchParentheses
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "BZWReader.h"

// implementation-specific system headers
#include <fstream>
#include <sstream>

// implementation-specific bzflag headers
#include "URLManager.h"

// implementation-specific bzfs-specific headers
#include "WorldFileObject.h"
#include "CustomBox.h"
#include "CustomPyramid.h"
#include "CustomGate.h"
#include "CustomLink.h"
#include "CustomBase.h"
#include "CustomWeapon.h"
#include "CustomWorld.h"
#include "CustomZone.h"
#include "CustomTetra.h"
#include "CustomDynamicColor.h"
#include "CustomTextureMatrix.h"
#include "CustomMesh.h"
#include "CustomArc.h"
#include "CustomCone.h"
#include "CustomSphere.h"
#include "CustomWaterLevel.h"

static const std::string urlProtocol("http://");

BZWReader::BZWReader(std::string filename) : location(filename), input(NULL)
{
  errorHandler = new BZWError(location);
  if (filename.substr(0, urlProtocol.size()) != urlProtocol) {
    input = new std::ifstream(filename.c_str(), std::ios::in);
  } else {
    URLManager::instance().getURL(location, httpData);
    input = new std::istringstream(httpData);
  }

  if (input->peek() == EOF) {
    errorHandler->fatalError(std::string("could not find bzflag world file"), 0);
  }
}

BZWReader::~BZWReader()
{
  // clean up
  delete errorHandler;
  delete input;
}

void BZWReader::readToken(char *buffer, int n)
{
  int c = -1;

  // skip whitespace
  while (input->good() && (c = input->get()) != -1 && isspace(c) && c != '\n')
    ;

  // read up to whitespace or n - 1 characters into buffer
  int i = 0;
  if (c != -1 && c != '\n') {
    buffer[i++] = c;
    while (input->good() && i < n - 1 && (c = input->get()) != -1 && !isspace(c))
      buffer[i++] = (char)c;
  }

  // terminate string
  buffer[i] = 0;

  // put back last character we didn't use
  if (c != -1 && isspace(c))
    input->putback(c);
}

bool BZWReader::readWorldStream(std::vector<WorldFileObject*>& wlist)
{
  int line = 1;
  char buffer[1024];
  WorldFileObject *object    = NULL;
  WorldFileObject *newObject = NULL;
  WorldFileObject * const fakeObject = (WorldFileObject*)((char*)NULL + 1); // for options

  bool gotWorld = false;

  while (!input->eof() && !input->fail() && input->good())
  {
    // watch out for starting a new object when one is already in progress
    if (newObject) {
      if (object) {
	errorHandler->warning(std::string("discarding incomplete object"), line);
	if (object != fakeObject)
	  delete object;
      }
      object = newObject;
      newObject = NULL;
    }

    // read first token but do not skip newlines
    readToken(buffer, sizeof(buffer));
    if (strcmp(buffer, "") == 0) {
      // ignore blank line
    } else if (buffer[0] == '#') {
      // ignore comment
    } else if (strcasecmp(buffer, "end") == 0) {
      if (object) {
        if (object != fakeObject) {
	  wlist.push_back(object);
	}
	object = NULL;
      } else {
	errorHandler->fatalError(std::string("unexpected \"end\" token"), line);
	return false;
      }
    } else if (strcasecmp(buffer, "box") == 0) {
      newObject = new CustomBox;
    } else if (strcasecmp(buffer, "pyramid") == 0) {
      newObject = new CustomPyramid();
    } else if (strcasecmp(buffer, "tetra") == 0) {
      newObject = new CustomTetra();
    } else if (strcasecmp(buffer, "teleporter") == 0) {
      newObject = new CustomGate();
    } else if (strcasecmp(buffer, "link") == 0) {
      newObject = new CustomLink();
    } else if (strcasecmp(buffer, "base") == 0) {
      newObject = new CustomBase;
    } else if (strcasecmp(buffer, "mesh") == 0) {
      newObject = new CustomMesh;
    } else if (strcasecmp(buffer, "arc") == 0) {
      newObject = new CustomArc;
    } else if (strcasecmp(buffer, "cone") == 0) {
      newObject = new CustomCone;
    } else if (strcasecmp(buffer, "sphere") == 0) {
      newObject = new CustomSphere;
    } else if (strcasecmp(buffer, "weapon") == 0) {
      newObject = new CustomWeapon;
    } else if (strcasecmp(buffer, "zone") == 0) {
      newObject = new CustomZone;
    } else if (strcasecmp(buffer, "world") == 0) {
      if (!gotWorld) {
	newObject = new CustomWorld();
	gotWorld = true;
      } else {
	errorHandler->warning(std::string("multiple \"world\" sections found"), line);
      }
    } else if (strcasecmp(buffer, "waterLevel") == 0) {
      newObject = new CustomWaterLevel;
    } else if (strcasecmp(buffer, "dynamicColor") == 0) {
      newObject = new CustomDynamicColor;
    } else if (strcasecmp(buffer, "textureMatrix") == 0) {
      newObject = new CustomTextureMatrix;
    } else if (strcasecmp(buffer, "options") == 0) {
      newObject = fakeObject;
    } else if (object) {
      if (object != fakeObject) {
        if (!object->read(buffer, *input)) {
	  // unknown token
	  errorHandler->warning(std::string("unknown object parameter \"") + std::string(buffer) + std::string("\" - skipping"), line);
	  // delete object;
	  // return false;
	}
      }
    } else { // filling the current object
      // unknown token
      errorHandler->warning(std::string("invalid object type \"") + std::string(buffer) + std::string("\" - skipping"), line);
      if (object != fakeObject)
        delete object;
     // return false;
    }

    // discard remainder of line
    while (input->good() && input->peek() != '\n')
      input->get(buffer, sizeof(buffer));
    input->getline(buffer, sizeof(buffer));
    ++line;
  }

  if (object) {
    errorHandler->fatalError(std::string("missing \"end\" parameter"), line);
    if (object != fakeObject)
      delete object;
    return false;
  }

  return true;
}

WorldInfo* BZWReader::defineWorldFromFile()
{
  // make sure input is valid
  if (input->peek() == EOF) {
    errorHandler->fatalError(std::string("unexpected EOF"), 0);
    return NULL;
  }

  // create world object
  WorldInfo *world = new WorldInfo;
  if (!world) {
    errorHandler->fatalError(std::string("WorldInfo failed to initialize"), 0);
    return NULL;
  }

  // read file
  std::vector<WorldFileObject*> list;
  if (!readWorldStream(list)) {
    emptyWorldFileObjectList(list);
    errorHandler->fatalError(std::string("world file failed to load."), 0);
    delete world;
    return NULL;
  }

  // make walls
  float wallHeight = BZDB.eval(StateDatabase::BZDB_WALLHEIGHT);
  float worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  world->addWall(0.0f, 0.5f * worldSize, 0.0f, 1.5f * M_PI, 0.5f * worldSize, wallHeight);
  world->addWall(0.5f * worldSize, 0.0f, 0.0f, M_PI, 0.5f * worldSize, wallHeight);
  world->addWall(0.0f, -0.5f * worldSize, 0.0f, 0.5f * M_PI, 0.5f * worldSize, wallHeight);
  world->addWall(-0.5f * worldSize, 0.0f, 0.0f, 0.0f, 0.5f * worldSize, wallHeight);

  // add objects
  const int n = list.size();
  for (int i = 0; i < n; ++i)
    list[i]->write(world);

  // clean up
  emptyWorldFileObjectList(list);
  world->finishWorld();
  return world;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>Adding ftp: and file: urls<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "BZWReader.h"

// implementation-specific system headers
#include <fstream>
#include <sstream>

// implementation-specific bzflag headers
#include "URLManager.h"

// implementation-specific bzfs-specific headers
#include "WorldFileObject.h"
#include "CustomBox.h"
#include "CustomPyramid.h"
#include "CustomGate.h"
#include "CustomLink.h"
#include "CustomBase.h"
#include "CustomWeapon.h"
#include "CustomWorld.h"
#include "CustomZone.h"
#include "CustomTetra.h"
#include "CustomDynamicColor.h"
#include "CustomTextureMatrix.h"
#include "CustomMesh.h"
#include "CustomArc.h"
#include "CustomCone.h"
#include "CustomSphere.h"
#include "CustomWaterLevel.h"

BZWReader::BZWReader(std::string filename) : location(filename), input(NULL)
{
  static const std::string httpProtocol("http://");
  static const std::string ftpProtocol("ftp://");
  static const std::string fileProtocol("file:/");

  errorHandler = new BZWError(location);

  if ((filename.substr(0, httpProtocol.size()) == httpProtocol)
      || (filename.substr(0, ftpProtocol.size()) == ftpProtocol)
      || (filename.substr(0, fileProtocol.size()) == fileProtocol)) {
    URLManager::instance().getURL(location, httpData);
    input = new std::istringstream(httpData);
  } else {
    input = new std::ifstream(filename.c_str(), std::ios::in);
  }

  if (input->peek() == EOF) {
    errorHandler->fatalError(std::string("could not find bzflag world file"), 0);
  }
}

BZWReader::~BZWReader()
{
  // clean up
  delete errorHandler;
  delete input;
}

void BZWReader::readToken(char *buffer, int n)
{
  int c = -1;

  // skip whitespace
  while (input->good() && (c = input->get()) != -1 && isspace(c) && c != '\n')
    ;

  // read up to whitespace or n - 1 characters into buffer
  int i = 0;
  if (c != -1 && c != '\n') {
    buffer[i++] = c;
    while (input->good() && i < n - 1 && (c = input->get()) != -1 && !isspace(c))
      buffer[i++] = (char)c;
  }

  // terminate string
  buffer[i] = 0;

  // put back last character we didn't use
  if (c != -1 && isspace(c))
    input->putback(c);
}

bool BZWReader::readWorldStream(std::vector<WorldFileObject*>& wlist)
{
  int line = 1;
  char buffer[1024];
  WorldFileObject *object    = NULL;
  WorldFileObject *newObject = NULL;
  WorldFileObject * const fakeObject = (WorldFileObject*)((char*)NULL + 1); // for options

  bool gotWorld = false;

  while (!input->eof() && !input->fail() && input->good())
  {
    // watch out for starting a new object when one is already in progress
    if (newObject) {
      if (object) {
	errorHandler->warning(std::string("discarding incomplete object"), line);
	if (object != fakeObject)
	  delete object;
      }
      object = newObject;
      newObject = NULL;
    }

    // read first token but do not skip newlines
    readToken(buffer, sizeof(buffer));
    if (strcmp(buffer, "") == 0) {
      // ignore blank line
    } else if (buffer[0] == '#') {
      // ignore comment
    } else if (strcasecmp(buffer, "end") == 0) {
      if (object) {
        if (object != fakeObject) {
	  wlist.push_back(object);
	}
	object = NULL;
      } else {
	errorHandler->fatalError(std::string("unexpected \"end\" token"), line);
	return false;
      }
    } else if (strcasecmp(buffer, "box") == 0) {
      newObject = new CustomBox;
    } else if (strcasecmp(buffer, "pyramid") == 0) {
      newObject = new CustomPyramid();
    } else if (strcasecmp(buffer, "tetra") == 0) {
      newObject = new CustomTetra();
    } else if (strcasecmp(buffer, "teleporter") == 0) {
      newObject = new CustomGate();
    } else if (strcasecmp(buffer, "link") == 0) {
      newObject = new CustomLink();
    } else if (strcasecmp(buffer, "base") == 0) {
      newObject = new CustomBase;
    } else if (strcasecmp(buffer, "mesh") == 0) {
      newObject = new CustomMesh;
    } else if (strcasecmp(buffer, "arc") == 0) {
      newObject = new CustomArc;
    } else if (strcasecmp(buffer, "cone") == 0) {
      newObject = new CustomCone;
    } else if (strcasecmp(buffer, "sphere") == 0) {
      newObject = new CustomSphere;
    } else if (strcasecmp(buffer, "weapon") == 0) {
      newObject = new CustomWeapon;
    } else if (strcasecmp(buffer, "zone") == 0) {
      newObject = new CustomZone;
    } else if (strcasecmp(buffer, "world") == 0) {
      if (!gotWorld) {
	newObject = new CustomWorld();
	gotWorld = true;
      } else {
	errorHandler->warning(std::string("multiple \"world\" sections found"), line);
      }
    } else if (strcasecmp(buffer, "waterLevel") == 0) {
      newObject = new CustomWaterLevel;
    } else if (strcasecmp(buffer, "dynamicColor") == 0) {
      newObject = new CustomDynamicColor;
    } else if (strcasecmp(buffer, "textureMatrix") == 0) {
      newObject = new CustomTextureMatrix;
    } else if (strcasecmp(buffer, "options") == 0) {
      newObject = fakeObject;
    } else if (object) {
      if (object != fakeObject) {
        if (!object->read(buffer, *input)) {
	  // unknown token
	  errorHandler->warning(std::string("unknown object parameter \"") + std::string(buffer) + std::string("\" - skipping"), line);
	  // delete object;
	  // return false;
	}
      }
    } else { // filling the current object
      // unknown token
      errorHandler->warning(std::string("invalid object type \"") + std::string(buffer) + std::string("\" - skipping"), line);
      if (object != fakeObject)
        delete object;
     // return false;
    }

    // discard remainder of line
    while (input->good() && input->peek() != '\n')
      input->get(buffer, sizeof(buffer));
    input->getline(buffer, sizeof(buffer));
    ++line;
  }

  if (object) {
    errorHandler->fatalError(std::string("missing \"end\" parameter"), line);
    if (object != fakeObject)
      delete object;
    return false;
  }

  return true;
}

WorldInfo* BZWReader::defineWorldFromFile()
{
  // make sure input is valid
  if (input->peek() == EOF) {
    errorHandler->fatalError(std::string("unexpected EOF"), 0);
    return NULL;
  }

  // create world object
  WorldInfo *world = new WorldInfo;
  if (!world) {
    errorHandler->fatalError(std::string("WorldInfo failed to initialize"), 0);
    return NULL;
  }

  // read file
  std::vector<WorldFileObject*> list;
  if (!readWorldStream(list)) {
    emptyWorldFileObjectList(list);
    errorHandler->fatalError(std::string("world file failed to load."), 0);
    delete world;
    return NULL;
  }

  // make walls
  float wallHeight = BZDB.eval(StateDatabase::BZDB_WALLHEIGHT);
  float worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  world->addWall(0.0f, 0.5f * worldSize, 0.0f, 1.5f * M_PI, 0.5f * worldSize, wallHeight);
  world->addWall(0.5f * worldSize, 0.0f, 0.0f, M_PI, 0.5f * worldSize, wallHeight);
  world->addWall(0.0f, -0.5f * worldSize, 0.0f, 0.5f * M_PI, 0.5f * worldSize, wallHeight);
  world->addWall(-0.5f * worldSize, 0.0f, 0.0f, 0.0f, 0.5f * worldSize, wallHeight);

  // add objects
  const int n = list.size();
  for (int i = 0; i < n; ++i)
    list[i]->write(world);

  // clean up
  emptyWorldFileObjectList(list);
  world->finishWorld();
  return world;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>/*
  QtCurve KWin window decoration
  Copyright (C) 2007 Craig Drummond <Craig.Drummond@lycos.co.uk>

  based on the window decoration "Plastik":
  Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>

  based on the window decoration "Web":
  Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
 */

#include <klocale.h>
#include <QBitmap>
#include <QDateTime>
#include <QFontMetrics>
#include <QImage>
#include <QLabel>
#include <QLayout>
#include <QPainter>
#include <QPixmap>
#include <QStyleOptionTitleBar>
#include <QStyle>
#include <qdesktopwidget.h>
#include "qtcurvehandler.h"
#include "qtcurveclient.h"
#include "qtcurvebutton.h"
#define QTC_KWIN
#include "common.h"

namespace KWinQtCurve
{

QtCurveClient::QtCurveClient(KDecorationBridge *bridge, KDecorationFactory *factory)
             : KCommonDecoration (bridge, factory),
               itsTitleFont(QFont())
{
}

QString QtCurveClient::visibleName() const
{
    return i18n("QtCurve");
}

bool QtCurveClient::decorationBehaviour(DecorationBehaviour behaviour) const
{
    switch (behaviour)
    {
        case DB_MenuClose:
            return true; // Handler()->menuClose();
        case DB_WindowMask:
            return true;
        default:
            return KCommonDecoration::decorationBehaviour(behaviour);
    }
}

int QtCurveClient::layoutMetric(LayoutMetric lm, bool respectWindowState,
                                const KCommonDecorationButton *btn) const
{
    bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows();

    switch (lm)
    {
        case LM_BorderLeft:
        case LM_BorderRight:
        case LM_BorderBottom:
            return respectWindowState && maximized ? 0 : Handler()->borderSize();
        case LM_TitleEdgeTop:
            return respectWindowState && maximized ? 0 : 3;
        case LM_TitleEdgeBottom:
            return /*respectWindowState && maximized ? 1 : */ 3;
        case LM_TitleEdgeLeft:
        case LM_TitleEdgeRight:
            return respectWindowState && maximized ? 0 : 3;
        case LM_TitleBorderLeft:
        case LM_TitleBorderRight:
            return 5;
        case LM_ButtonWidth:
        case LM_ButtonHeight:
        case LM_TitleHeight:
            return respectWindowState && isToolWindow() ? Handler()->titleHeightTool() : Handler()->titleHeight();
        case LM_ButtonSpacing:
            return 1;
        case LM_ButtonMarginTop:
            return 0;
        default:
            return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
    }
}

KCommonDecorationButton *QtCurveClient::createButton(ButtonType type)
{
    switch (type)
    {
        case MenuButton:
            return new QtCurveButton(MenuButton, this);
        case OnAllDesktopsButton:
            return new QtCurveButton(OnAllDesktopsButton, this);
        case HelpButton:
            return new QtCurveButton(HelpButton, this);
        case MinButton:
            return new QtCurveButton(MinButton, this);
        case MaxButton:
            return new QtCurveButton(MaxButton, this);
        case CloseButton:
            return new QtCurveButton(CloseButton, this);
        case AboveButton:
            return new QtCurveButton(AboveButton, this);
        case BelowButton:
            return new QtCurveButton(BelowButton, this);
        case ShadeButton:
            return new QtCurveButton(ShadeButton, this);
        default:
            return 0;
    }
}

void QtCurveClient::init()
{
    itsTitleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();

    KCommonDecoration::init();
}

QRegion QtCurveClient::cornerShape(WindowCorner corner)
{
    int round=Handler()->wStyle()->pixelMetric((QStyle::PixelMetric)QtC_Round, NULL, NULL);

    if(ROUND_NONE==round)
        return QRegion();

    int w(widget()->width()),
        h(widget()->height());

    switch (corner)
    {
        case WC_TopLeft:
            return layoutMetric(LM_TitleEdgeLeft) > 0
                ? ROUND_FULL==round
                    ? QRegion(0, 0, 1, 2) + QRegion(1, 0, 1, 1)
                    : QRegion(0, 0, 1, 1)
                : QRegion();
        case WC_TopRight:
            return layoutMetric(LM_TitleEdgeRight) > 0
                ? ROUND_FULL==round
                    ? QRegion(w-1, 0, 1, 2) + QRegion(w-2, 0, 1, 1)
                    : QRegion(w-1, 0, 1, 1)
                : QRegion();
        case WC_BottomLeft:
            return layoutMetric(LM_BorderBottom) > 0
                ? QRegion(0, h-1, 1, 1)
                : QRegion();
        case WC_BottomRight:
            return layoutMetric(LM_BorderBottom) > 0
                ? QRegion(w-1, h-1, 1, 1)
                : QRegion();
        default:
            return QRegion();
    }
}

void QtCurveClient::drawBtnBgnd(QPainter *p, const QRect &r, bool active)
{
    QRect                br(r);
    QStyleOptionTitleBar opt;

    br.adjust(-3, -3, 3, 3);
    opt.rect=br;

    opt.state=QStyle::State_Horizontal|QStyle::State_Enabled|QStyle::State_Raised|
             (active ? QStyle::State_Active : QStyle::State_None);
    opt.titleBarState=(active ? QStyle::State_Active : QStyle::State_None);
    Handler()->wStyle()->drawComplexControl(QStyle::CC_TitleBar, &opt, p, widget());
}

void QtCurveClient::paintEvent(QPaintEvent *e)
{
    QPainter             painter(widget());
    QRect                r(widget()->rect());
    QStyleOptionTitleBar opt;
    bool                 active(isActive());
    const int            titleHeight(layoutMetric(LM_TitleHeight)),
                         titleEdgeTop(layoutMetric(LM_TitleEdgeTop)),
                         titleEdgeBottom(layoutMetric(LM_TitleEdgeBottom)),
                         titleEdgeLeft(layoutMetric(LM_TitleEdgeLeft)),
                         titleEdgeRight(layoutMetric(LM_TitleEdgeRight)),
                         borderWidth(layoutMetric(LM_BorderLeft));
    int                  rectX, rectY, rectX2, rectY2;

    r.getCoords(&rectX, &rectY, &rectX2, &rectY2);

    const int titleEdgeBottomBottom = rectY+titleEdgeTop+titleHeight+titleEdgeBottom-1;
    QRect     titleRect(rectX+titleEdgeLeft+buttonsLeftWidth(), rectY+titleEdgeTop,
                        rectX2-titleEdgeRight-buttonsRightWidth()-(rectX+titleEdgeLeft+buttonsLeftWidth()),
                        titleEdgeBottomBottom-(rectY+titleEdgeTop));

    painter.setClipRegion(e->region());

    if(borderWidth)
    {
        painter.fillRect(rectX, rectY, rectX+borderWidth, rectY2, widget()->palette().background());
        painter.fillRect(rectX2-borderWidth, rectY, rectX2, rectY2, widget()->palette().background());
        painter.fillRect(rectX, rectY2-borderWidth, rectX2, rectY2, widget()->palette().background());
    }

    opt.init(widget());

    if(MaximizeFull==maximizeMode())
        r.adjust(-3, -3, 3, 0);
    opt.rect=QRect(r.x(), r.y()+4, r.width(), r.height()-4);
    opt.state=QStyle::State_Horizontal|QStyle::State_Enabled|QStyle::State_Raised|
             (active ? QStyle::State_Active : QStyle::State_None);

    Handler()->wStyle()->drawPrimitive(QStyle::PE_FrameWindow, &opt, &painter, widget());

    opt.rect=QRect(r.x(), r.y(), r.width(), titleHeight+titleEdgeTop+titleEdgeBottom+
                                            (MaximizeFull==maximizeMode() ? 3 : 0));
    opt.titleBarState=(active ? QStyle::State_Active : QStyle::State_None);
    Handler()->wStyle()->drawComplexControl(QStyle::CC_TitleBar, &opt, &painter, widget());

    itsCaptionRect = captionRect(); // also update itsCaptionRect!

    if(!caption().isEmpty())
    {
        const int maxCaptionLength = 300; // truncate captions longer than this!
        QString c(caption());
        if (c.length() > maxCaptionLength)
        {
            c.truncate(maxCaptionLength);
            c.append(" [...]");
        }

        QFontMetrics fm(itsTitleFont);
        int          captionHeight(fm.height());

        painter.setFont(itsTitleFont);
        QPoint tp(itsCaptionRect.x(), itsCaptionRect.y()+captionHeight-3);

        painter.setPen(shadowColor(KDecoration::options()->color(KDecoration::ColorFont, active)));
        painter.drawText(tp+QPoint(1, 1), c);
        painter.setPen(KDecoration::options()->color(KDecoration::ColorFont, active));
        painter.drawText(tp, c);
    }
    painter.setClipping(false);
    painter.end();
}

QRect QtCurveClient::captionRect() const
{
    QRect r = widget()->rect();

    const int titleHeight = layoutMetric(LM_TitleHeight),
              titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom),
              titleEdgeTop = layoutMetric(LM_TitleEdgeTop),
              titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft),
              marginLeft = layoutMetric(LM_TitleBorderLeft),
              marginRight = layoutMetric(LM_TitleBorderRight),
              titleLeft = r.left() + titleEdgeLeft + buttonsLeftWidth() + marginLeft,
              titleWidth = r.width() -
                           titleEdgeLeft - layoutMetric(LM_TitleEdgeRight) -
                           buttonsLeftWidth() - buttonsRightWidth() -
                           marginLeft - marginRight;

    return QRect(titleLeft, r.top()+titleEdgeTop, titleWidth, titleHeight+titleEdgeBottom);
}

void QtCurveClient::updateCaption()
{
    QRect oldCaptionRect(itsCaptionRect);

    itsCaptionRect = QtCurveClient::captionRect();

    if (oldCaptionRect.isValid() && itsCaptionRect.isValid())
        widget()->update(oldCaptionRect|itsCaptionRect);
    else
        widget()->update();
}

void QtCurveClient::reset(unsigned long changed)
{
    if (changed & SettingColors)
    {
        // repaint the whole thing
        widget()->update();
        updateButtons();
    }
    else if (changed & SettingFont)
    {
        // font has changed -- update title height and font
        itsTitleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();

        updateLayout();
        widget()->update();
    }

    KCommonDecoration::reset(changed);
}

}
<commit_msg>Fix flicker caused by left/right/bottom borders, and by PE_WindowFrame.<commit_after>/*
  QtCurve KWin window decoration
  Copyright (C) 2007 Craig Drummond <Craig.Drummond@lycos.co.uk>

  based on the window decoration "Plastik":
  Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>

  based on the window decoration "Web":
  Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
 */

#include <klocale.h>
#include <QBitmap>
#include <QDateTime>
#include <QFontMetrics>
#include <QImage>
#include <QLabel>
#include <QLayout>
#include <QPainter>
#include <QPixmap>
#include <QStyleOptionTitleBar>
#include <QStyle>
#include <qdesktopwidget.h>
#include "qtcurvehandler.h"
#include "qtcurveclient.h"
#include "qtcurvebutton.h"
#define QTC_KWIN
#include "common.h"

namespace KWinQtCurve
{

QtCurveClient::QtCurveClient(KDecorationBridge *bridge, KDecorationFactory *factory)
             : KCommonDecoration (bridge, factory),
               itsTitleFont(QFont())
{
}

QString QtCurveClient::visibleName() const
{
    return i18n("QtCurve");
}

bool QtCurveClient::decorationBehaviour(DecorationBehaviour behaviour) const
{
    switch (behaviour)
    {
        case DB_MenuClose:
            return true; // Handler()->menuClose();
        case DB_WindowMask:
            return true;
        default:
            return KCommonDecoration::decorationBehaviour(behaviour);
    }
}

int QtCurveClient::layoutMetric(LayoutMetric lm, bool respectWindowState,
                                const KCommonDecorationButton *btn) const
{
    bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows();

    switch (lm)
    {
        case LM_BorderLeft:
        case LM_BorderRight:
        case LM_BorderBottom:
            return respectWindowState && maximized ? 0 : Handler()->borderSize();
        case LM_TitleEdgeTop:
            return respectWindowState && maximized ? 0 : 3;
        case LM_TitleEdgeBottom:
            return /*respectWindowState && maximized ? 1 : */ 3;
        case LM_TitleEdgeLeft:
        case LM_TitleEdgeRight:
            return respectWindowState && maximized ? 0 : 3;
        case LM_TitleBorderLeft:
        case LM_TitleBorderRight:
            return 5;
        case LM_ButtonWidth:
        case LM_ButtonHeight:
        case LM_TitleHeight:
            return respectWindowState && isToolWindow() ? Handler()->titleHeightTool() : Handler()->titleHeight();
        case LM_ButtonSpacing:
            return 1;
        case LM_ButtonMarginTop:
            return 0;
        default:
            return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
    }
}

KCommonDecorationButton *QtCurveClient::createButton(ButtonType type)
{
    switch (type)
    {
        case MenuButton:
            return new QtCurveButton(MenuButton, this);
        case OnAllDesktopsButton:
            return new QtCurveButton(OnAllDesktopsButton, this);
        case HelpButton:
            return new QtCurveButton(HelpButton, this);
        case MinButton:
            return new QtCurveButton(MinButton, this);
        case MaxButton:
            return new QtCurveButton(MaxButton, this);
        case CloseButton:
            return new QtCurveButton(CloseButton, this);
        case AboveButton:
            return new QtCurveButton(AboveButton, this);
        case BelowButton:
            return new QtCurveButton(BelowButton, this);
        case ShadeButton:
            return new QtCurveButton(ShadeButton, this);
        default:
            return 0;
    }
}

void QtCurveClient::init()
{
    itsTitleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();

    KCommonDecoration::init();
}

QRegion QtCurveClient::cornerShape(WindowCorner corner)
{
    int round=Handler()->wStyle()->pixelMetric((QStyle::PixelMetric)QtC_Round, NULL, NULL);

    if(ROUND_NONE==round)
        return QRegion();

    int w(widget()->width()),
        h(widget()->height());

    switch (corner)
    {
        case WC_TopLeft:
            return layoutMetric(LM_TitleEdgeLeft) > 0
                ? ROUND_FULL==round
                    ? QRegion(0, 0, 1, 2) + QRegion(1, 0, 1, 1)
                    : QRegion(0, 0, 1, 1)
                : QRegion();
        case WC_TopRight:
            return layoutMetric(LM_TitleEdgeRight) > 0
                ? ROUND_FULL==round
                    ? QRegion(w-1, 0, 1, 2) + QRegion(w-2, 0, 1, 1)
                    : QRegion(w-1, 0, 1, 1)
                : QRegion();
        case WC_BottomLeft:
            return layoutMetric(LM_BorderBottom) > 0
                ? QRegion(0, h-1, 1, 1)
                : QRegion();
        case WC_BottomRight:
            return layoutMetric(LM_BorderBottom) > 0
                ? QRegion(w-1, h-1, 1, 1)
                : QRegion();
        default:
            return QRegion();
    }
}

void QtCurveClient::drawBtnBgnd(QPainter *p, const QRect &r, bool active)
{
    QRect                br(r);
    QStyleOptionTitleBar opt;

    br.adjust(-3, -3, 3, 3);
    opt.rect=br;

    opt.state=QStyle::State_Horizontal|QStyle::State_Enabled|QStyle::State_Raised|
             (active ? QStyle::State_Active : QStyle::State_None);
    opt.titleBarState=(active ? QStyle::State_Active : QStyle::State_None);
    Handler()->wStyle()->drawComplexControl(QStyle::CC_TitleBar, &opt, p, widget());
}

void QtCurveClient::paintEvent(QPaintEvent *e)
{
    QPainter             painter(widget());
    QRect                r(widget()->rect());
    QStyleOptionTitleBar opt;
    bool                 active(isActive());
    const int            titleHeight(layoutMetric(LM_TitleHeight)),
                         titleEdgeTop(layoutMetric(LM_TitleEdgeTop)),
                         titleEdgeBottom(layoutMetric(LM_TitleEdgeBottom)),
                         titleEdgeLeft(layoutMetric(LM_TitleEdgeLeft)),
                         titleEdgeRight(layoutMetric(LM_TitleEdgeRight)),
                         borderWidth(layoutMetric(LM_BorderLeft)),
                         titleBarHeight(titleHeight+titleEdgeTop+titleEdgeBottom+
                                        (MaximizeFull==maximizeMode() ? 3 : 0));
    int                  rectX, rectY, rectX2, rectY2;

    r.getCoords(&rectX, &rectY, &rectX2, &rectY2);

    const int titleEdgeBottomBottom(rectY+titleEdgeTop+titleHeight+titleEdgeBottom);
    QRect     titleRect(rectX+titleEdgeLeft+buttonsLeftWidth(), rectY+titleEdgeTop,
                        rectX2-titleEdgeRight-buttonsRightWidth()-(rectX+titleEdgeLeft+buttonsLeftWidth()),
                        titleEdgeBottomBottom-(rectY+titleEdgeTop));

    painter.setClipRegion(e->region());

    if(borderWidth)
    {
        painter.fillRect(rectX+2, titleEdgeBottomBottom, borderWidth-2,
                        (rectY2-titleEdgeBottomBottom)-2,
                         widget()->palette().background());
        painter.fillRect(rectX2-borderWidth, titleEdgeBottomBottom, borderWidth-1,
                         (rectY2-titleEdgeBottomBottom)-2, widget()->palette().background());
        painter.fillRect(rectX+2, rectY2-borderWidth, (rectX2-rectX)-3, borderWidth-1,
                         widget()->palette().background());
    }

    opt.init(widget());

    if(MaximizeFull==maximizeMode())
        r.adjust(-3, -3, 3, 0);
    opt.rect=QRect(r.x(), r.y()+4, r.width(), r.height()-4);
    opt.state=QStyle::State_Horizontal|QStyle::State_Enabled|QStyle::State_Raised|
             (active ? QStyle::State_Active : QStyle::State_None);

    painter.setClipRect(QRect(rectX, titleEdgeBottomBottom, (rectX2-rectX)+1, (rectY2-titleEdgeBottomBottom)+1));
    Handler()->wStyle()->drawPrimitive(QStyle::PE_FrameWindow, &opt, &painter, widget());
    painter.setClipping(false);

    opt.rect=QRect(r.x(), r.y(), r.width(), titleBarHeight);
    opt.titleBarState=(active ? QStyle::State_Active : QStyle::State_None);
    Handler()->wStyle()->drawComplexControl(QStyle::CC_TitleBar, &opt, &painter, widget());

    itsCaptionRect = captionRect(); // also update itsCaptionRect!

    if(!caption().isEmpty())
    {
        const int maxCaptionLength = 300; // truncate captions longer than this!
        QString c(caption());
        if (c.length() > maxCaptionLength)
        {
            c.truncate(maxCaptionLength);
            c.append(" [...]");
        }

        QFontMetrics fm(itsTitleFont);
        int          captionHeight(fm.height());

        painter.setFont(itsTitleFont);
        QPoint tp(itsCaptionRect.x(), itsCaptionRect.y()+captionHeight-3);

        painter.setPen(shadowColor(KDecoration::options()->color(KDecoration::ColorFont, active)));
        painter.drawText(tp+QPoint(1, 1), c);
        painter.setPen(KDecoration::options()->color(KDecoration::ColorFont, active));
        painter.drawText(tp, c);
    }
    painter.setClipping(false);
    painter.end();
}

QRect QtCurveClient::captionRect() const
{
    QRect     r(widget()->rect());
    const int titleHeight(layoutMetric(LM_TitleHeight)),
              titleEdgeBottom(layoutMetric(LM_TitleEdgeBottom)),
              titleEdgeTop(layoutMetric(LM_TitleEdgeTop)),
              titleEdgeLeft(layoutMetric(LM_TitleEdgeLeft)),
              marginLeft(layoutMetric(LM_TitleBorderLeft)),
              marginRight(layoutMetric(LM_TitleBorderRight)),
              titleLeft(r.left() + titleEdgeLeft + buttonsLeftWidth() + marginLeft),
              titleWidth(r.width() -
                           titleEdgeLeft - layoutMetric(LM_TitleEdgeRight) -
                           buttonsLeftWidth() - buttonsRightWidth() -
                           marginLeft - marginRight);

    return QRect(titleLeft, r.top()+titleEdgeTop, titleWidth, titleHeight+titleEdgeBottom);
}

void QtCurveClient::updateCaption()
{
    QRect oldCaptionRect(itsCaptionRect);

    itsCaptionRect = QtCurveClient::captionRect();

    if (oldCaptionRect.isValid() && itsCaptionRect.isValid())
        widget()->update(oldCaptionRect|itsCaptionRect);
    else
        widget()->update();
}

void QtCurveClient::reset(unsigned long changed)
{
    if (changed & SettingColors)
    {
        // repaint the whole thing
        widget()->update();
        updateButtons();
    }
    else if (changed & SettingFont)
    {
        // font has changed -- update title height and font
        itsTitleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();

        updateLayout();
        widget()->update();
    }

    KCommonDecoration::reset(changed);
}

}
<|endoftext|>