<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Nibbler.h>
#include <Lexer.h>
#include <Duration.h>
#include <text.h>

#define DAY    86400
#define HOUR    3600
#define MINUTE    60
#define SECOND     1

static struct
{
  std::string unit;
  int seconds;
  bool standalone;
} durations[] =
{
  // These are sorted by first character, then length, so that Nibbler::getOneOf
  // returns a maximal match.
  {"annual",     365 * DAY,    true},
  {"biannual",   730 * DAY,    true},
  {"bimonthly",   61 * DAY,    true},
  {"biweekly",    14 * DAY,    true},
  {"biyearly",   730 * DAY,    true},
  {"daily",        1 * DAY,    true},
  {"days",         1 * DAY,    false},
  {"day",          1 * DAY,    true},
  {"d",            1 * DAY,    false},
  {"fortnight",   14 * DAY,    true},
  {"hours",        1 * HOUR,   false},
  {"hour",         1 * HOUR,   true},
  {"hrs",          1 * HOUR,   false},
  {"hr",           1 * HOUR,   true},
  {"h",            1 * HOUR,   false},
  {"minutes",      1 * MINUTE, false},
  {"minute",       1 * MINUTE, true},
  {"mins",         1 * MINUTE, false},
  {"min",          1 * MINUTE, true},
  {"monthly",     30 * DAY,    true},
  {"months",      30 * DAY,    false},
  {"month",       30 * DAY,    true},
  {"mnths",       30 * DAY,    false},
  {"mths",        30 * DAY,    false},
  {"mth",         30 * DAY,    true},
  {"mos",         30 * DAY,    false},
  {"mo",          30 * DAY,    true},
  {"m",           30 * DAY,    false},
  {"quarterly",   91 * DAY,    true},
  {"quarters",    91 * DAY,    false},
  {"quarter",     91 * DAY,    true},
  {"qrtrs",       91 * DAY,    false},
  {"qrtr",        91 * DAY,    true},
  {"qtrs",        91 * DAY,    false},
  {"qtr",         91 * DAY,    true},
  {"q",           91 * DAY,    false},
  {"semiannual", 183 * DAY,    true},
  {"sennight",    14 * DAY,    false},
  {"seconds",      1 * SECOND, false},
  {"second",       1 * SECOND, true},
  {"secs",         1 * SECOND, false},
  {"sec",          1 * SECOND, true},
  {"s",            1 * SECOND, false},
  {"weekdays",     1 * DAY,    true},
  {"weekly",       7 * DAY,    true},
  {"weeks",        7 * DAY,    false},
  {"week",         7 * DAY,    true},
  {"wks",          7 * DAY,    false},
  {"wk",           7 * DAY,    true},
  {"w",            7 * DAY,    false},
  {"yearly",     365 * DAY,    true},
  {"years",      365 * DAY,    false},
  {"year",       365 * DAY,    true},
  {"yrs",        365 * DAY,    false},
  {"yr",         365 * DAY,    true},
  {"y",          365 * DAY,    false},
};

#define NUM_DURATIONS (sizeof (durations) / sizeof (durations[0]))

////////////////////////////////////////////////////////////////////////////////
Duration::Duration ()
: _secs (0)
{
}

////////////////////////////////////////////////////////////////////////////////
Duration::Duration (time_t input)
: _secs (input)
{
}

////////////////////////////////////////////////////////////////////////////////
Duration::Duration (const std::string& input)
: _secs (0)
{
  if (Lexer::isAllDigits (input))
  {
    time_t value = (time_t) strtol (input.c_str (), NULL, 10);
    if (value == 0 || value > 60)
    {
      _secs = value;
      return;
    }
  }

  std::string::size_type idx = 0;
  parse (input, idx);
}

////////////////////////////////////////////////////////////////////////////////
Duration::~Duration ()
{
}

////////////////////////////////////////////////////////////////////////////////
bool Duration::operator< (const Duration& other)
{
  return _secs < other._secs;
}

////////////////////////////////////////////////////////////////////////////////
bool Duration::operator> (const Duration& other)
{
  return _secs > other._secs;
}

////////////////////////////////////////////////////////////////////////////////
Duration& Duration::operator= (const Duration& other)
{
  if (this != &other)
    _secs = other._secs;

  return *this;
}

////////////////////////////////////////////////////////////////////////////////
Duration::operator time_t () const
{
  return _secs;
}

////////////////////////////////////////////////////////////////////////////////
Duration::operator std::string () const
{
  std::stringstream s;
  s << _secs;
  return s.str ();
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::format () const
{
  char formatted[24];
  float days = (float) _secs / 86400.0;

  if (_secs >= 86400 * 365)
    sprintf (formatted, "%.1f year%s",
                        (days / 365),
                        ((int) (float) (days / 365) == 1 ? "" : "s"));
  else if (_secs > 86400 * 84)
    sprintf (formatted, "%1d month%s",
                        (int) (float) (days / 30),
                        ((int) (float) (days / 30) == 1 ? "" : "s"));
  else if (_secs > 86400 * 13)
    sprintf (formatted, "%d week%s",
                        (int) (float) (days / 7.0),
                        ((int) (float) (days / 7.0) == 1 ? "" : "s"));
  else if (_secs >= 86400)
    sprintf (formatted, "%d day%s",
                        (int) days,
                        ((int) days == 1 ? "" : "s"));
  else if (_secs >= 3600)
    sprintf (formatted, "%d hour%s",
                        (int) (float) (_secs / 3600),
                        ((int) (float) (_secs / 3600) == 1 ? "" : "s"));
  else if (_secs >= 60)
    sprintf (formatted, "%d minute%s",
                        (int) (float) (_secs / 60),
                        ((int) (float) (_secs / 60) == 1 ? "" : "s"));
  else if (_secs >= 1)
    sprintf (formatted, "%d second%s",
                        (int) _secs,
                        ((int) _secs == 1 ? "" : "s"));
  else
    strcpy (formatted, "-"); // no i18n

  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatCompact () const
{
  char formatted[24];
  float days = (float) _secs / 86400.0;

       if (_secs >= 86400 * 365) sprintf (formatted, "%.1fy", (days / 365.0));
  else if (_secs >= 86400 * 84)  sprintf (formatted, "%1dmo", (int) (days / 30));
  else if (_secs >= 86400 * 13)  sprintf (formatted, "%dw",   (int) (float) (days / 7.0));
  else if (_secs >= 86400)       sprintf (formatted, "%dd",   (int) days);
  else if (_secs >= 3600)        sprintf (formatted, "%dh",   (int) (_secs / 3600));
  else if (_secs >= 60)          sprintf (formatted, "%dmin", (int) (_secs / 60));
  else if (_secs >= 1)           sprintf (formatted, "%ds",   (int) _secs);
  else                           formatted[0] = '\0';

  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatPrecise () const
{
  char formatted[24];

  int days    = _secs / 86400;
  int hours   = (_secs % 86400) / 3600;
  int minutes = (_secs % 3600) / 60;
  int seconds = _secs % 60;

  if (days > 0) sprintf (formatted, "%dd %d:%02d:%02d", days, hours, minutes, seconds);
  else          sprintf (formatted, "%d:%02d:%02d",     hours, minutes, seconds);

  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatSeconds () const
{
  char formatted[24];
  sprintf (formatted, "%llus", (unsigned long long)_secs);
  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatISO () const
{
  if (_secs)
  {
    time_t t = _secs;
    int seconds = t % 60; t /= 60;
    int minutes = t % 60; t /= 60;
    int hours   = t % 24; t /= 24;
    int days    = t % 30; t /= 30;
    int months  = t % 12; t /= 12;
    int years   = t;

    std::stringstream s;
    s << 'P';
    if (years)  s << years  << 'Y';
    if (months) s << months << 'M';
    if (days)   s << days   << 'D';

    if (hours || minutes || seconds)
    {
      s << 'T';
      if (hours)   s << hours   << 'H';
      if (minutes) s << minutes << 'M';
      if (seconds) s << seconds << 'S';
    }

    return s.str ();
  }
  else
  {
    return "PT0S";
  }
}

////////////////////////////////////////////////////////////////////////////////
bool Duration::parse (const std::string& input, std::string::size_type& start)
{
  auto original_start = start;
  Nibbler n (input.substr (start));

  // Static and so preserved between calls.
  static std::vector <std::string> units;
  if (units.size () == 0)
    for (unsigned int i = 0; i < NUM_DURATIONS; i++)
      units.push_back (durations[i].unit);

  std::string number;
  std::string unit;

  if (n.getOneOf (units, unit))
  {
    if (n.depleted ()                           ||
        Lexer::isWhitespace         (n.next ()) ||
        Lexer::isSingleCharOperator (n.next ()))
    {
      start = original_start + n.cursor ();

      // Linear lookup - should be logarithmic.
      for (unsigned int i = 0; i < NUM_DURATIONS; i++)
      {
        if (durations[i].unit == unit &&
            durations[i].standalone == true)
        {
          _secs = static_cast <int> (durations[i].seconds);
          return true;
        }
      }
    }
  }

  else if (n.getNumber (number) &&
           number.find ('e') == std::string::npos &&
           number.find ('E') == std::string::npos &&
           (number.find ('+') == std::string::npos || number.find ('+') == 0) &&
           (number.find ('-') == std::string::npos || number.find ('-') == 0))
  {
    n.skipWS ();
    if (n.getOneOf (units, unit))
    {
      if (n.depleted ()                           ||
          Lexer::isWhitespace         (n.next ()) ||
          Lexer::isSingleCharOperator (n.next ()))
      {
        start = original_start + n.cursor ();
        double quantity = strtod (number.c_str (), NULL);

        // Linear lookup - should be logarithmic.
        double seconds = 1;
        for (unsigned int i = 0; i < NUM_DURATIONS; i++)
        {
          if (durations[i].unit == unit)
          {
            seconds = durations[i].seconds;
            _secs = static_cast <int> (quantity * static_cast <double> (seconds));
            return true;
          }
        }
      }
    }
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Duration: Addressed problem of UUID/Duration overlap<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Nibbler.h>
#include <Lexer.h>
#include <Duration.h>
#include <text.h>

#define DAY    86400
#define HOUR    3600
#define MINUTE    60
#define SECOND     1

static struct
{
  std::string unit;
  int seconds;
  bool standalone;
} durations[] =
{
  // These are sorted by first character, then length, so that Nibbler::getOneOf
  // returns a maximal match.
  {"annual",     365 * DAY,    true},
  {"biannual",   730 * DAY,    true},
  {"bimonthly",   61 * DAY,    true},
  {"biweekly",    14 * DAY,    true},
  {"biyearly",   730 * DAY,    true},
  {"daily",        1 * DAY,    true},
  {"days",         1 * DAY,    false},
  {"day",          1 * DAY,    true},
  {"d",            1 * DAY,    false},
  {"fortnight",   14 * DAY,    true},
  {"hours",        1 * HOUR,   false},
  {"hour",         1 * HOUR,   true},
  {"hrs",          1 * HOUR,   false},
  {"hr",           1 * HOUR,   true},
  {"h",            1 * HOUR,   false},
  {"minutes",      1 * MINUTE, false},
  {"minute",       1 * MINUTE, true},
  {"mins",         1 * MINUTE, false},
  {"min",          1 * MINUTE, true},
  {"monthly",     30 * DAY,    true},
  {"months",      30 * DAY,    false},
  {"month",       30 * DAY,    true},
  {"mnths",       30 * DAY,    false},
  {"mths",        30 * DAY,    false},
  {"mth",         30 * DAY,    true},
  {"mos",         30 * DAY,    false},
  {"mo",          30 * DAY,    true},
  {"m",           30 * DAY,    false},
  {"quarterly",   91 * DAY,    true},
  {"quarters",    91 * DAY,    false},
  {"quarter",     91 * DAY,    true},
  {"qrtrs",       91 * DAY,    false},
  {"qrtr",        91 * DAY,    true},
  {"qtrs",        91 * DAY,    false},
  {"qtr",         91 * DAY,    true},
  {"q",           91 * DAY,    false},
  {"semiannual", 183 * DAY,    true},
  {"sennight",    14 * DAY,    false},
  {"seconds",      1 * SECOND, false},
  {"second",       1 * SECOND, true},
  {"secs",         1 * SECOND, false},
  {"sec",          1 * SECOND, true},
  {"s",            1 * SECOND, false},
  {"weekdays",     1 * DAY,    true},
  {"weekly",       7 * DAY,    true},
  {"weeks",        7 * DAY,    false},
  {"week",         7 * DAY,    true},
  {"wks",          7 * DAY,    false},
  {"wk",           7 * DAY,    true},
  {"w",            7 * DAY,    false},
  {"yearly",     365 * DAY,    true},
  {"years",      365 * DAY,    false},
  {"year",       365 * DAY,    true},
  {"yrs",        365 * DAY,    false},
  {"yr",         365 * DAY,    true},
  {"y",          365 * DAY,    false},
};

#define NUM_DURATIONS (sizeof (durations) / sizeof (durations[0]))

////////////////////////////////////////////////////////////////////////////////
Duration::Duration ()
: _secs (0)
{
}

////////////////////////////////////////////////////////////////////////////////
Duration::Duration (time_t input)
: _secs (input)
{
}

////////////////////////////////////////////////////////////////////////////////
Duration::Duration (const std::string& input)
: _secs (0)
{
  if (Lexer::isAllDigits (input))
  {
    time_t value = (time_t) strtol (input.c_str (), NULL, 10);
    if (value == 0 || value > 60)
    {
      _secs = value;
      return;
    }
  }

  std::string::size_type idx = 0;
  parse (input, idx);
}

////////////////////////////////////////////////////////////////////////////////
Duration::~Duration ()
{
}

////////////////////////////////////////////////////////////////////////////////
bool Duration::operator< (const Duration& other)
{
  return _secs < other._secs;
}

////////////////////////////////////////////////////////////////////////////////
bool Duration::operator> (const Duration& other)
{
  return _secs > other._secs;
}

////////////////////////////////////////////////////////////////////////////////
Duration& Duration::operator= (const Duration& other)
{
  if (this != &other)
    _secs = other._secs;

  return *this;
}

////////////////////////////////////////////////////////////////////////////////
Duration::operator time_t () const
{
  return _secs;
}

////////////////////////////////////////////////////////////////////////////////
Duration::operator std::string () const
{
  std::stringstream s;
  s << _secs;
  return s.str ();
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::format () const
{
  char formatted[24];
  float days = (float) _secs / 86400.0;

  if (_secs >= 86400 * 365)
    sprintf (formatted, "%.1f year%s",
                        (days / 365),
                        ((int) (float) (days / 365) == 1 ? "" : "s"));
  else if (_secs > 86400 * 84)
    sprintf (formatted, "%1d month%s",
                        (int) (float) (days / 30),
                        ((int) (float) (days / 30) == 1 ? "" : "s"));
  else if (_secs > 86400 * 13)
    sprintf (formatted, "%d week%s",
                        (int) (float) (days / 7.0),
                        ((int) (float) (days / 7.0) == 1 ? "" : "s"));
  else if (_secs >= 86400)
    sprintf (formatted, "%d day%s",
                        (int) days,
                        ((int) days == 1 ? "" : "s"));
  else if (_secs >= 3600)
    sprintf (formatted, "%d hour%s",
                        (int) (float) (_secs / 3600),
                        ((int) (float) (_secs / 3600) == 1 ? "" : "s"));
  else if (_secs >= 60)
    sprintf (formatted, "%d minute%s",
                        (int) (float) (_secs / 60),
                        ((int) (float) (_secs / 60) == 1 ? "" : "s"));
  else if (_secs >= 1)
    sprintf (formatted, "%d second%s",
                        (int) _secs,
                        ((int) _secs == 1 ? "" : "s"));
  else
    strcpy (formatted, "-"); // no i18n

  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatCompact () const
{
  char formatted[24];
  float days = (float) _secs / 86400.0;

       if (_secs >= 86400 * 365) sprintf (formatted, "%.1fy", (days / 365.0));
  else if (_secs >= 86400 * 84)  sprintf (formatted, "%1dmo", (int) (days / 30));
  else if (_secs >= 86400 * 13)  sprintf (formatted, "%dw",   (int) (float) (days / 7.0));
  else if (_secs >= 86400)       sprintf (formatted, "%dd",   (int) days);
  else if (_secs >= 3600)        sprintf (formatted, "%dh",   (int) (_secs / 3600));
  else if (_secs >= 60)          sprintf (formatted, "%dmin", (int) (_secs / 60));
  else if (_secs >= 1)           sprintf (formatted, "%ds",   (int) _secs);
  else                           formatted[0] = '\0';

  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatPrecise () const
{
  char formatted[24];

  int days    = _secs / 86400;
  int hours   = (_secs % 86400) / 3600;
  int minutes = (_secs % 3600) / 60;
  int seconds = _secs % 60;

  if (days > 0) sprintf (formatted, "%dd %d:%02d:%02d", days, hours, minutes, seconds);
  else          sprintf (formatted, "%d:%02d:%02d",     hours, minutes, seconds);

  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatSeconds () const
{
  char formatted[24];
  sprintf (formatted, "%llus", (unsigned long long)_secs);
  return std::string (formatted);
}

////////////////////////////////////////////////////////////////////////////////
std::string Duration::formatISO () const
{
  if (_secs)
  {
    time_t t = _secs;
    int seconds = t % 60; t /= 60;
    int minutes = t % 60; t /= 60;
    int hours   = t % 24; t /= 24;
    int days    = t % 30; t /= 30;
    int months  = t % 12; t /= 12;
    int years   = t;

    std::stringstream s;
    s << 'P';
    if (years)  s << years  << 'Y';
    if (months) s << months << 'M';
    if (days)   s << days   << 'D';

    if (hours || minutes || seconds)
    {
      s << 'T';
      if (hours)   s << hours   << 'H';
      if (minutes) s << minutes << 'M';
      if (seconds) s << seconds << 'S';
    }

    return s.str ();
  }
  else
  {
    return "PT0S";
  }
}

////////////////////////////////////////////////////////////////////////////////
bool Duration::parse (const std::string& input, std::string::size_type& start)
{
  auto original_start = start;
  Nibbler n (input.substr (start));

  // Static and so preserved between calls.
  static std::vector <std::string> units;
  if (units.size () == 0)
    for (unsigned int i = 0; i < NUM_DURATIONS; i++)
      units.push_back (durations[i].unit);

  std::string number;
  std::string unit;

  if (n.getOneOf (units, unit))
  {
    if (n.depleted ()                           ||
        Lexer::isWhitespace         (n.next ()) ||
        Lexer::isSingleCharOperator (n.next ()))
    {
      start = original_start + n.cursor ();

      // Linear lookup - should be logarithmic.
      for (unsigned int i = 0; i < NUM_DURATIONS; i++)
      {
        if (durations[i].unit == unit &&
            durations[i].standalone == true)
        {
          _secs = static_cast <int> (durations[i].seconds);
          return true;
        }
      }
    }
  }

  else if (n.getNumber (number) &&
           number.find ('e') == std::string::npos &&
           number.find ('E') == std::string::npos &&
           (number.find ('+') == std::string::npos || number.find ('+') == 0) &&
           (number.find ('-') == std::string::npos || number.find ('-') == 0))
  {
    n.skipWS ();
    if (n.getOneOf (units, unit))
    {
      // The "d" unit is a special case, because it is the only one that can
      // legitimately occur at the beginning of a UUID, and be followed by an
      // operator:
      //
      //   1111111d-0000-0000-0000-000000000000
      //
      // Because Lexer::isDuration is higher precedence than Lexer::isUUID,
      // the above UUID looks like:
      //
      //   <1111111d> <-> ...
      //   duration   op  ...
      //
      // So as a special case, durations, with units of "d" are rejected if the
      // quantity exceeds 10000.
      //
      if (unit == "d" &&
          strtol (number.c_str (), NULL, 10) > 10000)
        return false;

      if (n.depleted ()                           ||
          Lexer::isWhitespace         (n.next ()) ||
          Lexer::isSingleCharOperator (n.next ()))
      {
        start = original_start + n.cursor ();
        double quantity = strtod (number.c_str (), NULL);

        // Linear lookup - should be logarithmic.
        double seconds = 1;
        for (unsigned int i = 0; i < NUM_DURATIONS; i++)
        {
          if (durations[i].unit == unit)
          {
            seconds = durations[i].seconds;
            _secs = static_cast <int> (quantity * static_cast <double> (seconds));
            return true;
          }
        }
      }
    }
  }

  return false;
}

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


<commit_before>/*****************************************************************************
 * sout.cpp : Stream output dialog ( old-style )
 ****************************************************************************
 * Copyright (C) 2007-2009 the VideoLAN team
 *
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.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; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "dialogs/sout.hpp"
#include "util/qt_dirs.hpp"
#include "components/sout/sout_widgets.hpp"

#include <QString>
#include <QFileDialog>
#include <QToolButton>
#include <assert.h>

SoutDialog::SoutDialog( QWidget *parent, intf_thread_t *_p_intf, const QString& inputMRL )
           : QVLCDialog( parent,  _p_intf )
{
    setWindowTitle( qtr( "Stream Output" ) );
    setWindowRole( "vlc-stream-output" );

    /* UI stuff */
    ui.setupUi( this );
    ui.inputBox->setMRL( inputMRL );
    ui.helpEdit->setPlainText( qtr("This dialog will allow you to stream or "
            "convert your media for use locally, on your private network, "
            "or on the Internet.\n"
            "You should start by checking that source matches what you want "
            "your input to be and then press the \"Next\" "
            "button to continue.\n") );

    ui.mrlEdit->setToolTip ( qtr( "Stream output string.\n"
                "This is automatically generated "
                 "when you change the above settings,\n"
                 "but you can change it manually." ) ) ;

#if 0
    /* This needs Qt4.5 to be cool */
    ui.destTab->setTabsClosable( true );
#else
    closeTabButton = new QToolButton( this );
    ui.destTab->setCornerWidget( closeTabButton );
    closeTabButton->hide();
    closeTabButton->setAutoRaise( true );
    closeTabButton->setIcon( QIcon( ":/toolbar/clear" ) );
    BUTTONACT( closeTabButton, closeTab() );
#endif
    CONNECT( ui.destTab, currentChanged( int ), this, tabChanged( int ) );
    ui.destTab->setTabIcon( 0, QIcon( ":/buttons/playlist/playlist_add" ) );

    ui.destBox->addItem( qtr( "File" ) );
    ui.destBox->addItem( "HTTP" );
    ui.destBox->addItem( "MS-WMSP (MMSH)" );
    ui.destBox->addItem( "RTP / Transport Stream" );
    ui.destBox->addItem( "UDP (legacy)" );
    ui.destBox->addItem( "IceCast" );

    BUTTONACT( ui.addButton, addDest() );

//     /* Connect everything to the updateMRL function */
#define CB( x ) CONNECT( ui.x, toggled( bool ), this, updateMRL() );
#define CT( x ) CONNECT( ui.x, textChanged( const QString& ), this, updateMRL() );
#define CS( x ) CONNECT( ui.x, valueChanged( int ), this, updateMRL() );
#define CC( x ) CONNECT( ui.x, currentIndexChanged( int ), this, updateMRL() );

    /* Misc */
    CB( soutAll );  CS( ttl ); CT( sapName ); CT( sapGroup );
    CB( localOutput );
    CONNECT( ui.profileSelect, optionsChanged(), this, updateMRL() );

    okButton = new QPushButton( qtr( "&Stream" ) );
    QPushButton *cancelButton = new QPushButton( qtr( "&Cancel" ) );

    okButton->setDefault( true );
    ui.acceptButtonBox->addButton( okButton, QDialogButtonBox::AcceptRole );
    ui.acceptButtonBox->addButton( cancelButton, QDialogButtonBox::RejectRole );

    BUTTONACT( okButton, ok() );
    BUTTONACT( cancelButton, cancel() );

    BUTTONACT( ui.nextButton, next() );
    BUTTONACT( ui.nextButton2, next() );
    BUTTONACT( ui.prevButton, prev() );
    BUTTONACT( ui.prevButton2, prev() );

#undef CC
#undef CS
#undef CT
#undef CB
}

void SoutDialog::next()
{
    ui.toolBox->setCurrentIndex( ui.toolBox->currentIndex() + 1 );
}

void SoutDialog::prev()
{
    ui.toolBox->setCurrentIndex( ui.toolBox->currentIndex() - 1 );
}

void SoutDialog::tabChanged( int i )
{
    closeTabButton->setVisible( (i != 0) );
}

void SoutDialog::closeTab()
{
    int i = ui.destTab->currentIndex();
    if( i == 0 ) return;

    QWidget *temp = ui.destTab->currentWidget();
    ui.destTab->removeTab( i );
    delete temp;
    updateMRL();
}

void SoutDialog::addDest( )
{
    int index;
    switch( ui.destBox->currentIndex() )
    {
        case 0:
            {
                FileDestBox *fdb = new FileDestBox( this );
                index = ui.destTab->addTab( fdb, qtr( "File" ) );
                CONNECT( fdb, mrlUpdated(), this, updateMRL() );
            }
            break;
        case 1:
            {
                HTTPDestBox *hdb = new HTTPDestBox( this );
                index = ui.destTab->addTab( hdb, "HTTP" );
                CONNECT( hdb, mrlUpdated(), this, updateMRL() );
            }
            break;
        case 2:
            {
                MMSHDestBox *mdb = new MMSHDestBox( this );
                index = ui.destTab->addTab( mdb, "WMSP" );
                CONNECT( mdb, mrlUpdated(), this, updateMRL() );
            }
            break;
        case 3:
            {
                RTPDestBox *rdb = new RTPDestBox( this );
                index = ui.destTab->addTab( rdb, "RTP/TS" );
                CONNECT( rdb, mrlUpdated(), this, updateMRL() );
            }
            break;
        case 4:
            {
                UDPDestBox *udb = new UDPDestBox( this );
                index = ui.destTab->addTab( udb, "UDP" );
                CONNECT( udb, mrlUpdated(), this, updateMRL() );
            }
            break;
        case 5:
            {
                ICEDestBox *idb = new ICEDestBox( this );
                index = ui.destTab->addTab( idb, "Icecast" );
                CONNECT( idb, mrlUpdated(), this, updateMRL() );
            }
            break;
        default:
            assert(0);
    }

    ui.destTab->setCurrentIndex( index );
    updateMRL();
}

void SoutDialog::ok()
{
    mrl = ui.mrlEdit->toPlainText();
    accept();
}

void SoutDialog::cancel()
{
    mrl.clear();
    reject();
}

void SoutDialog::updateMRL()
{
    QString qs_mux = ui.profileSelect->getMux();

    SoutMrl smrl( ":sout=#" );
    if( !ui.profileSelect->getTranscode().isEmpty() && ui.transcodeBox->isChecked() )
    {
        smrl.begin( ui.profileSelect->getTranscode() );
        smrl.end();
    }

    bool multi = false;

    if( ui.destTab->count() >= 3 ||
        ( ui.destTab->count() == 2 && ui.localOutput->isChecked() ) )
        multi = true;

    if( multi )
        smrl.begin( "duplicate" );

    for( int i = 1; i < ui.destTab->count(); i++ )
    {
        VirtualDestBox *vdb = qobject_cast<VirtualDestBox *>(ui.destTab->widget( i ));
        QString tempMRL = vdb->getMRL( qs_mux );

        if( tempMRL.isEmpty() ) continue;
        if( multi )
            smrl.option( "dst", tempMRL );
        else
        {
            smrl.begin( tempMRL);
            smrl.end();
        }
    }
    if( ui.localOutput->isChecked() )
    {
        if( multi )
            smrl.option( "dst", "display" );
        else
        {
            smrl.begin( "display" );
            smrl.end();
        }
    }

    if ( multi ) smrl.end();

    mrl = smrl.getMrl();

    /* FIXME, deal with SAP
    sout.b_sap = ui.sap->isChecked();
    sout.psz_group = strdup( qtu( ui.sapGroup->text() ) );
    sout.psz_name = strdup( qtu( ui.sapName->text() ) ); */

    if( ui.soutAll->isChecked() )  mrl.append( " :sout-all" );

    mrl.append( " :sout-keep" );

    ui.mrlEdit->setPlainText( mrl );
}

<commit_msg>Code factorization<commit_after>/*****************************************************************************
 * sout.cpp : Stream output dialog ( old-style )
 ****************************************************************************
 * Copyright (C) 2007-2009 the VideoLAN team
 *
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.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; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "dialogs/sout.hpp"
#include "util/qt_dirs.hpp"
#include "components/sout/sout_widgets.hpp"

#include <QString>
#include <QFileDialog>
#include <QToolButton>
#include <assert.h>

SoutDialog::SoutDialog( QWidget *parent, intf_thread_t *_p_intf, const QString& inputMRL )
           : QVLCDialog( parent,  _p_intf )
{
    setWindowTitle( qtr( "Stream Output" ) );
    setWindowRole( "vlc-stream-output" );

    /* UI stuff */
    ui.setupUi( this );
    ui.inputBox->setMRL( inputMRL );
    ui.helpEdit->setPlainText( qtr("This dialog will allow you to stream or "
            "convert your media for use locally, on your private network, "
            "or on the Internet.\n"
            "You should start by checking that source matches what you want "
            "your input to be and then press the \"Next\" "
            "button to continue.\n") );

    ui.mrlEdit->setToolTip ( qtr( "Stream output string.\n"
                "This is automatically generated "
                 "when you change the above settings,\n"
                 "but you can change it manually." ) ) ;

#if 0
    /* This needs Qt4.5 to be cool */
    ui.destTab->setTabsClosable( true );
#else
    closeTabButton = new QToolButton( this );
    ui.destTab->setCornerWidget( closeTabButton );
    closeTabButton->hide();
    closeTabButton->setAutoRaise( true );
    closeTabButton->setIcon( QIcon( ":/toolbar/clear" ) );
    BUTTONACT( closeTabButton, closeTab() );
#endif
    CONNECT( ui.destTab, currentChanged( int ), this, tabChanged( int ) );
    ui.destTab->setTabIcon( 0, QIcon( ":/buttons/playlist/playlist_add" ) );

    ui.destBox->addItem( qtr( "File" ) );
    ui.destBox->addItem( "HTTP" );
    ui.destBox->addItem( "MS-WMSP (MMSH)" );
    ui.destBox->addItem( "RTP / Transport Stream" );
    ui.destBox->addItem( "UDP (legacy)" );
    ui.destBox->addItem( "IceCast" );

    BUTTONACT( ui.addButton, addDest() );

//     /* Connect everything to the updateMRL function */
#define CB( x ) CONNECT( ui.x, toggled( bool ), this, updateMRL() );
#define CT( x ) CONNECT( ui.x, textChanged( const QString& ), this, updateMRL() );
#define CS( x ) CONNECT( ui.x, valueChanged( int ), this, updateMRL() );
#define CC( x ) CONNECT( ui.x, currentIndexChanged( int ), this, updateMRL() );

    /* Misc */
    CB( soutAll );  CS( ttl ); CT( sapName ); CT( sapGroup );
    CB( localOutput );
    CONNECT( ui.profileSelect, optionsChanged(), this, updateMRL() );

    okButton = new QPushButton( qtr( "&Stream" ) );
    QPushButton *cancelButton = new QPushButton( qtr( "&Cancel" ) );

    okButton->setDefault( true );
    ui.acceptButtonBox->addButton( okButton, QDialogButtonBox::AcceptRole );
    ui.acceptButtonBox->addButton( cancelButton, QDialogButtonBox::RejectRole );

    BUTTONACT( okButton, ok() );
    BUTTONACT( cancelButton, cancel() );

    BUTTONACT( ui.nextButton, next() );
    BUTTONACT( ui.nextButton2, next() );
    BUTTONACT( ui.prevButton, prev() );
    BUTTONACT( ui.prevButton2, prev() );

#undef CC
#undef CS
#undef CT
#undef CB
}

void SoutDialog::next()
{
    ui.toolBox->setCurrentIndex( ui.toolBox->currentIndex() + 1 );
}

void SoutDialog::prev()
{
    ui.toolBox->setCurrentIndex( ui.toolBox->currentIndex() - 1 );
}

void SoutDialog::tabChanged( int i )
{
    closeTabButton->setVisible( (i != 0) );
}

void SoutDialog::closeTab()
{
    int i = ui.destTab->currentIndex();
    if( i == 0 ) return;

    QWidget *temp = ui.destTab->currentWidget();
    ui.destTab->removeTab( i );
    delete temp;
    updateMRL();
}

void SoutDialog::addDest( )
{
    VirtualDestBox *db;
    QString caption;

    switch( ui.destBox->currentIndex() )
    {
        case 0:
            db = new FileDestBox( this );
            caption = qtr( "File" );
            break;
        case 1:
            db = new HTTPDestBox( this );
            caption = qfu( "HTTP" );
            break;
        case 2:
            db = new MMSHDestBox( this );
            caption = qfu( "WMSP" );
            break;
        case 3:
            db = new RTPDestBox( this );
            caption = "RTP/TS";
            break;
        case 4:
            db = new UDPDestBox( this );
            caption = "UDP";
            break;
        case 5:
            db = new ICEDestBox( this );
            caption = "Icecast";
            break;
        default:
            assert(0);
    }

    int index = ui.destTab->addTab( db, caption );
    CONNECT( db, mrlUpdated(), this, updateMRL() );
    ui.destTab->setCurrentIndex( index );
    updateMRL();
}

void SoutDialog::ok()
{
    mrl = ui.mrlEdit->toPlainText();
    accept();
}

void SoutDialog::cancel()
{
    mrl.clear();
    reject();
}

void SoutDialog::updateMRL()
{
    QString qs_mux = ui.profileSelect->getMux();

    SoutMrl smrl( ":sout=#" );
    if( !ui.profileSelect->getTranscode().isEmpty() && ui.transcodeBox->isChecked() )
    {
        smrl.begin( ui.profileSelect->getTranscode() );
        smrl.end();
    }

    bool multi = false;

    if( ui.destTab->count() >= 3 ||
        ( ui.destTab->count() == 2 && ui.localOutput->isChecked() ) )
        multi = true;

    if( multi )
        smrl.begin( "duplicate" );

    for( int i = 1; i < ui.destTab->count(); i++ )
    {
        VirtualDestBox *vdb = qobject_cast<VirtualDestBox *>(ui.destTab->widget( i ));
        QString tempMRL = vdb->getMRL( qs_mux );

        if( tempMRL.isEmpty() ) continue;
        if( multi )
            smrl.option( "dst", tempMRL );
        else
        {
            smrl.begin( tempMRL);
            smrl.end();
        }
    }
    if( ui.localOutput->isChecked() )
    {
        if( multi )
            smrl.option( "dst", "display" );
        else
        {
            smrl.begin( "display" );
            smrl.end();
        }
    }

    if ( multi ) smrl.end();

    mrl = smrl.getMrl();

    /* FIXME, deal with SAP
    sout.b_sap = ui.sap->isChecked();
    sout.psz_group = strdup( qtu( ui.sapGroup->text() ) );
    sout.psz_name = strdup( qtu( ui.sapName->text() ) ); */

    if( ui.soutAll->isChecked() )  mrl.append( " :sout-all" );

    mrl.append( " :sout-keep" );

    ui.mrlEdit->setPlainText( mrl );
}

<|endoftext|>


<commit_before>#include "Smartcar.h"

ESCMotor::ESCMotor(unsigned short pin) {
	_pin = pin;
	setFreqsAndSpeeds();
	setAllowedSpeedLimits();
}

void ESCMotor::setFreqsAndSpeeds(){
	FULL_FORWARD = 50;
        FULL_BACKWARD = 80;
	IDLE_RAW_SPEED = 1500;
	MAX_FRONT_RAW_SPEED = 2000;
	MAX_BACK_RAW_SPEED = 1000;
	_speed = IDLE_RAW_SPEED;
}

void ESCMotor::init(){
	attach(_pin); //attach the servo to its pin
}

void ESCMotor::setSpeed(int speed){ //receives a speed in the scale of -100 to 100
	_speed = filterSpeed(speed); //_speed now holds a value between MAX_BACK_ALLOWED_SPEED and MAX_FRONT_ALLOWED_SPEED
	writeMicroseconds(_speed); //write the appropriate pwm signal to the servo
}
<commit_msg>Adjusting the values in the ESC motor so it makes more sense for the average use cases<commit_after>#include "Smartcar.h"

ESCMotor::ESCMotor(unsigned short pin) {
	_pin = pin;
	setFreqsAndSpeeds();
	setAllowedSpeedLimits();
}

void ESCMotor::setFreqsAndSpeeds(){
	FULL_FORWARD = 100;
        FULL_BACKWARD = 100;
	IDLE_RAW_SPEED = 1500;
	MAX_FRONT_RAW_SPEED = 1800;
	MAX_BACK_RAW_SPEED = 1200;
	_speed = IDLE_RAW_SPEED;
}

void ESCMotor::init(){
	attach(_pin); //attach the servo to its pin
}

void ESCMotor::setSpeed(int speed){ //receives a speed in the scale of -100 to 100
	_speed = filterSpeed(speed); //_speed now holds a value between MAX_BACK_ALLOWED_SPEED and MAX_FRONT_ALLOWED_SPEED
	writeMicroseconds(_speed); //write the appropriate pwm signal to the servo
}
<|endoftext|>


<commit_before>/*
   Filename: EngineUI.cpp
   Purpose:  Draws the EngineUI and console on top of rendering

   Part of Engine2D

   Copyright (C) 2014 Vbitz

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "EngineUI.hpp"

#include "FramePerfMonitor.hpp"
#include "Config.hpp"
#include "Profiler.hpp"

namespace Engine {
    char getSpecialChars(int key) {
        switch (key) {
            case '[':       return '{';
            case ']':       return '}';
            case '-':       return '_';
            case '=':       return '+';
            case '\\':      return '|';
            case '`':       return '~';
            case '1':       return '!';
            case '2':       return '@';
            case '3':       return '#';
            case '4':       return '$';
            case '5':       return '%';
            case '6':       return '^';
            case '7':       return '&';
            case '8':       return '*';
            case '9':       return '(';
            case '0':       return ')';
            case ',':       return '<';
            case '.':       return '>';
            case ';':       return ':';
            case '\'':      return '"';
            case '/':       return '?';
            default:        return key;
        }
    }

    EngineUI::EngineUI(Application* app) : _app(app) {
        this->_draw = new Draw2D(GetRenderGL());
    }

    void EngineUI::Draw() {
        if (!Config::GetBoolean("core.debug.engineUI")) {
            return;
        }

        RenderGL3* renderGL = GetRenderGL();

        renderGL->ResetMatrix();

        if (!_showConsole) {
            renderGL->SetColor(25 / 255.0f, 25 / 255.0f, 25 / 255.0f);
        } else {
            renderGL->SetColor(40 / 255.0f, 40 / 255.0f, 40 / 255.0f, 0.95f);
        }

        this->_draw->Rect(0.0f, 0.0f, this->_app->GetScreenWidth(), _showConsole ? this->_app->GetScreenHeight() : 14);

        renderGL->SetFont("basic", 10);
        if (!this->_showConsole) {
            renderGL->SetColor(220 / 255.0f, 220 / 255.0f, 220 / 255.0f);
        } else {
            renderGL->SetColor(1.0f, 1.0f, 1.0f);
        }

        if (Config::GetBoolean("core.debug.profiler")) {
            double drawTime = Profiler::GetTime("Draw");
            this->_lastDrawTimes[this->_currentLastDrawTimePos++] = drawTime;

            if (this->_currentLastDrawTimePos > 100) {
                this->_currentLastDrawTimePos = 0;
            }

            this->_ss.str("");
            this->_ss.precision(4);
            this->_ss << "FPS: " << FramePerfMonitor::GetFPS();
            this->_ss << " | DrawTime: " << drawTime;
            renderGL->Print(this->_app->GetScreenWidth() - 220, 4, this->_ss.str().c_str());

            renderGL->DisableSmooth();

            this->_draw->LineGraph(this->_app->GetScreenWidth() - 430, 14, 2, 200, this->_lastDrawTimes, 100);

            renderGL->EnableSmooth();
        }

        renderGL->Print(10, 4, "-- Engine2D --");

        if (!_showConsole) {
            return;
        }

        std::vector<Logger::LogEvent>* logEvents = Logger::GetEvents();

        bool showVerbose = Config::GetBoolean("core.debug.engineUI.showVerboseLog"); // pretty cheap

        int i = this->_app->GetScreenHeight() - 40;

        for (auto iterator = logEvents->rbegin(); iterator < logEvents->rend(); iterator++) {
            if (iterator->Hidden) {
                continue; // don't show it if it's hidden
            }

            if (iterator->Type == Logger::LogType_Text) {
                if (iterator->Level == Logger::LogLevel_Verbose && !showVerbose) {
                    i -= 6; // add some padding to show that a message is there, just hidden
                    renderGL->SetColor(80 / 255.0f, 80 / 255.0f, 80 / 255.0f);
                    this->_draw->Rect(0, i + 2, this->_app->GetScreenWidth(), 2);
                } else {
                    i -= 22;
                    if (iterator->Level == Logger::LogLevel_Highlight) {
                        renderGL->SetColor(200 / 255.0f, 200 / 255.0f, 200 / 255.0f, 0.9f);
                        this->_draw->Rect(0, i + 1, this->_app->GetScreenWidth(), 20);
                    } else {
                        renderGL->SetColor(30 / 255.0f, 30 / 255.0f, 30 / 255.0f, 0.9f);
                        this->_draw->Rect(60, i + 1, this->_app->GetScreenWidth() - 60, 20);
                    }
                }
            }

            switch (iterator->Level) {
                case Logger::LogLevel_Verbose:
                    renderGL->SetColor(205 / 255.0f, 205 / 255.0f, 205 / 255.0f);
                    break;
                case Logger::LogLevel_User:
                    renderGL->SetColor(255 / 255.0f, 0 / 255.0f, 255 / 255.0f);
                    break;
                case Logger::LogLevel_ConsoleInput:
                    renderGL->SetColor(0 / 255.0f, 191 / 255.0f, 255 / 255.0f);
                    break;
                case Logger::LogLevel_Log:
                    renderGL->SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                    break;
                case Logger::LogLevel_Warning:
                    renderGL->SetColor(255 / 255.0f, 165 / 255.0f, 0 / 255.0f);
                    break;
                case Logger::LogLevel_Error:
                    renderGL->SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                    break;
                case Logger::LogLevel_Highlight:
                    renderGL->SetColor(0.1f, 0.1f, 0.1f);
                    break;
                case Logger::LogLevel_TestLog:
                    renderGL->SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                    break;
                case Logger::LogLevel_TestError:
                    renderGL->SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                    break;
            }

            std::string time = std::to_string(iterator->time);
            time.resize(6, '0');

            if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                renderGL->Print(5, i + 7, (time + "s").c_str());
            }

            if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                if (iterator->Type == Logger::LogType_Text) {
                    renderGL->Print(65, i + 7, iterator->Event.c_str());
                } else if (iterator->Type == Logger::LogType_Graphical) {
                    i -= (*iterator->GraphEvent)(65, i);
                }
            }

            if (i < 35) {
                break;
            }
        }

        renderGL->SetColor(0.0f, 0.0f, 0.0f, 0.85f);
        this->_draw->Rect(5, this->_app->GetScreenHeight() - 30, this->_app->GetScreenWidth() - 10, 25);

        renderGL->SetColor(1.0f, 1.0f, 1.0f);
        renderGL->SetFont("basic", 12);
        renderGL->Print(10, this->_app->GetScreenHeight() - 22, (this->_currentConsoleInput.str() + "_").c_str());
    }

#ifndef _PLATFORM_WIN32
#define KEY_CONSOLE 161
#else
#define KEY_CONSOLE 96
#endif

    void EngineUI::OnKeyPress(int key, int press, bool shift) {
        if (!Config::GetBoolean("core.debug.engineUI")) {
            return;
        }

        if (key == KEY_CONSOLE && press == GLFW_PRESS) { // `
            this->ToggleConsole();
        } else if (key == GLFW_KEY_F10 && press == GLFW_PRESS) { // f10
            Events::Emit("dumpProfile");
        }

        if (!_showConsole) {
            return;
        }

        if (key < 256 && (press == GLFW_PRESS || press == GLFW_REPEAT) && key != KEY_CONSOLE && key != GLFW_KEY_ENTER) {
#ifndef _PLATFORM_WIN32
            this->_currentConsoleInput << (char) (shift ? getSpecialChars(key) : (char) std::tolower(key));
#else
            currentConsoleInput << (char) (shift ? getSpecialChars(key) : tolower(key));
#endif
        } else if (key == GLFW_KEY_BACKSPACE && (press == GLFW_PRESS || press == GLFW_REPEAT)) {
            std::string str = this->_currentConsoleInput.str();
            if (str.length() > 0) {
                str.resize(str.length() - 1);
                this->_currentConsoleInput.str(str);
                if (str.length() != 0) {
                    this->_currentConsoleInput.seekp(str.length());
                }
            }
        } else if (key == GLFW_KEY_UP && press == GLFW_PRESS) {
            if (this->_currentHistoryLine > 0) {
                this->_currentHistoryLine--;
                this->_currentConsoleInput.str(this->_commandHistory[this->_currentHistoryLine]);
                if (this->_currentConsoleInput.str().length() != 0) {
                    this->_currentConsoleInput.seekp(this->_currentConsoleInput.str().length());
                }
            }
        } else if (key == GLFW_KEY_DOWN && press == GLFW_PRESS) {
            if (this->_commandHistory.size() > 0 && this->_currentHistoryLine < this->_commandHistory.size() - 1) {
                this->_currentHistoryLine++;
                this->_currentConsoleInput.str(this->_commandHistory[this->_currentHistoryLine]);
                if (this->_currentConsoleInput.str().length() != 0) {
                    this->_currentConsoleInput.seekp(this->_currentConsoleInput.str().length());
                }
            }
        } else if (key == GLFW_KEY_ENTER && press == GLFW_PRESS) {
            std::string command = this->_currentConsoleInput.str();
            this->_app->RunCommand(command);
            if (this->_commandHistory.size() == 0 || this->_commandHistory[this->_commandHistory.size() - 1] != command) {
                this->_commandHistory.push_back(command);
            }
            this->_currentHistoryLine = this->_commandHistory.size();
            this->_currentConsoleInput.str("");
        }
    }

    void EngineUI::SetActive(bool active) {
        this->_active = active;
    }

    void EngineUI::ToggleConsole() {
        this->_showConsole = !this->_showConsole;
    }

    void EngineUI::ClearConsole() {
        Logger::HideAllEvents();
    }

    bool EngineUI::ConsoleActive() {
        return this->_showConsole;
    }
}<commit_msg>EngineUI now fetches RenderGL from Application<commit_after>/*
   Filename: EngineUI.cpp
   Purpose:  Draws the EngineUI and console on top of rendering

   Part of Engine2D

   Copyright (C) 2014 Vbitz

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "EngineUI.hpp"

#include "FramePerfMonitor.hpp"
#include "Config.hpp"
#include "Profiler.hpp"

namespace Engine {
    char getSpecialChars(int key) {
        switch (key) {
            case '[':       return '{';
            case ']':       return '}';
            case '-':       return '_';
            case '=':       return '+';
            case '\\':      return '|';
            case '`':       return '~';
            case '1':       return '!';
            case '2':       return '@';
            case '3':       return '#';
            case '4':       return '$';
            case '5':       return '%';
            case '6':       return '^';
            case '7':       return '&';
            case '8':       return '*';
            case '9':       return '(';
            case '0':       return ')';
            case ',':       return '<';
            case '.':       return '>';
            case ';':       return ':';
            case '\'':      return '"';
            case '/':       return '?';
            default:        return key;
        }
    }

    EngineUI::EngineUI(Application* app) : _app(app) {
        this->_draw = new Draw2D(app->GetRender());
    }

    void EngineUI::Draw() {
        if (!Config::GetBoolean("core.debug.engineUI")) {
            return;
        }

        RenderGL3* renderGL = this->_draw->GetRender();

        renderGL->ResetMatrix();

        if (!_showConsole) {
            renderGL->SetColor(25 / 255.0f, 25 / 255.0f, 25 / 255.0f);
        } else {
            renderGL->SetColor(40 / 255.0f, 40 / 255.0f, 40 / 255.0f, 0.95f);
        }

        this->_draw->Rect(0.0f, 0.0f, this->_app->GetScreenWidth(), _showConsole ? this->_app->GetScreenHeight() : 14);

        renderGL->SetFont("basic", 10);
        if (!this->_showConsole) {
            renderGL->SetColor(220 / 255.0f, 220 / 255.0f, 220 / 255.0f);
        } else {
            renderGL->SetColor(1.0f, 1.0f, 1.0f);
        }

        if (Config::GetBoolean("core.debug.profiler")) {
            double drawTime = Profiler::GetTime("Draw");
            this->_lastDrawTimes[this->_currentLastDrawTimePos++] = drawTime;

            if (this->_currentLastDrawTimePos > 100) {
                this->_currentLastDrawTimePos = 0;
            }

            this->_ss.str("");
            this->_ss.precision(4);
            this->_ss << "FPS: " << FramePerfMonitor::GetFPS();
            this->_ss << " | DrawTime: " << drawTime;
            renderGL->Print(this->_app->GetScreenWidth() - 220, 4, this->_ss.str().c_str());

            renderGL->DisableSmooth();

            this->_draw->LineGraph(this->_app->GetScreenWidth() - 430, 14, 2, 200, this->_lastDrawTimes, 100);

            renderGL->EnableSmooth();
        }

        renderGL->Print(10, 4, "-- Engine2D --");

        if (!_showConsole) {
            return;
        }

        std::vector<Logger::LogEvent>* logEvents = Logger::GetEvents();

        bool showVerbose = Config::GetBoolean("core.debug.engineUI.showVerboseLog"); // pretty cheap

        int i = this->_app->GetScreenHeight() - 40;

        for (auto iterator = logEvents->rbegin(); iterator < logEvents->rend(); iterator++) {
            if (iterator->Hidden) {
                continue; // don't show it if it's hidden
            }

            if (iterator->Type == Logger::LogType_Text) {
                if (iterator->Level == Logger::LogLevel_Verbose && !showVerbose) {
                    i -= 6; // add some padding to show that a message is there, just hidden
                    renderGL->SetColor(80 / 255.0f, 80 / 255.0f, 80 / 255.0f);
                    this->_draw->Rect(0, i + 2, this->_app->GetScreenWidth(), 2);
                } else {
                    i -= 22;
                    if (iterator->Level == Logger::LogLevel_Highlight) {
                        renderGL->SetColor(200 / 255.0f, 200 / 255.0f, 200 / 255.0f, 0.9f);
                        this->_draw->Rect(0, i + 1, this->_app->GetScreenWidth(), 20);
                    } else {
                        renderGL->SetColor(30 / 255.0f, 30 / 255.0f, 30 / 255.0f, 0.9f);
                        this->_draw->Rect(60, i + 1, this->_app->GetScreenWidth() - 60, 20);
                    }
                }
            }

            switch (iterator->Level) {
                case Logger::LogLevel_Verbose:
                    renderGL->SetColor(205 / 255.0f, 205 / 255.0f, 205 / 255.0f);
                    break;
                case Logger::LogLevel_User:
                    renderGL->SetColor(255 / 255.0f, 0 / 255.0f, 255 / 255.0f);
                    break;
                case Logger::LogLevel_ConsoleInput:
                    renderGL->SetColor(0 / 255.0f, 191 / 255.0f, 255 / 255.0f);
                    break;
                case Logger::LogLevel_Log:
                    renderGL->SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                    break;
                case Logger::LogLevel_Warning:
                    renderGL->SetColor(255 / 255.0f, 165 / 255.0f, 0 / 255.0f);
                    break;
                case Logger::LogLevel_Error:
                    renderGL->SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                    break;
                case Logger::LogLevel_Highlight:
                    renderGL->SetColor(0.1f, 0.1f, 0.1f);
                    break;
                case Logger::LogLevel_TestLog:
                    renderGL->SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                    break;
                case Logger::LogLevel_TestError:
                    renderGL->SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                    break;
            }

            std::string time = std::to_string(iterator->time);
            time.resize(6, '0');

            if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                renderGL->Print(5, i + 7, (time + "s").c_str());
            }

            if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                if (iterator->Type == Logger::LogType_Text) {
                    renderGL->Print(65, i + 7, iterator->Event.c_str());
                } else if (iterator->Type == Logger::LogType_Graphical) {
                    i -= (*iterator->GraphEvent)(65, i);
                }
            }

            if (i < 35) {
                break;
            }
        }

        renderGL->SetColor(0.0f, 0.0f, 0.0f, 0.85f);
        this->_draw->Rect(5, this->_app->GetScreenHeight() - 30, this->_app->GetScreenWidth() - 10, 25);

        renderGL->SetColor(1.0f, 1.0f, 1.0f);
        renderGL->SetFont("basic", 12);
        renderGL->Print(10, this->_app->GetScreenHeight() - 22, (this->_currentConsoleInput.str() + "_").c_str());
    }

#ifndef _PLATFORM_WIN32
#define KEY_CONSOLE 161
#else
#define KEY_CONSOLE 96
#endif

    void EngineUI::OnKeyPress(int key, int press, bool shift) {
        if (!Config::GetBoolean("core.debug.engineUI")) {
            return;
        }

        if (key == KEY_CONSOLE && press == GLFW_PRESS) { // `
            this->ToggleConsole();
        } else if (key == GLFW_KEY_F10 && press == GLFW_PRESS) { // f10
            Events::Emit("dumpProfile");
        }

        if (!_showConsole) {
            return;
        }

        if (key < 256 && (press == GLFW_PRESS || press == GLFW_REPEAT) && key != KEY_CONSOLE && key != GLFW_KEY_ENTER) {
#ifndef _PLATFORM_WIN32
            this->_currentConsoleInput << (char) (shift ? getSpecialChars(key) : (char) std::tolower(key));
#else
            currentConsoleInput << (char) (shift ? getSpecialChars(key) : tolower(key));
#endif
        } else if (key == GLFW_KEY_BACKSPACE && (press == GLFW_PRESS || press == GLFW_REPEAT)) {
            std::string str = this->_currentConsoleInput.str();
            if (str.length() > 0) {
                str.resize(str.length() - 1);
                this->_currentConsoleInput.str(str);
                if (str.length() != 0) {
                    this->_currentConsoleInput.seekp(str.length());
                }
            }
        } else if (key == GLFW_KEY_UP && press == GLFW_PRESS) {
            if (this->_currentHistoryLine > 0) {
                this->_currentHistoryLine--;
                this->_currentConsoleInput.str(this->_commandHistory[this->_currentHistoryLine]);
                if (this->_currentConsoleInput.str().length() != 0) {
                    this->_currentConsoleInput.seekp(this->_currentConsoleInput.str().length());
                }
            }
        } else if (key == GLFW_KEY_DOWN && press == GLFW_PRESS) {
            if (this->_commandHistory.size() > 0 && this->_currentHistoryLine < this->_commandHistory.size() - 1) {
                this->_currentHistoryLine++;
                this->_currentConsoleInput.str(this->_commandHistory[this->_currentHistoryLine]);
                if (this->_currentConsoleInput.str().length() != 0) {
                    this->_currentConsoleInput.seekp(this->_currentConsoleInput.str().length());
                }
            }
        } else if (key == GLFW_KEY_ENTER && press == GLFW_PRESS) {
            std::string command = this->_currentConsoleInput.str();
            this->_app->RunCommand(command);
            if (this->_commandHistory.size() == 0 || this->_commandHistory[this->_commandHistory.size() - 1] != command) {
                this->_commandHistory.push_back(command);
            }
            this->_currentHistoryLine = this->_commandHistory.size();
            this->_currentConsoleInput.str("");
        }
    }

    void EngineUI::SetActive(bool active) {
        this->_active = active;
    }

    void EngineUI::ToggleConsole() {
        this->_showConsole = !this->_showConsole;
    }

    void EngineUI::ClearConsole() {
        Logger::HideAllEvents();
    }

    bool EngineUI::ConsoleActive() {
        return this->_showConsole;
    }
}<|endoftext|>


<commit_before>// Font.cc
// Copyright (c) 2002 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//$Id$

#include "StringUtil.hh"
#include "stringstream.hh"
#include "Font.hh"
#include "FontImp.hh"
#include "I18n.hh"
#include "App.hh"

#ifdef    HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H

// for antialias
#ifdef USE_XFT
#include "XftFontImp.hh"
#endif // USE_XFT

// for multibyte support
#ifdef USE_XMB
#include "XmbFontImp.hh"
#endif //USE_XMB

// standard font system
#include "XFontImp.hh"

#include "GContext.hh"
//use gnu extensions
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif //_GNU_SOURCE

#ifndef __USE_GNU
#define __USE_GNU
#endif //__USE_GNU

#include <iostream>
#ifdef HAVE_CSTRING
  #include <cstring>
#else
  #include <string.h>
#endif
#ifdef HAVE_CSTDLIB
  #include <cstdlib>
#else
  #include <stdlib.h>
#endif
#include <list>
#include <map>
#include <typeinfo>
#include <langinfo.h>

#ifdef HAVE_CSTDLIB
  #include <cstdlib>
#else
  #include <stdlib.h>
#endif

using namespace std;

namespace {

#ifdef HAVE_SETLOCALE
#include <locale.h>
#endif //HAVE_SETLOCALE

#ifdef HAVE_ICONV
/**
   Recodes the text from one encoding to another
   assuming cd is correct
   @param cd the iconv type
   @param msg text to be converted
   @param len number of chars to convert
   @return the recoded string, or 0 on failure
*/
char* recode(iconv_t cd,
             const char *msg, size_t size) {

    // If empty message, yes this can happen, return
    if(strlen(msg) == 0 || size == 0)
        return 0;

    if(strlen(msg) < size)
        size = strlen(msg);

    size_t inbytesleft = size;
    size_t outbytesleft = 4*inbytesleft;
    char *new_msg = new char[outbytesleft];
    char *new_msg_ptr = new_msg;
    char *msg_ptr = strdup(msg);
    char *orig_msg_ptr = msg_ptr; // msg_ptr modified in iconv call
    size_t result = (size_t)(-1);

#ifdef HAVE_CONST_ICONV
    result = iconv(cd, (const char**)(&msg_ptr), &inbytesleft, &new_msg, &outbytesleft);
#else
    result = iconv(cd, &msg_ptr, &inbytesleft, &new_msg, &outbytesleft);
#endif  // HAVE_CONST_ICONV

    if (result == (size_t)(-1)) {
        // iconv can fail for three reasons
        // 1) Invalid multibyte sequence is encountered in the input
        // 2) An incomplete multibyte sequence
        // 3) The output buffer has no more room for the next converted character.
        // So we the delete new message and return original message
        delete[] new_msg_ptr;
        free(orig_msg_ptr);
        return 0;
    }
    free(orig_msg_ptr);

    *new_msg = '\0';

    if(inbytesleft != 0) {
        delete[] new_msg_ptr;
        return 0;
    }

    return new_msg_ptr;
}
#else

char *recode(int cd,
             const char *msg, size_t size) {
    return 0;
}
#endif // HAVE_ICONV

// use to map <font1>|<font2>|<font3> => <fontthatworks>
typedef std::map<std::string, std::string> StringMap;
typedef StringMap::iterator StringMapIt;
StringMap lookup_map;

// stores <fontthatworks and the fontimp
typedef std::map<std::string, FbTk::FontImp* > FontCache;
typedef FontCache::iterator FontCacheIt;
FontCache font_cache;

void resetEffects(FbTk::Font* font) {
    font->setHalo(false);
    font->setHaloColor(FbTk::Color("white", DefaultScreen(FbTk::App::instance()->display())));
    font->setShadow(false);
    font->setShadowColor(FbTk::Color("black", DefaultScreen(FbTk::App::instance()->display())));
    font->setShadowOffY(2);
    font->setShadowOffX(2);
}

}; // end nameless namespace

namespace FbTk {

bool Font::s_multibyte = false;
bool Font::s_utf8mode = false;

void Font::init() {
    // must be set before the first XFontSet is created
    setlocale(LC_CTYPE, "");
}

void Font::shutdown() {

    FontCacheIt fit;
    for (fit = font_cache.begin(); fit != font_cache.end(); fit++) {
        FontImp* font = fit->second;
        if (font) {
            FontCacheIt it;
            for (it = fit; it != font_cache.end(); it++)
                if (it->second == font)
                    it->second = 0;
            delete font;
        }
    }
}

Font::Font(const char *name):
    m_fontimp(0),
    m_rotated(false),
    m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())),
    m_shadow_offx(2), m_shadow_offy(2),
    m_halo(false), m_halo_color("white", DefaultScreen(App::instance()->display())),
#ifdef HAVE_ICONV
    m_iconv((iconv_t)(-1))
#else
    m_iconv(-1)
#endif // HAVE_ICONV
{
    // MB_CUR_MAX returns the size of a char in the current locale
    if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte
        s_multibyte = true;

    // check for utf-8 mode
#ifdef CODESET
    char *locale_codeset = nl_langinfo(CODESET);
#else // openbsd doesnt have this (yet?)
    char *locale_codeset = 0;
#endif // CODESET

    if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) {
        s_utf8mode = true;
    } else if (locale_codeset != 0) {
        // if locale isn't UTF-8 we try to
        // create a iconv pointer so we can
        // convert non utf-8 strings to utf-8

#ifdef DEBUG
        cerr<<"FbTk::Font: check UTF-8 convert for codeset = "<<locale_codeset<<endl;
#endif // DEBUG

#ifdef HAVE_ICONV
        m_iconv = iconv_open("UTF-8", locale_codeset);
        if(m_iconv == (iconv_t)(-1)) {
            cerr<<"FbTk::Font: code error: from "<<locale_codeset<<" to: UTF-8"<<endl;
            // if we failed with iconv then we can't convert
            // the strings to utf-8, so we disable utf8 mode
            s_utf8mode = false;
        } else {
            // success, we can now enable utf8mode
            // and if antialias is on later we can recode
            // the non utf-8 string to utf-8 and use utf-8
            // drawing functions
            s_utf8mode = true;
        }
#endif // HAVE_ICONV
    }

#ifdef DEBUG
    cerr<<"FbTk::Font m_iconv = "<<(int)m_iconv<<endl;
#endif // DEBUG

    if (name != 0) {
        load(name);
    }

}

Font::~Font() {
#ifdef HAVE_ICONV
    if (m_iconv != (iconv_t)(-1))
        iconv_close(m_iconv);
#endif // HAVE_ICONV
}

bool Font::load(const std::string &name) {

    if (name.size() == 0)
        return false;

    bool ret = false;
    StringMapIt lookup_entry;
    FontCacheIt cache_entry;

    // check if one of <font1>|<font2>|<font3> is already there
    if ((lookup_entry = lookup_map.find(name)) != lookup_map.end() &&
            (cache_entry = font_cache.find(lookup_entry->second)) != font_cache.end()) {
        m_fontstr = cache_entry->first;
        m_fontimp = cache_entry->second;
        resetEffects(this);
        return true;
     }

    // split up the namelist
    typedef std::list<std::string> StringList;
    typedef StringList::iterator StringListIt;
    StringList names;
    FbTk::StringUtil::stringtok<StringList>(names, name, "|");

    StringListIt name_it;
    for (name_it = names.begin(); name_it != names.end(); name_it++) {
        FbTk::StringUtil::removeTrailingWhitespace(*name_it);
        FbTk::StringUtil::removeFirstWhitespace(*name_it);

        if ((cache_entry = font_cache.find(*name_it)) != font_cache.end()) {
            m_fontstr = cache_entry->first;
            m_fontimp = cache_entry->second;
            lookup_map[name] = m_fontstr;
            resetEffects(this);
            return true;
        }

        FontImp* tmp_font(0);

#ifdef USE_XFT
        if ((*name_it)[0] != '-')
            tmp_font = new XftFontImp(0, s_utf8mode);
#endif // USE_XFT

        if (!tmp_font) {
#ifdef USE_XMB
            if (s_multibyte || s_utf8mode)
                tmp_font = new XmbFontImp(0, s_utf8mode);
            else // basic font implementation
#endif // USE_XMB
                tmp_font = new XFontImp();
        }

        if (tmp_font && tmp_font->load((*name_it).c_str())) {
            lookup_map[name] = (*name_it);
            m_fontimp = tmp_font;
            font_cache[(*name_it)] = tmp_font;
            m_fontstr = name;
            resetEffects(this);
            return true;
        }

        delete tmp_font;
    }

    return false;
}

unsigned int Font::textWidth(const char * const text, unsigned int size) const {
#ifdef HAVE_ICONV
    if (m_fontimp->utf8() && m_iconv != (iconv_t)(-1)) {
        char* rtext  = recode(m_iconv, text, size);
        if (rtext != 0)
            size = strlen(rtext);
        unsigned int r = m_fontimp->textWidth(rtext ? rtext : text, size);
        if (rtext != 0)
            delete[] rtext;
        return r;
    }
#endif // HAVE_ICONV
    return m_fontimp->textWidth(text, size);
}

unsigned int Font::height() const {
    return m_fontimp->height();
}

int Font::ascent() const {
    return m_fontimp->ascent();
}

int Font::descent() const {
    return m_fontimp->descent();
}

void Font::drawText(const FbDrawable &w, int screen, GC gc,
                    const char *text, size_t len, int x, int y,
                    bool rotate) const {
    if (text == 0 || len == 0)
        return;

    char* rtext = 0;

    // so we don't end up in a loop with m_shadow
    static bool first_run = true;

#ifdef HAVE_ICONV
    if (m_fontimp->utf8() && m_iconv != (iconv_t)(-1) && first_run) {
        rtext = recode(m_iconv, text, len);
        if (rtext != 0) {
            len = strlen(rtext);
            // ok, we can't use utf8 mode since the string is invalid
        }
    }
#endif // HAVE_ICONV

    const char *real_text = rtext ? rtext : text;

    // draw "effects" first
    if (first_run) {
        if (m_shadow) {
            FbTk::GContext shadow_gc(w);
            shadow_gc.setForeground(m_shadow_color);
            first_run = false;
            drawText(w, screen, shadow_gc.gc(), real_text, len,
                     x + m_shadow_offx, y + m_shadow_offy, rotate);
            first_run = true;
        } else if (m_halo) {
            FbTk::GContext halo_gc(w);
            halo_gc.setForeground(m_halo_color);
            first_run = false;
            drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y + 1, rotate);
            drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y + 1, rotate);
            drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y - 1, rotate);
            drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y - 1, rotate);
            first_run = true;
        }
    }

    if (!rotate && isRotated()) {
        // if this was called with request to not rotated the text
        // we just forward it to the implementation that handles rotation
        // currently just XFontImp
        // Using dynamic_cast just temporarly until there's a better solution
        // to put in FontImp
        try {
            XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp);
            font->setRotate(false); // disable rotation temporarly

            font->drawText(w, screen, gc, real_text, len, x, y);
            font->setRotate(true); // enable rotation
        } catch (std::bad_cast &bc) {
            // draw normal...
            m_fontimp->drawText(w, screen, gc, real_text, len, x, y);
        }

    } else
        m_fontimp->drawText(w, screen, gc, real_text, len, x, y);

    if (rtext != 0)
        delete[] rtext;

}

void Font::rotate(float angle) {
/* TODO: reimplement rotated text
#ifdef USE_XFT
    // if we are rotated and we are changing to horiz text
    // and we were antialiased before we rotated then change to XftFontImp
    if (isRotated() && angle == 0 && !m_xftfontstr.empty())
        m_fontimp.reset(new XftFontImp(m_fontstr.c_str(),s_utf8mode));
#endif // USE_XFT
    // change to a font imp that handles rotated fonts (i.e just XFontImp at the moment)
    // if we're going to rotate this font
    if (angle != 0 && !isRotated()) {
        m_fontimp.reset(new XFontImp(m_fontstr.c_str()));
        if (!m_fontimp->loaded()) // if it failed to load font, try default font fixed
            m_fontimp->load("fixed");
    }

    //Note: only XFontImp implements FontImp::rotate
    m_fontimp->rotate(angle);

    m_rotated = (angle == 0 ? false : true);
    m_angle = angle;
    */
}

};

<commit_msg>removed unused variable<commit_after>// Font.cc
// Copyright (c) 2002 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//$Id$

#include "StringUtil.hh"
#include "stringstream.hh"
#include "Font.hh"
#include "FontImp.hh"
#include "I18n.hh"
#include "App.hh"

#ifdef    HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H

// for antialias
#ifdef USE_XFT
#include "XftFontImp.hh"
#endif // USE_XFT

// for multibyte support
#ifdef USE_XMB
#include "XmbFontImp.hh"
#endif //USE_XMB

// standard font system
#include "XFontImp.hh"

#include "GContext.hh"
//use gnu extensions
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif //_GNU_SOURCE

#ifndef __USE_GNU
#define __USE_GNU
#endif //__USE_GNU

#include <iostream>
#ifdef HAVE_CSTRING
  #include <cstring>
#else
  #include <string.h>
#endif
#ifdef HAVE_CSTDLIB
  #include <cstdlib>
#else
  #include <stdlib.h>
#endif
#include <list>
#include <map>
#include <typeinfo>
#include <langinfo.h>

#ifdef HAVE_CSTDLIB
  #include <cstdlib>
#else
  #include <stdlib.h>
#endif

using namespace std;

namespace {

#ifdef HAVE_SETLOCALE
#include <locale.h>
#endif //HAVE_SETLOCALE

#ifdef HAVE_ICONV
/**
   Recodes the text from one encoding to another
   assuming cd is correct
   @param cd the iconv type
   @param msg text to be converted
   @param len number of chars to convert
   @return the recoded string, or 0 on failure
*/
char* recode(iconv_t cd,
             const char *msg, size_t size) {

    // If empty message, yes this can happen, return
    if(strlen(msg) == 0 || size == 0)
        return 0;

    if(strlen(msg) < size)
        size = strlen(msg);

    size_t inbytesleft = size;
    size_t outbytesleft = 4*inbytesleft;
    char *new_msg = new char[outbytesleft];
    char *new_msg_ptr = new_msg;
    char *msg_ptr = strdup(msg);
    char *orig_msg_ptr = msg_ptr; // msg_ptr modified in iconv call
    size_t result = (size_t)(-1);

#ifdef HAVE_CONST_ICONV
    result = iconv(cd, (const char**)(&msg_ptr), &inbytesleft, &new_msg, &outbytesleft);
#else
    result = iconv(cd, &msg_ptr, &inbytesleft, &new_msg, &outbytesleft);
#endif  // HAVE_CONST_ICONV

    if (result == (size_t)(-1)) {
        // iconv can fail for three reasons
        // 1) Invalid multibyte sequence is encountered in the input
        // 2) An incomplete multibyte sequence
        // 3) The output buffer has no more room for the next converted character.
        // So we the delete new message and return original message
        delete[] new_msg_ptr;
        free(orig_msg_ptr);
        return 0;
    }
    free(orig_msg_ptr);

    *new_msg = '\0';

    if(inbytesleft != 0) {
        delete[] new_msg_ptr;
        return 0;
    }

    return new_msg_ptr;
}
#else

char *recode(int cd,
             const char *msg, size_t size) {
    return 0;
}
#endif // HAVE_ICONV

// use to map <font1>|<font2>|<font3> => <fontthatworks>
typedef std::map<std::string, std::string> StringMap;
typedef StringMap::iterator StringMapIt;
StringMap lookup_map;

// stores <fontthatworks and the fontimp
typedef std::map<std::string, FbTk::FontImp* > FontCache;
typedef FontCache::iterator FontCacheIt;
FontCache font_cache;

void resetEffects(FbTk::Font* font) {
    font->setHalo(false);
    font->setHaloColor(FbTk::Color("white", DefaultScreen(FbTk::App::instance()->display())));
    font->setShadow(false);
    font->setShadowColor(FbTk::Color("black", DefaultScreen(FbTk::App::instance()->display())));
    font->setShadowOffY(2);
    font->setShadowOffX(2);
}

}; // end nameless namespace

namespace FbTk {

bool Font::s_multibyte = false;
bool Font::s_utf8mode = false;

void Font::init() {
    // must be set before the first XFontSet is created
    setlocale(LC_CTYPE, "");
}

void Font::shutdown() {

    FontCacheIt fit;
    for (fit = font_cache.begin(); fit != font_cache.end(); fit++) {
        FontImp* font = fit->second;
        if (font) {
            FontCacheIt it;
            for (it = fit; it != font_cache.end(); it++)
                if (it->second == font)
                    it->second = 0;
            delete font;
        }
    }
}

Font::Font(const char *name):
    m_fontimp(0),
    m_rotated(false),
    m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())),
    m_shadow_offx(2), m_shadow_offy(2),
    m_halo(false), m_halo_color("white", DefaultScreen(App::instance()->display())),
#ifdef HAVE_ICONV
    m_iconv((iconv_t)(-1))
#else
    m_iconv(-1)
#endif // HAVE_ICONV
{
    // MB_CUR_MAX returns the size of a char in the current locale
    if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte
        s_multibyte = true;

    // check for utf-8 mode
#ifdef CODESET
    char *locale_codeset = nl_langinfo(CODESET);
#else // openbsd doesnt have this (yet?)
    char *locale_codeset = 0;
#endif // CODESET

    if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) {
        s_utf8mode = true;
    } else if (locale_codeset != 0) {
        // if locale isn't UTF-8 we try to
        // create a iconv pointer so we can
        // convert non utf-8 strings to utf-8

#ifdef DEBUG
        cerr<<"FbTk::Font: check UTF-8 convert for codeset = "<<locale_codeset<<endl;
#endif // DEBUG

#ifdef HAVE_ICONV
        m_iconv = iconv_open("UTF-8", locale_codeset);
        if(m_iconv == (iconv_t)(-1)) {
            cerr<<"FbTk::Font: code error: from "<<locale_codeset<<" to: UTF-8"<<endl;
            // if we failed with iconv then we can't convert
            // the strings to utf-8, so we disable utf8 mode
            s_utf8mode = false;
        } else {
            // success, we can now enable utf8mode
            // and if antialias is on later we can recode
            // the non utf-8 string to utf-8 and use utf-8
            // drawing functions
            s_utf8mode = true;
        }
#endif // HAVE_ICONV
    }

#ifdef DEBUG
    cerr<<"FbTk::Font m_iconv = "<<(int)m_iconv<<endl;
#endif // DEBUG

    if (name != 0) {
        load(name);
    }

}

Font::~Font() {
#ifdef HAVE_ICONV
    if (m_iconv != (iconv_t)(-1))
        iconv_close(m_iconv);
#endif // HAVE_ICONV
}

bool Font::load(const std::string &name) {

    if (name.size() == 0)
        return false;

    StringMapIt lookup_entry;
    FontCacheIt cache_entry;

    // check if one of <font1>|<font2>|<font3> is already there
    if ((lookup_entry = lookup_map.find(name)) != lookup_map.end() &&
            (cache_entry = font_cache.find(lookup_entry->second)) != font_cache.end()) {
        m_fontstr = cache_entry->first;
        m_fontimp = cache_entry->second;
        resetEffects(this);
        return true;
     }

    // split up the namelist
    typedef std::list<std::string> StringList;
    typedef StringList::iterator StringListIt;
    StringList names;
    FbTk::StringUtil::stringtok<StringList>(names, name, "|");

    StringListIt name_it;
    for (name_it = names.begin(); name_it != names.end(); name_it++) {
        FbTk::StringUtil::removeTrailingWhitespace(*name_it);
        FbTk::StringUtil::removeFirstWhitespace(*name_it);

        if ((cache_entry = font_cache.find(*name_it)) != font_cache.end()) {
            m_fontstr = cache_entry->first;
            m_fontimp = cache_entry->second;
            lookup_map[name] = m_fontstr;
            resetEffects(this);
            return true;
        }

        FontImp* tmp_font(0);

#ifdef USE_XFT
        if ((*name_it)[0] != '-')
            tmp_font = new XftFontImp(0, s_utf8mode);
#endif // USE_XFT

        if (!tmp_font) {
#ifdef USE_XMB
            if (s_multibyte || s_utf8mode)
                tmp_font = new XmbFontImp(0, s_utf8mode);
            else // basic font implementation
#endif // USE_XMB
                tmp_font = new XFontImp();
        }

        if (tmp_font && tmp_font->load((*name_it).c_str())) {
            lookup_map[name] = (*name_it);
            m_fontimp = tmp_font;
            font_cache[(*name_it)] = tmp_font;
            m_fontstr = name;
            resetEffects(this);
            return true;
        }

        delete tmp_font;
    }

    return false;
}

unsigned int Font::textWidth(const char * const text, unsigned int size) const {
#ifdef HAVE_ICONV
    if (m_fontimp->utf8() && m_iconv != (iconv_t)(-1)) {
        char* rtext  = recode(m_iconv, text, size);
        if (rtext != 0)
            size = strlen(rtext);
        unsigned int r = m_fontimp->textWidth(rtext ? rtext : text, size);
        if (rtext != 0)
            delete[] rtext;
        return r;
    }
#endif // HAVE_ICONV
    return m_fontimp->textWidth(text, size);
}

unsigned int Font::height() const {
    return m_fontimp->height();
}

int Font::ascent() const {
    return m_fontimp->ascent();
}

int Font::descent() const {
    return m_fontimp->descent();
}

void Font::drawText(const FbDrawable &w, int screen, GC gc,
                    const char *text, size_t len, int x, int y,
                    bool rotate) const {
    if (text == 0 || len == 0)
        return;

    char* rtext = 0;

    // so we don't end up in a loop with m_shadow
    static bool first_run = true;

#ifdef HAVE_ICONV
    if (m_fontimp->utf8() && m_iconv != (iconv_t)(-1) && first_run) {
        rtext = recode(m_iconv, text, len);
        if (rtext != 0) {
            len = strlen(rtext);
            // ok, we can't use utf8 mode since the string is invalid
        }
    }
#endif // HAVE_ICONV

    const char *real_text = rtext ? rtext : text;

    // draw "effects" first
    if (first_run) {
        if (m_shadow) {
            FbTk::GContext shadow_gc(w);
            shadow_gc.setForeground(m_shadow_color);
            first_run = false;
            drawText(w, screen, shadow_gc.gc(), real_text, len,
                     x + m_shadow_offx, y + m_shadow_offy, rotate);
            first_run = true;
        } else if (m_halo) {
            FbTk::GContext halo_gc(w);
            halo_gc.setForeground(m_halo_color);
            first_run = false;
            drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y + 1, rotate);
            drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y + 1, rotate);
            drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y - 1, rotate);
            drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y - 1, rotate);
            first_run = true;
        }
    }

    if (!rotate && isRotated()) {
        // if this was called with request to not rotated the text
        // we just forward it to the implementation that handles rotation
        // currently just XFontImp
        // Using dynamic_cast just temporarly until there's a better solution
        // to put in FontImp
        try {
            XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp);
            font->setRotate(false); // disable rotation temporarly

            font->drawText(w, screen, gc, real_text, len, x, y);
            font->setRotate(true); // enable rotation
        } catch (std::bad_cast &bc) {
            // draw normal...
            m_fontimp->drawText(w, screen, gc, real_text, len, x, y);
        }

    } else
        m_fontimp->drawText(w, screen, gc, real_text, len, x, y);

    if (rtext != 0)
        delete[] rtext;

}

void Font::rotate(float angle) {
/* TODO: reimplement rotated text
#ifdef USE_XFT
    // if we are rotated and we are changing to horiz text
    // and we were antialiased before we rotated then change to XftFontImp
    if (isRotated() && angle == 0 && !m_xftfontstr.empty())
        m_fontimp.reset(new XftFontImp(m_fontstr.c_str(),s_utf8mode));
#endif // USE_XFT
    // change to a font imp that handles rotated fonts (i.e just XFontImp at the moment)
    // if we're going to rotate this font
    if (angle != 0 && !isRotated()) {
        m_fontimp.reset(new XFontImp(m_fontstr.c_str()));
        if (!m_fontimp->loaded()) // if it failed to load font, try default font fixed
            m_fontimp->load("fixed");
    }

    //Note: only XFontImp implements FontImp::rotate
    m_fontimp->rotate(angle);

    m_rotated = (angle == 0 ? false : true);
    m_angle = angle;
    */
}

};

<|endoftext|>