<commit_before>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#include "text-editor.hh"
#include "factory.hh"
#include "container.hh"
#include "window.hh" // FIXME: unneeded

namespace Rapicorn {
namespace Text {
using namespace Rapicorn;

typedef enum {
  NEXT_CHAR,
  PREV_CHAR,
  WARP_HOME,
  WARP_END,
} CursorMovement;

ParaState::ParaState() :
  align (ALIGN_LEFT), ellipsize (ELLIPSIZE_END),
  line_spacing (1), indent (0),
  font_family ("Sans"), font_size (12)
{}

AttrState::AttrState() :
  font_family (""), font_scale (1.0),
  bold (false), italic (false), underline (false),
  small_caps (false), strike_through (false),
  foreground (0), background (0)
{}

Editor::Client::~Client ()
{}

String
Editor::Client::markup_text () const
{
  return save_markup();
}

void
Editor::Client::markup_text (const String &markup)
{
  load_markup (markup);
}

static String
escape_xml (const String &input)
{
  String d;
  for (String::const_iterator it = input.begin(); it != input.end(); it++)
    switch (*it)
      {
      case '"':         d += """;  break;
      case '&':         d += "&";   break;
      case '\'':        d += "'";  break;
      case '<':         d += "<";    break;
      case '>':         d += ">";    break;
      default:          d += *it;       break;
      }
  return d;
}

void
Editor::Client::plain_text (const String &markup)
{
  load_markup (escape_xml (markup));
}

String
Editor::Client::plain_text () const
{
  int byte_length = 0;
  const char *t = const_cast<Client*> (this)->peek_text (&byte_length);
  return String (t, byte_length);
}

const PropertyList&
Editor::Client::client_property_list()
{
  static Property *properties[] = {
    MakeProperty (Client, markup_text, _("Markup Text"), _("The text to display, containing font and style markup."), "rw"),
    MakeProperty (Client, plain_text,  _("Plain Text"),  _("The text to display, without markup information."), "rw"),
    MakeProperty (Client, text_mode,   _("Text Mode"),   _("The basic text layout mechanism to use."), "rw"),
  };
  static const PropertyList property_list (properties);
  return property_list;
}

const PropertyList&
Editor::__aida_properties__()
{
  static Property *properties[] = {
    MakeProperty (Editor, text_mode,   _("Text Mode"),   _("The basic text layout mechanism to use."), "rw"),
    MakeProperty (Editor, markup_text, _("Markup Text"), _("The text to display, containing font and style markup."), "rw"),
    MakeProperty (Editor, plain_text,  _("Plain Text"),  _("The text to display, without markup information."), "rw"),
    MakeProperty (Editor, request_chars,  _("Request Chars"),  _("Number of characters to request space for."), 0, INT_MAX, 2, "rw"),
    MakeProperty (Editor, request_digits, _("Request Digits"), _("Number of digits to request space for."), 0, INT_MAX, 2, "rw"),
  };
  static const PropertyList property_list (properties, ContainerImpl::__aida_properties__());
  return property_list;
}

class EditorImpl : public virtual SingleContainerImpl, public virtual Editor, public virtual EventHandler {
  uint     request_chars_, request_digits_;
  int      cursor_;
  TextMode text_mode_;
  Client  *cached_client_;
  size_t   client_sig_;
public:
  EditorImpl() :
    request_chars_ (0), request_digits_ (0),
    cursor_ (0), text_mode_ (TEXT_MODE_SINGLE_LINE), cached_client_ (NULL), client_sig_ (0)
  {}
private:
  ~EditorImpl()
  {
    if (cached_client_)
      {
        cached_client_->sig_selection_changed() -= client_sig_;
        client_sig_ = 0;
        ReferenceCountable *trash = dynamic_cast<WidgetImpl*> (cached_client_);
        cached_client_ = NULL;
        if (trash)
          unref (trash);
      }
  }
  Client*
  get_client()
  {
    // check if text client changed
    Client *candidate = interface<Client*>();
    if (cached_client_ == candidate)
      return cached_client_;
    // adjust to new client
    Client *const old = cached_client_;
    const size_t old_sig = client_sig_;
    ReferenceCountable *base = dynamic_cast<WidgetImpl*> (candidate);
    cached_client_ = base ? candidate : NULL;
    if (base)
      {
        ref (base);
        client_sig_ = cached_client_->sig_selection_changed() += Aida::slot (this, &EditorImpl::selection_changed);
      }
    else
      client_sig_ = 0;
    // cleanup old
    base = dynamic_cast<WidgetImpl*> (old);
    if (base)
      {
        old->sig_selection_changed() -= old_sig;
        unref (base);
      }
    // update new client
    if (cached_client_)
      update_client();
    return cached_client_;
  }
  void
  update_client ()
  {
    Client *client = get_client();
    return_unless (client);
    client->text_mode (text_mode_);
    client->cursor2mark();
    cursor_ = client->mark();
    selection_changed();
  }
  virtual void
  size_request (Requisition &requisition)
  {
    update_client();
    SingleContainerImpl::size_request (requisition);
    uint fallback_chars = 0, fallback_digits = 0;
    if (text_mode_ == TEXT_MODE_SINGLE_LINE)
      {
        requisition.width = 0;
        if (request_chars_ <= 0 && request_digits_ <= 0)
          {
            fallback_chars = 26;
            fallback_digits = 10;
          }
      }
    Client *client = get_client();
    if (client)
      requisition.width += client->text_requisition (fallback_chars + request_chars_, fallback_digits + request_digits_);
  }
  virtual bool
  can_focus () const
  {
    Client *client = cached_client_;
    return client != NULL;
  }
  virtual void
  reset (ResetMode mode = RESET_ALL)
  {}
  virtual bool
  handle_event (const Event &event)
  {
    bool handled = false, ignore = false;
    switch (event.type)
      {
        Client *client;
        bool rs;
        const EventKey *kevent;
        const EventData *devent;
        const EventButton *bevent;
      case KEY_PRESS:
        kevent = dynamic_cast<const EventKey*> (&event);
        rs = (kevent->key_state & MOD_SHIFT) == 0; // reset selection
        switch (kevent->key)
          {
          case 'a':
            if (kevent->key_state & MOD_CONTROL)
              {
                select_all();
                handled = true;
                break;
              }
            goto _default;
          case 'v':
            if (kevent->key_state & MOD_CONTROL)
              {
                get_window()->request_clipboard (77, "text/plain"); // FIXME: should operate on viewport
                handled = true;
                break;
              }
            goto _default;
          case KEY_Home:    case KEY_KP_Home:           handled = move_cursor (WARP_HOME, rs);  break;
          case KEY_End:     case KEY_KP_End:            handled = move_cursor (WARP_END, rs);   break;
          case KEY_Right:   case KEY_KP_Right:          handled = move_cursor (NEXT_CHAR, rs);  break; // FIXME: CTRL moves words
          case KEY_Left:    case KEY_KP_Left:           handled = move_cursor (PREV_CHAR, rs);  break; // FIXME: CTRL moves words
          case KEY_BackSpace:                           handled = delete_backward();            break;
          case KEY_Delete:  case KEY_KP_Delete:         handled = delete_foreward();            break;
          default: _default:
            if (kevent->key_state & MOD_CONTROL &&      // preserve Ctrl + FocusKey for navigation
                key_value_is_focus_dir (kevent->key))
              {
                handled = false;
                ignore = true;
              }
            else
              handled = insert_literally (kevent->utf8input);
            break;
          }
        if (!handled && !ignore && !key_value_is_modifier (kevent->key))
          {
            notify_key_error();
            handled = true;
          }
        break;
      case KEY_CANCELED:
      case KEY_RELEASE:
        break;
      case CONTENT_DATA:
        devent = dynamic_cast<const EventData*> (&event);
        if (devent->nonce == 77 && devent->data_type == "text/plain")
          {
            handled = insert_literally (devent->data);
          }
        break;
      case CONTENT_REQUEST:
        devent = dynamic_cast<const EventData*> (&event);
        if (devent->nonce == 79)
          {
            printerr ("CONTENT_REQUEST: target=%s nonce=%u\n", devent->data_type, devent->nonce);
          }
        break;
      case BUTTON_PRESS:
        bevent = dynamic_cast<const EventButton*> (&event);
        client = get_client();
        grab_focus();
        if (client && bevent->button == 1)
          {
            int o = client->mark();
            bool moved = client->mark_to_coord (bevent->x, bevent->y);
            int m = client->mark();
            if (o != m)
              {
                cursor_ = m;
                client->mark2cursor();
                changed();
              }
            (void) moved;
          }
        else if (bevent->button == 2)
          {
            get_window()->request_selection (77, "text/plain"); // FIXME: should operate on viewport
          }
        handled = true;
        break;
      default: ;
      }
    return handled;
  }
  int
  cursor () const
  {
    return cursor_;
  }
  bool
  move_cursor (CursorMovement cm, const bool reset_selection)
  {
    const bool adjust_selection = !reset_selection;
    Client *client = get_client();
    return_unless (client, false);
    int start, end;
    const bool has_selection = client->get_selection (&start, &end);
    // special case, cursor left/right deselects
    if (has_selection && reset_selection && (cm == PREV_CHAR || cm == NEXT_CHAR))
      {
        client->mark (cm == PREV_CHAR ? start : end);
        client->hide_selector();
        client->mark2cursor();
        cursor_ = client->mark();
        changed();
        return true;
      }
    client->mark (cursor_);
    if (!has_selection && adjust_selection)
      client->mark2selector();                      // old cursor starts selection
    int o = client->mark();
    switch (cm)
      {
      case NEXT_CHAR:       client->step_mark (+1); break;
      case PREV_CHAR:       client->step_mark (-1); break;
      case WARP_HOME:       client->mark (0);       break;
      case WARP_END:        client->mark (-1);      break;
      }
    int m = client->mark();
    if (o == m)
      return false;
    if (reset_selection && has_selection)
      client->hide_selector();
    cursor_ = m;
    client->mark2cursor();
    changed();
    return true;
  }
  bool
  insert_literally (const String &utf8text)
  {
    if (utf8text.size() == 1 &&
        (utf8text[0] == '\b' || // Backspace
         utf8text[0] == '\n' || // Newline
         utf8text[0] == '\r' || // Carriage Return
         utf8text[0] == 0x7f || // Delete
         0))
      return false;     // ignore literal inputs from "control" keys
    Client *client = get_client();
    if (client && !utf8text.empty())
      {
        delete_selection();
        client->mark (cursor_);
        client->mark_insert (utf8text);
        cursor_ = client->mark();
        client->mark2cursor();
        changed();
        return true;
      }
    return false;
  }
  bool
  select_all()
  {
    Client *client = get_client();
    return_unless (client, false);
    client->mark (0);
    client->mark2selector();
    client->mark (-1);
    cursor_ = client->mark();
    client->mark2cursor();
    changed();
    return client->get_selection();
  }
  bool
  delete_selection()
  {
    Client *client = get_client();
    return_unless (client, false);
    int start, end, nutf8;
    const bool has_selection = client->get_selection (&start, &end, &nutf8);
    if (!has_selection)
      return false;
    client->mark (start);
    client->mark_delete (nutf8);
    client->hide_selector();
    cursor_ = client->mark();
    client->mark2cursor();
    changed();
    return true;
  }
  bool
  delete_backward ()
  {
    if (delete_selection())
      return true;
    Client *client = get_client();
    if (client)
      {
        client->mark (cursor_);
        int o = client->mark();
        client->step_mark (-1);
        int m = client->mark();
        if (o == m)
          return false;
        cursor_ = m;
        client->mark2cursor();
        client->mark_delete (1);
        changed();
        return true;
      }
    return false;
  }
  bool
  delete_foreward ()
  {
    Client *client = get_client();
    return_unless (client, false);
    if (delete_selection())
      return true;
    client->mark (cursor_);
    if (client->mark_at_end())
      return false;
    client->mark_delete (1);
    changed();
    return true;
  }
  void
  selection_changed()
  {
    Client *client = get_client();
    int start, end, nutf8;
    const bool has_selection = client->get_selection (&start, &end, &nutf8);
    if (!has_selection || nutf8 < 1)
      get_window()->claim_selection (0, StringVector()); // give up ownership
    else
      get_window()->claim_selection (79, cstrings_to_vector ("text/plain", NULL)); // claim new selection
  }
  virtual void
  text (const String &text)
  {
    Client *client = get_client();
    if (client)
      client->markup_text (text);
  }
  virtual String
  text () const
  {
    return cached_client_ ? cached_client_->markup_text() : "";
  }
  virtual TextMode text_mode      () const                      { return text_mode_; }
  virtual void     text_mode      (TextMode      text_mode)
  {
    text_mode_ = text_mode;
    Client *client = get_client();
    if (client)
      client->text_mode (text_mode_);
    invalidate_size();
  }
  virtual String   markup_text    () const                      { return cached_client_ ? cached_client_->markup_text() : ""; }
  virtual void     markup_text    (const String &markup)        { Client *client = get_client(); if (client) client->markup_text (markup); }
  virtual String   plain_text     () const                      { return cached_client_ ? cached_client_->plain_text() : ""; }
  virtual void     plain_text     (const String &ptext)         { Client *client = get_client(); if (client) client->plain_text (ptext); }
  virtual uint     request_chars  () const                      { return request_chars_; }
  virtual void     request_chars  (uint nc)                     { request_chars_ = nc; invalidate_size(); }
  virtual uint     request_digits () const                      { return request_digits_; }
  virtual void     request_digits (uint nd)                     { request_digits_ = nd; invalidate_size(); }
};
static const WidgetFactory<EditorImpl> editor_factory ("Rapicorn::Factory::Text::Editor");

} // Text
} // Rapicorn
<commit_msg>UI: provide current text selection as text/plain<commit_after>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#include "text-editor.hh"
#include "factory.hh"
#include "container.hh"
#include "window.hh" // FIXME: unneeded

namespace Rapicorn {
namespace Text {
using namespace Rapicorn;

typedef enum {
  NEXT_CHAR,
  PREV_CHAR,
  WARP_HOME,
  WARP_END,
} CursorMovement;

ParaState::ParaState() :
  align (ALIGN_LEFT), ellipsize (ELLIPSIZE_END),
  line_spacing (1), indent (0),
  font_family ("Sans"), font_size (12)
{}

AttrState::AttrState() :
  font_family (""), font_scale (1.0),
  bold (false), italic (false), underline (false),
  small_caps (false), strike_through (false),
  foreground (0), background (0)
{}

Editor::Client::~Client ()
{}

String
Editor::Client::markup_text () const
{
  return save_markup();
}

void
Editor::Client::markup_text (const String &markup)
{
  load_markup (markup);
}

static String
escape_xml (const String &input)
{
  String d;
  for (String::const_iterator it = input.begin(); it != input.end(); it++)
    switch (*it)
      {
      case '"':         d += """;  break;
      case '&':         d += "&";   break;
      case '\'':        d += "'";  break;
      case '<':         d += "<";    break;
      case '>':         d += ">";    break;
      default:          d += *it;       break;
      }
  return d;
}

void
Editor::Client::plain_text (const String &markup)
{
  load_markup (escape_xml (markup));
}

String
Editor::Client::plain_text () const
{
  int byte_length = 0;
  const char *t = const_cast<Client*> (this)->peek_text (&byte_length);
  return String (t, byte_length);
}

const PropertyList&
Editor::Client::client_property_list()
{
  static Property *properties[] = {
    MakeProperty (Client, markup_text, _("Markup Text"), _("The text to display, containing font and style markup."), "rw"),
    MakeProperty (Client, plain_text,  _("Plain Text"),  _("The text to display, without markup information."), "rw"),
    MakeProperty (Client, text_mode,   _("Text Mode"),   _("The basic text layout mechanism to use."), "rw"),
  };
  static const PropertyList property_list (properties);
  return property_list;
}

const PropertyList&
Editor::__aida_properties__()
{
  static Property *properties[] = {
    MakeProperty (Editor, text_mode,   _("Text Mode"),   _("The basic text layout mechanism to use."), "rw"),
    MakeProperty (Editor, markup_text, _("Markup Text"), _("The text to display, containing font and style markup."), "rw"),
    MakeProperty (Editor, plain_text,  _("Plain Text"),  _("The text to display, without markup information."), "rw"),
    MakeProperty (Editor, request_chars,  _("Request Chars"),  _("Number of characters to request space for."), 0, INT_MAX, 2, "rw"),
    MakeProperty (Editor, request_digits, _("Request Digits"), _("Number of digits to request space for."), 0, INT_MAX, 2, "rw"),
  };
  static const PropertyList property_list (properties, ContainerImpl::__aida_properties__());
  return property_list;
}

class EditorImpl : public virtual SingleContainerImpl, public virtual Editor, public virtual EventHandler {
  uint     request_chars_, request_digits_;
  int      cursor_;
  TextMode text_mode_;
  Client  *cached_client_;
  size_t   client_sig_;
public:
  EditorImpl() :
    request_chars_ (0), request_digits_ (0),
    cursor_ (0), text_mode_ (TEXT_MODE_SINGLE_LINE), cached_client_ (NULL), client_sig_ (0)
  {}
private:
  ~EditorImpl()
  {
    if (cached_client_)
      {
        cached_client_->sig_selection_changed() -= client_sig_;
        client_sig_ = 0;
        ReferenceCountable *trash = dynamic_cast<WidgetImpl*> (cached_client_);
        cached_client_ = NULL;
        if (trash)
          unref (trash);
      }
  }
  Client*
  get_client()
  {
    // check if text client changed
    Client *candidate = interface<Client*>();
    if (cached_client_ == candidate)
      return cached_client_;
    // adjust to new client
    Client *const old = cached_client_;
    const size_t old_sig = client_sig_;
    ReferenceCountable *base = dynamic_cast<WidgetImpl*> (candidate);
    cached_client_ = base ? candidate : NULL;
    if (base)
      {
        ref (base);
        client_sig_ = cached_client_->sig_selection_changed() += Aida::slot (this, &EditorImpl::selection_changed);
      }
    else
      client_sig_ = 0;
    // cleanup old
    base = dynamic_cast<WidgetImpl*> (old);
    if (base)
      {
        old->sig_selection_changed() -= old_sig;
        unref (base);
      }
    // update new client
    if (cached_client_)
      update_client();
    return cached_client_;
  }
  void
  update_client ()
  {
    Client *client = get_client();
    return_unless (client);
    client->text_mode (text_mode_);
    client->cursor2mark();
    cursor_ = client->mark();
    selection_changed();
  }
  virtual void
  size_request (Requisition &requisition)
  {
    update_client();
    SingleContainerImpl::size_request (requisition);
    uint fallback_chars = 0, fallback_digits = 0;
    if (text_mode_ == TEXT_MODE_SINGLE_LINE)
      {
        requisition.width = 0;
        if (request_chars_ <= 0 && request_digits_ <= 0)
          {
            fallback_chars = 26;
            fallback_digits = 10;
          }
      }
    Client *client = get_client();
    if (client)
      requisition.width += client->text_requisition (fallback_chars + request_chars_, fallback_digits + request_digits_);
  }
  virtual bool
  can_focus () const
  {
    Client *client = cached_client_;
    return client != NULL;
  }
  virtual void
  reset (ResetMode mode = RESET_ALL)
  {}
  virtual bool
  handle_event (const Event &event)
  {
    bool handled = false, ignore = false;
    switch (event.type)
      {
        Client *client;
        bool rs;
        const EventKey *kevent;
        const EventData *devent;
        const EventButton *bevent;
      case KEY_PRESS:
        kevent = dynamic_cast<const EventKey*> (&event);
        rs = (kevent->key_state & MOD_SHIFT) == 0; // reset selection
        switch (kevent->key)
          {
          case 'a':
            if (kevent->key_state & MOD_CONTROL)
              {
                select_all();
                handled = true;
                break;
              }
            goto _default;
          case 'v':
            if (kevent->key_state & MOD_CONTROL)
              {
                get_window()->request_clipboard (77, "text/plain"); // FIXME: should operate on viewport
                handled = true;
                break;
              }
            goto _default;
          case KEY_Home:    case KEY_KP_Home:           handled = move_cursor (WARP_HOME, rs);  break;
          case KEY_End:     case KEY_KP_End:            handled = move_cursor (WARP_END, rs);   break;
          case KEY_Right:   case KEY_KP_Right:          handled = move_cursor (NEXT_CHAR, rs);  break; // FIXME: CTRL moves words
          case KEY_Left:    case KEY_KP_Left:           handled = move_cursor (PREV_CHAR, rs);  break; // FIXME: CTRL moves words
          case KEY_BackSpace:                           handled = delete_backward();            break;
          case KEY_Delete:  case KEY_KP_Delete:         handled = delete_foreward();            break;
          default: _default:
            if (kevent->key_state & MOD_CONTROL &&      // preserve Ctrl + FocusKey for navigation
                key_value_is_focus_dir (kevent->key))
              {
                handled = false;
                ignore = true;
              }
            else
              handled = insert_literally (kevent->utf8input);
            break;
          }
        if (!handled && !ignore && !key_value_is_modifier (kevent->key))
          {
            notify_key_error();
            handled = true;
          }
        break;
      case KEY_CANCELED:
      case KEY_RELEASE:
        break;
      case CONTENT_DATA:
        devent = dynamic_cast<const EventData*> (&event);
        if (devent->nonce == 77 && devent->data_type == "text/plain")
          {
            handled = insert_literally (devent->data);
          }
        break;
      case CONTENT_REQUEST:
        devent = dynamic_cast<const EventData*> (&event);
        client = get_client();
        if (client && devent->data_type == "text/plain")
          {
            int start, end;
            const bool has_selection = client->get_selection (&start, &end);
            if (has_selection && start >= 0 && end > start)
              {
                String text = client->plain_text();
                if (size_t (end) <= text.size())
                  {
                    text = text.substr (start, end - start);
                    if (utf8_validate (text))
                      get_window()->provide_selection (devent->nonce, "text/plain", text);
                  }
              }
          }
        break;
      case BUTTON_PRESS:
        bevent = dynamic_cast<const EventButton*> (&event);
        client = get_client();
        grab_focus();
        if (client && bevent->button == 1)
          {
            int o = client->mark();
            bool moved = client->mark_to_coord (bevent->x, bevent->y);
            int m = client->mark();
            if (o != m)
              {
                cursor_ = m;
                client->mark2cursor();
                changed();
              }
            (void) moved;
          }
        else if (bevent->button == 2)
          {
            get_window()->request_selection (77, "text/plain"); // FIXME: should operate on viewport
          }
        handled = true;
        break;
      default: ;
      }
    return handled;
  }
  int
  cursor () const
  {
    return cursor_;
  }
  bool
  move_cursor (CursorMovement cm, const bool reset_selection)
  {
    const bool adjust_selection = !reset_selection;
    Client *client = get_client();
    return_unless (client, false);
    int start, end;
    const bool has_selection = client->get_selection (&start, &end);
    // special case, cursor left/right deselects
    if (has_selection && reset_selection && (cm == PREV_CHAR || cm == NEXT_CHAR))
      {
        client->mark (cm == PREV_CHAR ? start : end);
        client->hide_selector();
        client->mark2cursor();
        cursor_ = client->mark();
        changed();
        return true;
      }
    client->mark (cursor_);
    if (!has_selection && adjust_selection)
      client->mark2selector();                      // old cursor starts selection
    int o = client->mark();
    switch (cm)
      {
      case NEXT_CHAR:       client->step_mark (+1); break;
      case PREV_CHAR:       client->step_mark (-1); break;
      case WARP_HOME:       client->mark (0);       break;
      case WARP_END:        client->mark (-1);      break;
      }
    int m = client->mark();
    if (o == m)
      return false;
    if (reset_selection && has_selection)
      client->hide_selector();
    cursor_ = m;
    client->mark2cursor();
    changed();
    return true;
  }
  bool
  insert_literally (const String &utf8text)
  {
    if (utf8text.size() == 1 &&
        (utf8text[0] == '\b' || // Backspace
         utf8text[0] == '\n' || // Newline
         utf8text[0] == '\r' || // Carriage Return
         utf8text[0] == 0x7f || // Delete
         0))
      return false;     // ignore literal inputs from "control" keys
    Client *client = get_client();
    if (client && !utf8text.empty())
      {
        delete_selection();
        client->mark (cursor_);
        client->mark_insert (utf8text);
        cursor_ = client->mark();
        client->mark2cursor();
        changed();
        return true;
      }
    return false;
  }
  bool
  select_all()
  {
    Client *client = get_client();
    return_unless (client, false);
    client->mark (0);
    client->mark2selector();
    client->mark (-1);
    cursor_ = client->mark();
    client->mark2cursor();
    changed();
    return client->get_selection();
  }
  bool
  delete_selection()
  {
    Client *client = get_client();
    return_unless (client, false);
    int start, end, nutf8;
    const bool has_selection = client->get_selection (&start, &end, &nutf8);
    if (!has_selection)
      return false;
    client->mark (start);
    client->mark_delete (nutf8);
    client->hide_selector();
    cursor_ = client->mark();
    client->mark2cursor();
    changed();
    return true;
  }
  bool
  delete_backward ()
  {
    if (delete_selection())
      return true;
    Client *client = get_client();
    if (client)
      {
        client->mark (cursor_);
        int o = client->mark();
        client->step_mark (-1);
        int m = client->mark();
        if (o == m)
          return false;
        cursor_ = m;
        client->mark2cursor();
        client->mark_delete (1);
        changed();
        return true;
      }
    return false;
  }
  bool
  delete_foreward ()
  {
    Client *client = get_client();
    return_unless (client, false);
    if (delete_selection())
      return true;
    client->mark (cursor_);
    if (client->mark_at_end())
      return false;
    client->mark_delete (1);
    changed();
    return true;
  }
  void
  selection_changed()
  {
    Client *client = get_client();
    int start, end, nutf8;
    const bool has_selection = client->get_selection (&start, &end, &nutf8);
    if (!has_selection || nutf8 < 1)
      get_window()->claim_selection (StringVector()); // give up ownership
    else
      get_window()->claim_selection (cstrings_to_vector ("text/plain", NULL)); // claim new selection
  }
  virtual void
  text (const String &text)
  {
    Client *client = get_client();
    if (client)
      client->markup_text (text);
  }
  virtual String
  text () const
  {
    return cached_client_ ? cached_client_->markup_text() : "";
  }
  virtual TextMode text_mode      () const                      { return text_mode_; }
  virtual void     text_mode      (TextMode      text_mode)
  {
    text_mode_ = text_mode;
    Client *client = get_client();
    if (client)
      client->text_mode (text_mode_);
    invalidate_size();
  }
  virtual String   markup_text    () const                      { return cached_client_ ? cached_client_->markup_text() : ""; }
  virtual void     markup_text    (const String &markup)        { Client *client = get_client(); if (client) client->markup_text (markup); }
  virtual String   plain_text     () const                      { return cached_client_ ? cached_client_->plain_text() : ""; }
  virtual void     plain_text     (const String &ptext)         { Client *client = get_client(); if (client) client->plain_text (ptext); }
  virtual uint     request_chars  () const                      { return request_chars_; }
  virtual void     request_chars  (uint nc)                     { request_chars_ = nc; invalidate_size(); }
  virtual uint     request_digits () const                      { return request_digits_; }
  virtual void     request_digits (uint nd)                     { request_digits_ = nd; invalidate_size(); }
};
static const WidgetFactory<EditorImpl> editor_factory ("Rapicorn::Factory::Text::Editor");

} // Text
} // Rapicorn
<|endoftext|>


<commit_before><commit_msg>Fixed<commit_after><|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE broker
#include "caf/test/unit_test.hpp"

#include <memory>
#include <iostream>

#include "caf/all.hpp"
#include "caf/io/all.hpp"

#include "caf/string_algorithms.hpp"

#include "caf/detail/run_program.hpp"

using namespace std;
using namespace caf;
using namespace caf::io;

using ping_atom = caf::atom_constant<caf::atom("ping")>;
using pong_atom = caf::atom_constant<caf::atom("pong")>;
using publish_atom = caf::atom_constant<caf::atom("publish")>;
using kickoff_atom = caf::atom_constant<caf::atom("kickoff")>;

namespace {

void ping(event_based_actor* self, size_t num_pings) {
  CAF_MESSAGE("num_pings: " << num_pings);
  auto count = std::make_shared<size_t>(0);
  self->become(
    [=](kickoff_atom, const actor& pong) {
      CAF_MESSAGE("received `kickoff_atom`");
      self->send(pong, ping_atom::value, 1);
      self->become(
      [=](pong_atom, int value)->std::tuple<atom_value, int> {
        if (++*count >= num_pings) {
          CAF_MESSAGE("received " << num_pings
                      << " pings, call self->quit");
          self->quit();
        }
        return std::make_tuple(ping_atom::value, value + 1);
      },
      others >> [&] {
        CAF_TEST_ERROR("Unexpected message: "
                       << to_string(self->current_message()));
      });
    },
    others >> [&] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  );
}

void pong(event_based_actor* self) {
  CAF_MESSAGE("pong actor started");
  self->become(
    [=](ping_atom, int value) -> std::tuple<atom_value, int> {
      CAF_MESSAGE("received `ping_atom`");
      self->monitor(self->current_sender());
      // set next behavior
      self->become(
        [](ping_atom, int val) {
          return std::make_tuple(pong_atom::value, val);
        },
        [=](const down_msg& dm) {
          CAF_MESSAGE("received down_msg{" << dm.reason << "}");
          self->quit(dm.reason);
        },
        others >> [&] {
          CAF_TEST_ERROR("Unexpected message: "
                         << to_string(self->current_message()));
        }
      );
      // reply to 'ping'
      return std::make_tuple(pong_atom::value, value);
    },
    others >> [&] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  );
}

}

void peer_fun(broker* self, connection_handle hdl, const actor& buddy) {
  CAF_MESSAGE("peer_fun called");
  CAF_CHECK(self != nullptr);
  CAF_CHECK(buddy != invalid_actor);
  self->monitor(buddy);
  // assume exactly one connection
  auto cons = self->connections();
  if (cons.size() != 1) {
    cerr << "expected 1 connection, found " << cons.size() << endl;
    throw std::logic_error("num_connections() != 1");
  }
  self->configure_read(
    hdl, receive_policy::exactly(sizeof(atom_value) + sizeof(int)));
  auto write = [=](atom_value type, int value) {
    auto& buf = self->wr_buf(hdl);
    auto first = reinterpret_cast<char*>(&type);
    buf.insert(buf.end(), first, first + sizeof(atom_value));
    first = reinterpret_cast<char*>(&value);
    buf.insert(buf.end(), first, first + sizeof(int));
    self->flush(hdl);

  };
  self->become(
    [=](const connection_closed_msg&) {
      CAF_MESSAGE("received connection_closed_msg");
      self->quit();
    },
    [=](const new_data_msg& msg) {
      CAF_MESSAGE("received new_data_msg");
      atom_value type;
      int value;
      memcpy(&type, msg.buf.data(), sizeof(atom_value));
      memcpy(&value, msg.buf.data() + sizeof(atom_value), sizeof(int));
      self->send(buddy, type, value);
    },
    [=](ping_atom, int value) {
      CAF_MESSAGE("received ping{" << value << "}");
      write(ping_atom::value, value);
    },
    [=](pong_atom, int value) {
      CAF_MESSAGE("received pong{" << value << "}");
      write(pong_atom::value, value);
    },
    [=](const down_msg& dm) {
      CAF_MESSAGE("received down_msg");
      if (dm.source == buddy) {
        self->quit(dm.reason);
      }
    },
    others >> [&] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  );
}

behavior peer_acceptor_fun(broker* self, const actor& buddy) {
  CAF_MESSAGE("peer_acceptor_fun");
  return {
    [=](const new_connection_msg& msg) {
      CAF_MESSAGE("received `new_connection_msg`");
      self->fork(peer_fun, msg.handle, buddy);
      self->quit();
    },
    [=](publish_atom) {
      return self->add_tcp_doorman(0, "127.0.0.1").second;
    },
    others >> [&] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  };
}

namespace {

void run_server(bool spawn_client, const char* bin_path) {
  scoped_actor self;
  auto serv = io::spawn_io(peer_acceptor_fun, spawn(pong));
  self->sync_send(serv, publish_atom::value).await(
    [&](uint16_t port) {
      CAF_MESSAGE("server is running on port " << port);
      if (spawn_client) {
        auto child = detail::run_program(self, bin_path, "-n", "-s", "broker",
                                         "--", "-c", port);
        CAF_MESSAGE("block till child process has finished");
        child.join();
      }
    }
  );
  self->await_all_other_actors_done();
  self->receive(
    [](const std::string& output) {
      cout << endl << endl << "*** output of client program ***"
           << endl << output << endl;
    }
  );
}

}

CAF_TEST(test_broker) {
  auto argv = caf::test::engine::argv();
  auto argc = caf::test::engine::argc();
  if (argv) {
    uint16_t port = 0;
    auto r = message_builder(argv, argv + argc).extract_opts({
      {"client-port,c", "set port for IO client", port},
      {"server,s", "run in server mode"}
    });
    if (! r.error.empty() || r.opts.count("help") > 0 || ! r.remainder.empty()) {
      cout << r.error << endl << endl << r.helptext << endl;
      return;
    }
    if (r.opts.count("client-port") > 0) {
      auto p = spawn(ping, 10);
      CAF_MESSAGE("spawn_io_client...");
      auto cl = spawn_io_client(peer_fun, "localhost", port, p);
      CAF_MESSAGE("spawn_io_client finished");
      anon_send(p, kickoff_atom::value, cl);
      CAF_MESSAGE("`kickoff_atom` has been send");
    } else {
      // run in server mode
      run_server(false, argv[0]);
    }
  } else {
    run_server(true, caf::test::engine::path());
  }
  CAF_MESSAGE("block on `await_all_actors_done`");
  await_all_actors_done();
  CAF_MESSAGE("`await_all_actors_done` has finished");
  shutdown();
}
<commit_msg>Fix lambda captures in broker unit test<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE broker
#include "caf/test/unit_test.hpp"

#include <memory>
#include <iostream>

#include "caf/all.hpp"
#include "caf/io/all.hpp"

#include "caf/string_algorithms.hpp"

#include "caf/detail/run_program.hpp"

using namespace std;
using namespace caf;
using namespace caf::io;

namespace {

using ping_atom = caf::atom_constant<caf::atom("ping")>;
using pong_atom = caf::atom_constant<caf::atom("pong")>;
using publish_atom = caf::atom_constant<caf::atom("publish")>;
using kickoff_atom = caf::atom_constant<caf::atom("kickoff")>;

void ping(event_based_actor* self, size_t num_pings) {
  CAF_MESSAGE("num_pings: " << num_pings);
  auto count = std::make_shared<size_t>(0);
  self->become(
    [=](kickoff_atom, const actor& pong) {
      CAF_MESSAGE("received `kickoff_atom`");
      self->send(pong, ping_atom::value, 1);
      self->become(
      [=](pong_atom, int value)->std::tuple<atom_value, int> {
        if (++*count >= num_pings) {
          CAF_MESSAGE("received " << num_pings
                      << " pings, call self->quit");
          self->quit();
        }
        return std::make_tuple(ping_atom::value, value + 1);
      },
      others >> [=] {
        CAF_TEST_ERROR("Unexpected message: "
                       << to_string(self->current_message()));
      });
    },
    others >> [=] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  );
}

void pong(event_based_actor* self) {
  CAF_MESSAGE("pong actor started");
  self->become(
    [=](ping_atom, int value) -> std::tuple<atom_value, int> {
      CAF_MESSAGE("received `ping_atom`");
      self->monitor(self->current_sender());
      // set next behavior
      self->become(
        [](ping_atom, int val) {
          return std::make_tuple(pong_atom::value, val);
        },
        [=](const down_msg& dm) {
          CAF_MESSAGE("received down_msg{" << dm.reason << "}");
          self->quit(dm.reason);
        },
        others >> [=] {
          CAF_TEST_ERROR("Unexpected message: "
                         << to_string(self->current_message()));
        }
      );
      // reply to 'ping'
      return std::make_tuple(pong_atom::value, value);
    },
    others >> [=] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  );
}

void peer_fun(broker* self, connection_handle hdl, const actor& buddy) {
  CAF_MESSAGE("peer_fun called");
  CAF_CHECK(self != nullptr);
  CAF_CHECK(buddy != invalid_actor);
  self->monitor(buddy);
  // assume exactly one connection
  auto cons = self->connections();
  if (cons.size() != 1) {
    cerr << "expected 1 connection, found " << cons.size() << endl;
    throw std::logic_error("num_connections() != 1");
  }
  self->configure_read(
    hdl, receive_policy::exactly(sizeof(atom_value) + sizeof(int)));
  auto write = [=](atom_value type, int value) {
    auto& buf = self->wr_buf(hdl);
    auto first = reinterpret_cast<char*>(&type);
    buf.insert(buf.end(), first, first + sizeof(atom_value));
    first = reinterpret_cast<char*>(&value);
    buf.insert(buf.end(), first, first + sizeof(int));
    self->flush(hdl);

  };
  self->become(
    [=](const connection_closed_msg&) {
      CAF_MESSAGE("received connection_closed_msg");
      self->quit();
    },
    [=](const new_data_msg& msg) {
      CAF_MESSAGE("received new_data_msg");
      atom_value type;
      int value;
      memcpy(&type, msg.buf.data(), sizeof(atom_value));
      memcpy(&value, msg.buf.data() + sizeof(atom_value), sizeof(int));
      self->send(buddy, type, value);
    },
    [=](ping_atom, int value) {
      CAF_MESSAGE("received ping{" << value << "}");
      write(ping_atom::value, value);
    },
    [=](pong_atom, int value) {
      CAF_MESSAGE("received pong{" << value << "}");
      write(pong_atom::value, value);
    },
    [=](const down_msg& dm) {
      CAF_MESSAGE("received down_msg");
      if (dm.source == buddy) {
        self->quit(dm.reason);
      }
    },
    others >> [=] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  );
}

behavior peer_acceptor_fun(broker* self, const actor& buddy) {
  CAF_MESSAGE("peer_acceptor_fun");
  return {
    [=](const new_connection_msg& msg) {
      CAF_MESSAGE("received `new_connection_msg`");
      self->fork(peer_fun, msg.handle, buddy);
      self->quit();
    },
    [=](publish_atom) {
      return self->add_tcp_doorman(0, "127.0.0.1").second;
    },
    others >> [&] {
      CAF_TEST_ERROR("Unexpected message: "
                     << to_string(self->current_message()));
    }
  };
}

void run_server(bool spawn_client, const char* bin_path) {
  scoped_actor self;
  auto serv = io::spawn_io(peer_acceptor_fun, spawn(pong));
  self->sync_send(serv, publish_atom::value).await(
    [&](uint16_t port) {
      CAF_MESSAGE("server is running on port " << port);
      if (spawn_client) {
        auto child = detail::run_program(self, bin_path, "-n", "-s", "broker",
                                         "--", "-c", port);
        CAF_MESSAGE("block till child process has finished");
        child.join();
      }
    }
  );
  self->await_all_other_actors_done();
  self->receive(
    [](const std::string& output) {
      cout << endl << endl << "*** output of client program ***"
           << endl << output << endl;
    }
  );
}

} // namespace <anonymous>

CAF_TEST(test_broker) {
  auto argv = caf::test::engine::argv();
  auto argc = caf::test::engine::argc();
  if (argv) {
    uint16_t port = 0;
    auto r = message_builder(argv, argv + argc).extract_opts({
      {"client-port,c", "set port for IO client", port},
      {"server,s", "run in server mode"}
    });
    if (! r.error.empty() || r.opts.count("help") > 0 || ! r.remainder.empty()) {
      cout << r.error << endl << endl << r.helptext << endl;
      return;
    }
    if (r.opts.count("client-port") > 0) {
      auto p = spawn(ping, 10);
      CAF_MESSAGE("spawn_io_client...");
      auto cl = spawn_io_client(peer_fun, "localhost", port, p);
      CAF_MESSAGE("spawn_io_client finished");
      anon_send(p, kickoff_atom::value, cl);
      CAF_MESSAGE("`kickoff_atom` has been send");
    } else {
      // run in server mode
      run_server(false, argv[0]);
    }
  } else {
    run_server(true, caf::test::engine::path());
  }
  CAF_MESSAGE("block on `await_all_actors_done`");
  await_all_actors_done();
  CAF_MESSAGE("`await_all_actors_done` has finished");
  shutdown();
}
<|endoftext|>


<commit_before><commit_msg>helloword<commit_after><|endoftext|>


<commit_before><commit_msg>Re-organize functions in UIRoot<commit_after><|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkVertexBufferObject.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include <pcl/visualization/vtk/vtkVertexBufferObject.h>

#include "vtkCellArray.h"
#include "vtkDataArray.h"
#include "vtkObject.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLExtensionManager.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkPoints.h"
#include "vtkRenderWindow.h"
#include "vtkUnsignedCharArray.h"

#include "vtkgl.h" // Needed for gl data types exposed in API
#include "vtkOpenGL.h"

//#define VTK_PBO_DEBUG
//#define VTK_PBO_TIMING

#ifdef VTK_PBO_TIMING
#include "vtkTimerLog.h"
#endif

// Mapping from Usage values to OpenGL values.

GLenum OpenGLVertexBufferObjectUsage[9]=
{
  vtkgl::STREAM_DRAW,
  vtkgl::STREAM_READ,
  vtkgl::STREAM_COPY,
  vtkgl::STATIC_DRAW,
  vtkgl::STATIC_READ,
  vtkgl::STATIC_COPY,
  vtkgl::DYNAMIC_DRAW,
  vtkgl::DYNAMIC_READ,
  vtkgl::DYNAMIC_COPY
};

const char *VertexBufferObjectUsageAsString[9]=
{
  "StreamDraw",
  "StreamRead",
  "StreamCopy",
  "StaticDraw",
  "StaticRead",
  "StaticCopy",
  "DynamicDraw",
  "DynamicRead",
  "DynamicCopy"
};

#ifdef  VTK_PBO_DEBUG
#include <pthread.h> // for debugging with MPI, pthread_self()
#endif

vtkStandardNewMacro(vtkVertexBufferObject);
//----------------------------------------------------------------------------
vtkVertexBufferObject::vtkVertexBufferObject()
{
  this->Handle = 0;
  this->Context = 0;
  this->BufferTarget = 0;
  this->Size=0;
  this->Count=0;
//  this->Type=VTK_UNSIGNED_CHAR;
  this->Usage=StaticDraw;
}

//----------------------------------------------------------------------------
vtkVertexBufferObject::~vtkVertexBufferObject()
{
  this->SetContext(0);
}

//----------------------------------------------------------------------------
// Description:
// Returns if the context supports the required extensions.
bool vtkVertexBufferObject::IsSupported(vtkRenderWindow* win)
{
  vtkOpenGLRenderWindow* renWin = vtkOpenGLRenderWindow::SafeDownCast(win);
  if (renWin)
    {
    vtkOpenGLExtensionManager* mgr = renWin->GetExtensionManager();

    bool vbo=mgr->ExtensionSupported("GL_VERSION_1_5") ||
      mgr->ExtensionSupported("GL_ARB_vertex_buffer_object");

    return vbo;
    }
  return false;
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::LoadRequiredExtensions(
  vtkOpenGLExtensionManager* mgr)
{
  bool gl15 = mgr->ExtensionSupported("GL_VERSION_1_5")==1;

  bool vbo = gl15 || mgr->ExtensionSupported("GL_ARB_vertex_buffer_object");

  if(vbo)
    {
    if(gl15)
      {
      mgr->LoadExtension("GL_VERSION_1_5");
      }
    else
      {
      mgr->LoadCorePromotedExtension("GL_ARB_vertex_buffer_object");
      }
    }
  return vbo;
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::SetContext(vtkRenderWindow* renWin)
{
  if (this->Context == renWin)
    {
    return;
    }

  this->DestroyBuffer();

  vtkOpenGLRenderWindow* openGLRenWin =
    vtkOpenGLRenderWindow::SafeDownCast(renWin);
  this->Context = openGLRenWin;
  if (openGLRenWin)
    {
    if (!this->LoadRequiredExtensions(openGLRenWin->GetExtensionManager()))
      {
      this->Context = 0;
      vtkErrorMacro("Required OpenGL extensions not supported by the context.");
      }
    }

  this->Modified();
}

//----------------------------------------------------------------------------
vtkRenderWindow* vtkVertexBufferObject::GetContext()
{
  return this->Context;
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::Bind()
{
  if (!this->Context)
    {
    vtkErrorMacro("No context specified. Cannot Bind.");
    return;
    }

  this->CreateBuffer();

  vtkgl::BindBuffer(static_cast<GLenum>(this->BufferTarget), this->Handle);

  vtkGraphicErrorMacro(this->Context,"after BindBuffer");
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::UnBind()
{
  if (this->Context && this->Handle && this->BufferTarget)
    {
    vtkgl::BindBuffer(this->BufferTarget, 0);
    vtkGraphicErrorMacro(this->Context,"after BindBuffer");
    //this->BufferTarget = 0;
    }
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::CreateBuffer()
{
  this->Context->MakeCurrent();
  if (!this->Handle)
    {
    cout << "Creating Buffer..." << endl;
    GLuint ioBuf;
    vtkgl::GenBuffers(1, &ioBuf);
    vtkGraphicErrorMacro(this->Context, "after GenBuffers");
    this->Handle = ioBuf;
    }
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::DestroyBuffer()
{
  if (this->Context && this->Handle)
    {
    GLuint ioBuf = static_cast<GLuint>(this->Handle);
    vtkgl::DeleteBuffers(1, &ioBuf);
    }
  this->Handle = 0;
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(vtkPoints *points)
{
  std::cout << "Setting Points" << endl;
  this->Count = points->GetNumberOfPoints();
  this->Size = this->Count * 3 * sizeof(float);
  this->BufferTarget = vtkgl::ARRAY_BUFFER;

  return this->SetData(points->GetVoidPointer(0));
}

//----------------------------------------------------------------------------
//bool vtkVertexBufferObject::SetData(vtkCellArray *verts)
//{
//  // The correct way to do this is to use each cells vtkIdTypes, but this
//  // returns a tuple (1, index) which I don't have time to understand right
//  // now
//  //vtkIdType *oldarray = input->GetVerts()->GetPointer();
//  //int *newarray = new int[numPoints];
//  //std::copy(oldarray, oldarray + numPoints, newarray);
//  //for (size_t i=0; i < numPoints*2; i+=2)
//  //  std::cout << "really" << oldarray[i] << endl;
//
//  this->Size = points->GetNumberOfPoints() * sizeof(unsigned int);
//  this->BufferTarget = vtkgl::ELEMENT_ARRAY_BUFFER;
//
//  // For now, display every indice
//  unsigned int *indices = new unsigned int[numPoints];
//  for (size_t i=0; i < numPoints; i++){
//    indices[i] = i;
//  }
//
//  this->SetData((void *)indices);
//}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(std::vector<unsigned int> *indices)
{
  std::cout << "Setting Indices" << endl;
  this->Count = indices->size();
  this->Size = this->Count * sizeof(unsigned int);
  this->BufferTarget = vtkgl::ELEMENT_ARRAY_BUFFER;

  return this->SetData(reinterpret_cast<GLvoid *>(indices->data()));
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(vtkDataArray *colors)
{
  std::cout << "Setting Colors" << endl;
  //this->Count = colors->GetNumberOfTuples();
  this->Count = colors->GetSize();
  std::cout << "Type: " << colors->GetDataTypeAsString() <<std::endl;
  this->Size = this->Count * 1 * sizeof(float);
  this->BufferTarget = vtkgl::ARRAY_BUFFER;
  std::cout << "Setting Data" << endl;

  return this->SetData(reinterpret_cast<GLvoid *>(colors->GetVoidPointer(0)));
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(vtkUnsignedCharArray *colors)
{
  std::cout << "Setting Colors" << endl;
  std::cout << "Colors == NULL: " << (colors == NULL) << endl;
  this->Count = colors->GetSize();
  std::cout << "Type: " << colors->GetDataTypeAsString() <<std::endl;
  this->Size = this->Count * 1 * sizeof(float);
  this->BufferTarget = vtkgl::ARRAY_BUFFER;

  std::cout << "Setting Data" << endl;
  return this->SetData(reinterpret_cast<GLvoid *>(colors->GetPointer(0)));
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(GLvoid* data)
{
  if (!this->Context)
     {
     vtkErrorMacro("No context specified. Cannot upload data.");
     return false;
     }

  this->CreateBuffer();

//  cout << "  Context: " << this->Context << endl;
//  cout << "  Handle: " << this->Handle << endl;
//  cout << "  Size: " << this->Size << endl;
//  cout << "  Count: " << this->Count << endl;
//  cout << "  Usage: " << VertexBufferObjectUsageAsString[this->Usage] << endl;

  GLenum usage = OpenGLVertexBufferObjectUsage[this->Usage];

  this->Bind();
    vtkgl::BufferData(this->BufferTarget, this->Size, data, usage);
  this->UnBind();

  cout << "Buffer Created" << endl;
  return true;
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::ReleaseMemory()
{
  if (this->Context && this->Handle)
    {
    this->Bind();
    vtkgl::BufferData(this->BufferTarget, 0, NULL, OpenGLVertexBufferObjectUsage[this->Usage]);
    this->Size = 0;
    this->Count = 0;
    }
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "Context: " << this->Context << endl;
  os << indent << "Handle: " << this->Handle << endl;
  os << indent << "Size: " << this->Size << endl;
  os << indent << "Count: " << this->Count << endl;
  os << indent << "Usage:" << VertexBufferObjectUsageAsString[this->Usage] << endl;
}
<commit_msg>compilation under windows<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkVertexBufferObject.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include <pcl/visualization/vtk/vtkVertexBufferObject.h>

#include "vtkCellArray.h"
#include "vtkDataArray.h"
#include "vtkObject.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLExtensionManager.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkPoints.h"
#include "vtkRenderWindow.h"
#include "vtkUnsignedCharArray.h"

#include "vtkgl.h" // Needed for gl data types exposed in API
#include "vtkOpenGL.h"

//#define VTK_PBO_DEBUG
//#define VTK_PBO_TIMING

#ifdef VTK_PBO_TIMING
#include "vtkTimerLog.h"
#endif

// Mapping from Usage values to OpenGL values.

GLenum OpenGLVertexBufferObjectUsage[9]=
{
  vtkgl::STREAM_DRAW,
  vtkgl::STREAM_READ,
  vtkgl::STREAM_COPY,
  vtkgl::STATIC_DRAW,
  vtkgl::STATIC_READ,
  vtkgl::STATIC_COPY,
  vtkgl::DYNAMIC_DRAW,
  vtkgl::DYNAMIC_READ,
  vtkgl::DYNAMIC_COPY
};

const char *VertexBufferObjectUsageAsString[9]=
{
  "StreamDraw",
  "StreamRead",
  "StreamCopy",
  "StaticDraw",
  "StaticRead",
  "StaticCopy",
  "DynamicDraw",
  "DynamicRead",
  "DynamicCopy"
};

#ifdef  VTK_PBO_DEBUG
#include <pthread.h> // for debugging with MPI, pthread_self()
#endif

vtkStandardNewMacro(vtkVertexBufferObject);
//----------------------------------------------------------------------------
vtkVertexBufferObject::vtkVertexBufferObject()
{
  this->Handle = 0;
  this->Context = 0;
  this->BufferTarget = 0;
  this->Size=0;
  this->Count=0;
//  this->Type=VTK_UNSIGNED_CHAR;
  this->Usage=StaticDraw;
}

//----------------------------------------------------------------------------
vtkVertexBufferObject::~vtkVertexBufferObject()
{
  this->SetContext(0);
}

//----------------------------------------------------------------------------
// Description:
// Returns if the context supports the required extensions.
bool vtkVertexBufferObject::IsSupported(vtkRenderWindow* win)
{
  vtkOpenGLRenderWindow* renWin = vtkOpenGLRenderWindow::SafeDownCast(win);
  if (renWin)
    {
    vtkOpenGLExtensionManager* mgr = renWin->GetExtensionManager();

    bool vbo=mgr->ExtensionSupported("GL_VERSION_1_5") ||
      mgr->ExtensionSupported("GL_ARB_vertex_buffer_object");

    return vbo;
    }
  return false;
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::LoadRequiredExtensions(
  vtkOpenGLExtensionManager* mgr)
{
  bool gl15 = mgr->ExtensionSupported("GL_VERSION_1_5")==1;

  bool vbo = gl15 || mgr->ExtensionSupported("GL_ARB_vertex_buffer_object");

  if(vbo)
    {
    if(gl15)
      {
      mgr->LoadExtension("GL_VERSION_1_5");
      }
    else
      {
      mgr->LoadCorePromotedExtension("GL_ARB_vertex_buffer_object");
      }
    }
  return vbo;
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::SetContext(vtkRenderWindow* renWin)
{
  if (this->Context == renWin)
    {
    return;
    }

  this->DestroyBuffer();

  vtkOpenGLRenderWindow* openGLRenWin =
    vtkOpenGLRenderWindow::SafeDownCast(renWin);
  this->Context = openGLRenWin;
  if (openGLRenWin)
    {
    if (!this->LoadRequiredExtensions(openGLRenWin->GetExtensionManager()))
      {
      this->Context = 0;
      vtkErrorMacro("Required OpenGL extensions not supported by the context.");
      }
    }

  this->Modified();
}

//----------------------------------------------------------------------------
vtkRenderWindow* vtkVertexBufferObject::GetContext()
{
  return this->Context;
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::Bind()
{
  if (!this->Context)
    {
    vtkErrorMacro("No context specified. Cannot Bind.");
    return;
    }

  this->CreateBuffer();

  vtkgl::BindBuffer(static_cast<GLenum>(this->BufferTarget), this->Handle);

  vtkGraphicErrorMacro(this->Context,"after BindBuffer");
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::UnBind()
{
  if (this->Context && this->Handle && this->BufferTarget)
    {
    vtkgl::BindBuffer(this->BufferTarget, 0);
    vtkGraphicErrorMacro(this->Context,"after BindBuffer");
    //this->BufferTarget = 0;
    }
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::CreateBuffer()
{
  this->Context->MakeCurrent();
  if (!this->Handle)
    {
    cout << "Creating Buffer..." << endl;
    GLuint ioBuf;
    vtkgl::GenBuffers(1, &ioBuf);
    vtkGraphicErrorMacro(this->Context, "after GenBuffers");
    this->Handle = ioBuf;
    }
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::DestroyBuffer()
{
  if (this->Context && this->Handle)
    {
    GLuint ioBuf = static_cast<GLuint>(this->Handle);
    vtkgl::DeleteBuffers(1, &ioBuf);
    }
  this->Handle = 0;
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(vtkPoints *points)
{
  std::cout << "Setting Points" << endl;
  this->Count = points->GetNumberOfPoints();
  this->Size = this->Count * 3 * sizeof(float);
  this->BufferTarget = vtkgl::ARRAY_BUFFER;

  return this->SetData(points->GetVoidPointer(0));
}

//----------------------------------------------------------------------------
//bool vtkVertexBufferObject::SetData(vtkCellArray *verts)
//{
//  // The correct way to do this is to use each cells vtkIdTypes, but this
//  // returns a tuple (1, index) which I don't have time to understand right
//  // now
//  //vtkIdType *oldarray = input->GetVerts()->GetPointer();
//  //int *newarray = new int[numPoints];
//  //std::copy(oldarray, oldarray + numPoints, newarray);
//  //for (size_t i=0; i < numPoints*2; i+=2)
//  //  std::cout << "really" << oldarray[i] << endl;
//
//  this->Size = points->GetNumberOfPoints() * sizeof(unsigned int);
//  this->BufferTarget = vtkgl::ELEMENT_ARRAY_BUFFER;
//
//  // For now, display every indice
//  unsigned int *indices = new unsigned int[numPoints];
//  for (size_t i=0; i < numPoints; i++){
//    indices[i] = i;
//  }
//
//  this->SetData((void *)indices);
//}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(std::vector<unsigned int> *indices)
{
  std::cout << "Setting Indices" << endl;
  this->Count = indices->size();
  this->Size = this->Count * sizeof(unsigned int);
  this->BufferTarget = vtkgl::ELEMENT_ARRAY_BUFFER;

  return this->SetData(reinterpret_cast<GLvoid *>(&indices[0]));
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(vtkDataArray *colors)
{
  std::cout << "Setting Colors" << endl;
  //this->Count = colors->GetNumberOfTuples();
  this->Count = colors->GetSize();
  std::cout << "Type: " << colors->GetDataTypeAsString() <<std::endl;
  this->Size = this->Count * 1 * sizeof(float);
  this->BufferTarget = vtkgl::ARRAY_BUFFER;
  std::cout << "Setting Data" << endl;

  return this->SetData(reinterpret_cast<GLvoid *>(colors->GetVoidPointer(0)));
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(vtkUnsignedCharArray *colors)
{
  std::cout << "Setting Colors" << endl;
  std::cout << "Colors == NULL: " << (colors == NULL) << endl;
  this->Count = colors->GetSize();
  std::cout << "Type: " << colors->GetDataTypeAsString() <<std::endl;
  this->Size = this->Count * 1 * sizeof(float);
  this->BufferTarget = vtkgl::ARRAY_BUFFER;

  std::cout << "Setting Data" << endl;
  return this->SetData(reinterpret_cast<GLvoid *>(colors->GetPointer(0)));
}

//----------------------------------------------------------------------------
bool vtkVertexBufferObject::SetData(GLvoid* data)
{
  if (!this->Context)
     {
     vtkErrorMacro("No context specified. Cannot upload data.");
     return false;
     }

  this->CreateBuffer();

//  cout << "  Context: " << this->Context << endl;
//  cout << "  Handle: " << this->Handle << endl;
//  cout << "  Size: " << this->Size << endl;
//  cout << "  Count: " << this->Count << endl;
//  cout << "  Usage: " << VertexBufferObjectUsageAsString[this->Usage] << endl;

  GLenum usage = OpenGLVertexBufferObjectUsage[this->Usage];

  this->Bind();
    vtkgl::BufferData(this->BufferTarget, this->Size, data, usage);
  this->UnBind();

  cout << "Buffer Created" << endl;
  return true;
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::ReleaseMemory()
{
  if (this->Context && this->Handle)
    {
    this->Bind();
    vtkgl::BufferData(this->BufferTarget, 0, NULL, OpenGLVertexBufferObjectUsage[this->Usage]);
    this->Size = 0;
    this->Count = 0;
    }
}

//----------------------------------------------------------------------------
void vtkVertexBufferObject::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "Context: " << this->Context << endl;
  os << indent << "Handle: " << this->Handle << endl;
  os << indent << "Size: " << this->Size << endl;
  os << indent << "Count: " << this->Count << endl;
  os << indent << "Usage:" << VertexBufferObjectUsageAsString[this->Usage] << endl;
}
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2016 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef JUBATUS_DUMP_REGRESSION_HPP_
#define JUBATUS_DUMP_REGRESSION_HPP_

#include <stdint.h>

#include <map>
#include <string>

#include <jubatus/util/data/serialization.h>

#include "types.hpp"
#include "weight_manager.hpp"
#include "local_storage_mixture.hpp"
#include "regression.hpp"

namespace jubatus {
namespace dump {

struct linear_regression {
  local_storage_mixture storage;

  MSGPACK_DEFINE(storage);
};

struct linear_regression_dump {
  explicit linear_regression_dump(const linear_regression& regression)
      : storage(regression.storage) {
  }

  local_storage_mixture_dump storage;

  template <class Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(storage);
  }
};

template <typename S>
struct regression {
  typedef S storage_type;

  storage_type storage;
  weight_manager weights;

  MSGPACK_DEFINE(storage, weights);
};

template <typename S, typename D>
struct regression_dump {
  typedef S storage_type;
  typedef D dump_type;

  explicit regression_dump(const regression<S>& regression)
      : storage(regression.storage),
        weights(regression.weights) {
  }

  dump_type storage;
  weight_manager_dump weights;

  template <class Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(storage) & JUBA_MEMBER(weights);
  }
};

}  // namespace dump
}  // namespace jubatus

#endif  // JUBATUS_DUMP_REGRESSION_HPP_
<commit_msg>remove unused include<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2016 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef JUBATUS_DUMP_REGRESSION_HPP_
#define JUBATUS_DUMP_REGRESSION_HPP_

#include <stdint.h>

#include <map>
#include <string>

#include <jubatus/util/data/serialization.h>

#include "types.hpp"
#include "weight_manager.hpp"
#include "local_storage_mixture.hpp"

namespace jubatus {
namespace dump {

struct linear_regression {
  local_storage_mixture storage;

  MSGPACK_DEFINE(storage);
};

struct linear_regression_dump {
  explicit linear_regression_dump(const linear_regression& regression)
      : storage(regression.storage) {
  }

  local_storage_mixture_dump storage;

  template <class Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(storage);
  }
};

template <typename S>
struct regression {
  typedef S storage_type;

  storage_type storage;
  weight_manager weights;

  MSGPACK_DEFINE(storage, weights);
};

template <typename S, typename D>
struct regression_dump {
  typedef S storage_type;
  typedef D dump_type;

  explicit regression_dump(const regression<S>& regression)
      : storage(regression.storage),
        weights(regression.weights) {
  }

  dump_type storage;
  weight_manager_dump weights;

  template <class Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(storage) & JUBA_MEMBER(weights);
  }
};

}  // namespace dump
}  // namespace jubatus

#endif  // JUBATUS_DUMP_REGRESSION_HPP_
<|endoftext|>


<commit_before>/*
    Simple Console
    Copyright (C) 1998 by Jorrit Tyberghein

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "sysdef.h"
#include "cssys/system.h"
#include "cssys/sysdriv.h"
#include "cstools/simpcons.h"
#include "csinput/csinput.h"
#include "csutil/csrect.h"
#include "csutil/inifile.h"
#include "igraph2d.h"
#include "itxtmgr.h"

#define SIZE_LINE	256
#define SIZE_HISTORY	32

#define Gfx2D System->piG2D

void GfxWrite (int x, int y, int fg, int bg, char *str, ...)
{
  va_list arg;
  char buf[256];

  va_start (arg, str);
  vsprintf (buf, str, arg);
  va_end (arg);

  Gfx2D->Write (x, y, fg, bg, buf);
}

csSimpleConsole::csSimpleConsole (csIniFile *iConfig, csSimpleCommand* pc) : command_handler(pc)
{
  config = iConfig;
  LineMessageMax = config->GetInt ("SimpleConsole", "LINEMAX", 4);
  HistoryMax = config->GetInt ("SimpleConsole", "LINEHISTORY", SIZE_HISTORY);
  console_transparent_bg = config->GetYesNo ("SimpleConsole", "TRANSPBG", 1);
  char *buf = config->GetStr ("SimpleConsole", "CONFG", "255,255,255");
  sscanf (buf, "%d,%d,%d", &console_fg_r, &console_fg_g, &console_fg_b);
  buf = config->GetStr ("SimpleConsole", "CONBG", "0,0,0");
  sscanf (buf, "%d,%d,%d", &console_bg_r, &console_bg_g, &console_bg_b);
  buf = config->GetStr ("SimpleConsole", "CONFONT", "auto");
  if (!strcasecmp (buf, "auto"))
  {
    long screen_surface = System->FrameWidth * System->FrameHeight;
    if (screen_surface <= 320*200)
      console_font = csFontTiny;
    else if (screen_surface <= 640*480)
      console_font = csFontCourier;
    else
      console_font = csFontPolice;
  }
  else if (!strcasecmp (buf, "tiny"))
    console_font = csFontTiny;
  else if (!strcasecmp (buf, "courier"))
    console_font = csFontCourier;
  else if (!strcasecmp (buf, "police"))
    console_font = csFontPolice;
  else
  {
    System->Printf (MSG_FATAL_ERROR, "Bad value for CONFONT in configuration "
      "file.\nUse 'auto', 'tiny', 'courier', or 'police'\n");
    fatal_exit (0, false);
  }

  int i;

  System->piGI->GetTextHeight (i, console_font);
  i += 2;
  LineMax = (System->FrameHeight / i) - 2;
  LineSize = (System->FrameWidth / 4) + 1;

  if (LineMessageMax <= 0)
    LineMessageMax = 1;
  else if (LineMessageMax >= LineMax)
    LineMessageMax = LineMax-1;

  CHK (LineMessage = new char * [LineMessageMax]);
  CHK (LinesChanged = new bool [LineMessageMax]);
  for (i = 0; i < LineMessageMax; i++)
  {
    CHK (LineMessage [i] = new char [SIZE_LINE]);
    LineMessage [i][0] = '\0';
    LinesChanged [i] = true;
  }
  LineMessageNumber = 0;

  CHK (Line = new char * [LineMax]);
  for (i = 0; i < LineMax; i++)
  {
    CHK (Line [i] = new char [SIZE_LINE]);
    Line [i][0] = '\0';
  }
  LineNumber = 0;

  CHK (LineCommand = new char [SIZE_LINE]);
  LineCommand [0] = '\0';
  LineCommandMax = SIZE_LINE - 1;
  LineCommandCount = 0;

  CHK (History = new char * [HistoryMax]);
  for (i = 0; i < HistoryMax; i++)
  {
    CHK (History [i] = new char[SIZE_LINE]);
    History [i][0] = '\0';
  }
  HistoryCount = 0;
  HistoryCurrent = 0;

  LineTime = System->Time ();
  ConsoleMode = MESSAGE_MODE;
  CursorState = false;
  CursorTime = System->Time ();
}

csSimpleConsole::~csSimpleConsole ()
{
  int i;

  for (i = 0; i < LineMessageMax; i++)
    CHKB (delete [] LineMessage [i]);
  CHK (delete [] LineMessage);

  if (Line)
  {
    for (i = 0; i < LineMax; i++)
      CHKB (delete [] Line [i]);
    CHK (delete [] Line);
  }

  if (History)
  {
    for (i = 0; i < HistoryMax; i++)
      CHKB (delete [] History [i]);
    CHK (delete [] History);
  }

  CHK (delete [] LineCommand);
  CHK (delete [] LinesChanged);
}

void csSimpleConsole::SetTransparent (int t)
{
  if (t == -1)
    console_transparent_bg = config->GetYesNo ("SimpleConsole", "TRANSPBG", 1);
  else
    console_transparent_bg = t;
}

void csSimpleConsole::SetMaxLines (int ml)
{
  int i;

  // First remove the old messages
  for (i = 0; i < LineMessageMax; i++)
    CHKB (delete [] LineMessage[i]);
  CHK (delete [] LineMessage);

  CHK (delete [] LinesChanged);

  if (ml == -1)
    LineMessageMax = config->GetInt ("SimpleConsole", "LINEMAX", 4);
  else
    LineMessageMax = ml;
  if (LineMessageMax >= LineMax)
    LineMessageMax = LineMax-1;

  // Allocate new messages.
  CHK (LineMessage = new char * [LineMessageMax]);
  CHK (LinesChanged = new bool [LineMessageMax]);
  for (i = 0; i < LineMessageMax; i++)
  {
    CHK (LineMessage [i] = new char [SIZE_LINE]);
    LineMessage [i][0] = '\0';
    LinesChanged[i] = true;
  }
  LineMessageNumber = 0;
}

void csSimpleConsole::Show ()
{
  ConsoleMode = CONSOLE_MODE;
}

void csSimpleConsole::Hide ()
{
  Gfx2D->ClearAll (0);
  ConsoleMode = MESSAGE_MODE;
}

void csSimpleConsole::PutMessage (bool advance, char *str,...)
{
  va_list arg;
  char buf[256];

  va_start (arg, str);
  vsprintf (buf, str, arg);
  va_end (arg);

  if (LineMessageNumber >= LineMessageMax)
  {
    for (int i = 1; i < LineMessageMax; i++)
    {
      strcpy (LineMessage [i - 1], LineMessage [i]);
      LinesChanged [i - 1] = true;
    }
    LineMessageNumber--;
  }

  strncpy (LineMessage [LineMessageNumber], buf, SIZE_LINE - 1);
  LinesChanged [LineMessageNumber] = true;

  LineTime = System->Time () + 4000;
  if (advance)
    LineMessageNumber++;
}

void csSimpleConsole::PutText (char *str,...)
{
  va_list arg;
  char buf[256];

  va_start (arg, str);
  vsprintf (buf, str, arg);
  va_end (arg);

  if(!buf[0])
    return;

  int len = strlen (Line[LineNumber]);
  char* dst = Line[LineNumber] + len;
  char const* src = buf;
  for (char c = *src; c != '\0'; c = *++src)
  {
    if (c == '\b')
    {
      if (len != 0)
      {
        dst--;
        len--;
      }
    }
    else if (c == '\n')
    {
      *dst = '\0';
      PutMessage (true, "%s", Line[LineNumber]);
      if (LineNumber + 1 < LineMax)
        LineNumber++;
      else
      {
        for (int i = 1; i < LineMax; i++)
          strcpy (Line[i - 1], Line[i]);
      }
      dst = Line[LineNumber];
      *dst = '\0';
      len = 0;
    }
    else if (len < SIZE_LINE - 1)
    {
      *dst++ = c;
      len++;
    } /* endif */
  } /* endfor */

  if (len != 0)
  {
    *dst = '\0';
    PutMessage (false, "%s", Line[LineNumber]);
  }
}

void csSimpleConsole::ExecuteCommand (char *command)
{
  PutText ("cs# %s\n", command);
  if (command && command[0] != '\0')
  {
    if (command_handler == 0 || !command_handler->PerformLine (command))
      PutText ("Unknown command: %s\n", command);

    if (HistoryCount > HistoryMax - 2)
    {
      for (int i = 0; i < (HistoryMax - 2); i++)
        strcpy (History[i], History[i + 1]);
      strncpy (History[HistoryMax - 2], command, SIZE_LINE - 1);
    } else
    {
      strncpy (History[HistoryCount], command, SIZE_LINE - 1);
      HistoryCount++;
    }
  }
}

void csSimpleConsole::Clear ()
{
  LineCommandCount = 0;
  LineMessageNumber = 0;
  LineNumber = 0;
  Line [LineNumber][0] = '\0';

  for (int i = 0; i < LineMessageMax; i++)
  {
    LineMessage [i][0] = '\0';
    LinesChanged [i] = true;
  }
}

void csSimpleConsole::Print (csRect* area)
{
  int i;
  long CurrentTime = System->Time ();

  Gfx2D->SetFontID (console_font);

#define WRITE(x,y,fc,bc,s,changed)				\
  {								\
    Gfx2D->Write (x, y, fc, bc, s);				\
    if ((changed) && area)					\
    {								\
      int tw;							\
      System->piGI->GetTextWidth (tw, console_font, s);		\
      area->Union (x, y, x + tw, y + th);			\
    }								\
  }

#define WRITE2(x,y,fc,bc,s,changed)				\
  {								\
    Gfx2D->Write (x + 1, y + 1, bc, -1, s);			\
    Gfx2D->Write (x, y, fc, -1, s);				\
    if ((changed) && area)					\
    {								\
      int tw;							\
      System->piGI->GetTextWidth (tw, console_font, s);		\
      area->Union (x, y, x + 1 + tw, y + 1 + th);		\
    }								\
  }

  // text height
  int th;
  System->piGI->GetTextHeight (th, console_font);
  th += 2;

  bool dblbuff;
  Gfx2D->GetDoubleBufferState (dblbuff);

  switch (ConsoleMode)
  {
    case MESSAGE_MODE:
    {
      if (CurrentTime > LineTime)
      {
        // Scroll all lines up once per four seconds
        for (i = 1; i < LineMessageMax; i++)
        {
          strcpy (LineMessage [i - 1], LineMessage [i]);
          LinesChanged [i - 1] = true;
        }
        if (LineMessageNumber > 0)
          LineMessageNumber--;
        LineMessage [LineMessageMax - 1][0] = '\0';
        LinesChanged [LineMessageMax - 1] = true;
        LineTime = System->Time () + 4000;
      }
      for (i = 0; i < LineMessageMax; i++)
      {
        WRITE2 (10, 10 + th * i, console_fg, console_bg, LineMessage [i],
	  dblbuff || LinesChanged [i]);
	LinesChanged [i] = false;
      }
      break;
    }
    case CONSOLE_MODE:
    {
      if (CurrentTime > CursorTime)
      {
        CursorState = !CursorState;
        CursorTime = System->Time () + 333;
      }

      char buf [256];
      sprintf (buf, CursorState ? "cs# %s_" : "cs# %s",  LineCommand);

      int const lastline = strlen (Line[LineNumber]) == 0 ?
	 LineNumber : LineNumber + 1; // Account for partial lines.

      if (console_transparent_bg)
      {
        for (i = 0; i < lastline; i++)
          WRITE2 (1, th * i, console_fg, console_bg, Line [i], dblbuff);
        WRITE2 (1, th * lastline, console_fg, console_bg, buf, dblbuff);
      }
      else
      {
        Gfx2D->Clear (console_bg);
        if (dblbuff && area)
          area->Union (0, 0, System->FrameWidth - 1, System->FrameHeight - 1);
        for (i = 0; i < lastline; i++)
          WRITE (1, th * i, console_fg, -1, Line [i], false);
        WRITE (1, th * lastline, console_fg, -1, buf, false);
      }
      break;
    }
  }
}

void csSimpleConsole::AddChar (int c)
{
  switch (c)
  {
    case CSKEY_TAB:
      Hide ();
      break;

    case CSKEY_ENTER:
      ExecuteCommand (LineCommand);
      LineCommand[0] = '\0';
      LineCommandCount = 0;
      HistoryCurrent = HistoryCount;
      break;

    case CSKEY_BACKSPACE:
      if (LineCommandCount >= 0)
        LineCommand[--LineCommandCount] = '\0';
      break;

    case CSKEY_DOWN:
      if (HistoryCurrent < HistoryCount)
        HistoryCurrent++;
      strcpy (LineCommand, History[HistoryCurrent]);
      LineCommandCount = strlen (LineCommand);
      break;

    case CSKEY_UP:
      if (HistoryCurrent > 0)
        HistoryCurrent--;
      strcpy (LineCommand, History[HistoryCurrent]);
      LineCommandCount = strlen (LineCommand);
      break;

    default:
      if (c >= ' ' && c < 256)
        if (LineCommandCount < LineCommandMax)
        {
          LineCommand[LineCommandCount++] = c;
          LineCommand[LineCommandCount] = '\0';
        }
      break;
  }
}

void csSimpleConsole::SetupColors (ITextureManager* txtmgr)
{
  txtmgr->FindRGB (console_fg_r, console_fg_g, console_fg_b, console_fg);
  txtmgr->FindRGB (console_bg_r, console_bg_g, console_bg_b, console_bg);
}
<commit_msg>If I run Walktest and other apps that use the graphical console in a resolution like 320x240 or 400x300, a lot of console messages won't fit the screen width.  This led me to decide that the font selection should be based on having at least 80 columns of text - instead of being based on the area of the screen.<commit_after>/*
    Simple Console
    Copyright (C) 1998 by Jorrit Tyberghein

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "sysdef.h"
#include "cssys/system.h"
#include "cssys/sysdriv.h"
#include "cstools/simpcons.h"
#include "csinput/csinput.h"
#include "csutil/csrect.h"
#include "csutil/inifile.h"
#include "igraph2d.h"
#include "itxtmgr.h"

#define SIZE_LINE	256
#define SIZE_HISTORY	32

#define Gfx2D System->piG2D

void GfxWrite (int x, int y, int fg, int bg, char *str, ...)
{
  va_list arg;
  char buf[256];

  va_start (arg, str);
  vsprintf (buf, str, arg);
  va_end (arg);

  Gfx2D->Write (x, y, fg, bg, buf);
}

csSimpleConsole::csSimpleConsole (csIniFile *iConfig, csSimpleCommand* pc) : command_handler(pc)
{
  config = iConfig;
  LineMessageMax = config->GetInt ("SimpleConsole", "LINEMAX", 4);
  HistoryMax = config->GetInt ("SimpleConsole", "LINEHISTORY", SIZE_HISTORY);
  console_transparent_bg = config->GetYesNo ("SimpleConsole", "TRANSPBG", 1);
  char *buf = config->GetStr ("SimpleConsole", "CONFG", "255,255,255");
  sscanf (buf, "%d,%d,%d", &console_fg_r, &console_fg_g, &console_fg_b);
  buf = config->GetStr ("SimpleConsole", "CONBG", "0,0,0");
  sscanf (buf, "%d,%d,%d", &console_bg_r, &console_bg_g, &console_bg_b);
  buf = config->GetStr ("SimpleConsole", "CONFONT", "auto");
  if (!strcasecmp (buf, "auto"))
  {
    // choose a font that allows at least 80 columns of text
    if (System->FrameWidth <= 560)
      console_font = csFontTiny;
    else if (System->FrameWidth <= 640)
      console_font = csFontCourier;
    else
      console_font = csFontPolice;
  }
  else if (!strcasecmp (buf, "tiny"))
    console_font = csFontTiny;
  else if (!strcasecmp (buf, "courier"))
    console_font = csFontCourier;
  else if (!strcasecmp (buf, "police"))
    console_font = csFontPolice;
  else
  {
    System->Printf (MSG_FATAL_ERROR, "Bad value for CONFONT in configuration "
      "file.\nUse 'auto', 'tiny', 'courier', or 'police'\n");
    fatal_exit (0, false);
  }

  int i;

  System->piGI->GetTextHeight (i, console_font);
  i += 2;
  LineMax = (System->FrameHeight / i) - 2;
  LineSize = (System->FrameWidth / 4) + 1;

  if (LineMessageMax <= 0)
    LineMessageMax = 1;
  else if (LineMessageMax >= LineMax)
    LineMessageMax = LineMax-1;

  CHK (LineMessage = new char * [LineMessageMax]);
  CHK (LinesChanged = new bool [LineMessageMax]);
  for (i = 0; i < LineMessageMax; i++)
  {
    CHK (LineMessage [i] = new char [SIZE_LINE]);
    LineMessage [i][0] = '\0';
    LinesChanged [i] = true;
  }
  LineMessageNumber = 0;

  CHK (Line = new char * [LineMax]);
  for (i = 0; i < LineMax; i++)
  {
    CHK (Line [i] = new char [SIZE_LINE]);
    Line [i][0] = '\0';
  }
  LineNumber = 0;

  CHK (LineCommand = new char [SIZE_LINE]);
  LineCommand [0] = '\0';
  LineCommandMax = SIZE_LINE - 1;
  LineCommandCount = 0;

  CHK (History = new char * [HistoryMax]);
  for (i = 0; i < HistoryMax; i++)
  {
    CHK (History [i] = new char[SIZE_LINE]);
    History [i][0] = '\0';
  }
  HistoryCount = 0;
  HistoryCurrent = 0;

  LineTime = System->Time ();
  ConsoleMode = MESSAGE_MODE;
  CursorState = false;
  CursorTime = System->Time ();
}

csSimpleConsole::~csSimpleConsole ()
{
  int i;

  for (i = 0; i < LineMessageMax; i++)
    CHKB (delete [] LineMessage [i]);
  CHK (delete [] LineMessage);

  if (Line)
  {
    for (i = 0; i < LineMax; i++)
      CHKB (delete [] Line [i]);
    CHK (delete [] Line);
  }

  if (History)
  {
    for (i = 0; i < HistoryMax; i++)
      CHKB (delete [] History [i]);
    CHK (delete [] History);
  }

  CHK (delete [] LineCommand);
  CHK (delete [] LinesChanged);
}

void csSimpleConsole::SetTransparent (int t)
{
  if (t == -1)
    console_transparent_bg = config->GetYesNo ("SimpleConsole", "TRANSPBG", 1);
  else
    console_transparent_bg = t;
}

void csSimpleConsole::SetMaxLines (int ml)
{
  int i;

  // First remove the old messages
  for (i = 0; i < LineMessageMax; i++)
    CHKB (delete [] LineMessage[i]);
  CHK (delete [] LineMessage);

  CHK (delete [] LinesChanged);

  if (ml == -1)
    LineMessageMax = config->GetInt ("SimpleConsole", "LINEMAX", 4);
  else
    LineMessageMax = ml;
  if (LineMessageMax >= LineMax)
    LineMessageMax = LineMax-1;

  // Allocate new messages.
  CHK (LineMessage = new char * [LineMessageMax]);
  CHK (LinesChanged = new bool [LineMessageMax]);
  for (i = 0; i < LineMessageMax; i++)
  {
    CHK (LineMessage [i] = new char [SIZE_LINE]);
    LineMessage [i][0] = '\0';
    LinesChanged[i] = true;
  }
  LineMessageNumber = 0;
}

void csSimpleConsole::Show ()
{
  ConsoleMode = CONSOLE_MODE;
}

void csSimpleConsole::Hide ()
{
  Gfx2D->ClearAll (0);
  ConsoleMode = MESSAGE_MODE;
}

void csSimpleConsole::PutMessage (bool advance, char *str,...)
{
  va_list arg;
  char buf[256];

  va_start (arg, str);
  vsprintf (buf, str, arg);
  va_end (arg);

  if (LineMessageNumber >= LineMessageMax)
  {
    for (int i = 1; i < LineMessageMax; i++)
    {
      strcpy (LineMessage [i - 1], LineMessage [i]);
      LinesChanged [i - 1] = true;
    }
    LineMessageNumber--;
  }

  strncpy (LineMessage [LineMessageNumber], buf, SIZE_LINE - 1);
  LinesChanged [LineMessageNumber] = true;

  LineTime = System->Time () + 4000;
  if (advance)
    LineMessageNumber++;
}

void csSimpleConsole::PutText (char *str,...)
{
  va_list arg;
  char buf[256];

  va_start (arg, str);
  vsprintf (buf, str, arg);
  va_end (arg);

  if(!buf[0])
    return;

  int len = strlen (Line[LineNumber]);
  char* dst = Line[LineNumber] + len;
  char const* src = buf;
  for (char c = *src; c != '\0'; c = *++src)
  {
    if (c == '\b')
    {
      if (len != 0)
      {
        dst--;
        len--;
      }
    }
    else if (c == '\n')
    {
      *dst = '\0';
      PutMessage (true, "%s", Line[LineNumber]);
      if (LineNumber + 1 < LineMax)
        LineNumber++;
      else
      {
        for (int i = 1; i < LineMax; i++)
          strcpy (Line[i - 1], Line[i]);
      }
      dst = Line[LineNumber];
      *dst = '\0';
      len = 0;
    }
    else if (len < SIZE_LINE - 1)
    {
      *dst++ = c;
      len++;
    } /* endif */
  } /* endfor */

  if (len != 0)
  {
    *dst = '\0';
    PutMessage (false, "%s", Line[LineNumber]);
  }
}

void csSimpleConsole::ExecuteCommand (char *command)
{
  PutText ("cs# %s\n", command);
  if (command && command[0] != '\0')
  {
    if (command_handler == 0 || !command_handler->PerformLine (command))
      PutText ("Unknown command: %s\n", command);

    if (HistoryCount > HistoryMax - 2)
    {
      for (int i = 0; i < (HistoryMax - 2); i++)
        strcpy (History[i], History[i + 1]);
      strncpy (History[HistoryMax - 2], command, SIZE_LINE - 1);
    } else
    {
      strncpy (History[HistoryCount], command, SIZE_LINE - 1);
      HistoryCount++;
    }
  }
}

void csSimpleConsole::Clear ()
{
  LineCommandCount = 0;
  LineMessageNumber = 0;
  LineNumber = 0;
  Line [LineNumber][0] = '\0';

  for (int i = 0; i < LineMessageMax; i++)
  {
    LineMessage [i][0] = '\0';
    LinesChanged [i] = true;
  }
}

void csSimpleConsole::Print (csRect* area)
{
  int i;
  long CurrentTime = System->Time ();

  Gfx2D->SetFontID (console_font);

#define WRITE(x,y,fc,bc,s,changed)				\
  {								\
    Gfx2D->Write (x, y, fc, bc, s);				\
    if ((changed) && area)					\
    {								\
      int tw;							\
      System->piGI->GetTextWidth (tw, console_font, s);		\
      area->Union (x, y, x + tw, y + th);			\
    }								\
  }

#define WRITE2(x,y,fc,bc,s,changed)				\
  {								\
    Gfx2D->Write (x + 1, y + 1, bc, -1, s);			\
    Gfx2D->Write (x, y, fc, -1, s);				\
    if ((changed) && area)					\
    {								\
      int tw;							\
      System->piGI->GetTextWidth (tw, console_font, s);		\
      area->Union (x, y, x + 1 + tw, y + 1 + th);		\
    }								\
  }

  // text height
  int th;
  System->piGI->GetTextHeight (th, console_font);
  th += 2;

  bool dblbuff;
  Gfx2D->GetDoubleBufferState (dblbuff);

  switch (ConsoleMode)
  {
    case MESSAGE_MODE:
    {
      if (CurrentTime > LineTime)
      {
        // Scroll all lines up once per four seconds
        for (i = 1; i < LineMessageMax; i++)
        {
          strcpy (LineMessage [i - 1], LineMessage [i]);
          LinesChanged [i - 1] = true;
        }
        if (LineMessageNumber > 0)
          LineMessageNumber--;
        LineMessage [LineMessageMax - 1][0] = '\0';
        LinesChanged [LineMessageMax - 1] = true;
        LineTime = System->Time () + 4000;
      }
      for (i = 0; i < LineMessageMax; i++)
      {
        WRITE2 (10, 10 + th * i, console_fg, console_bg, LineMessage [i],
	  dblbuff || LinesChanged [i]);
	LinesChanged [i] = false;
      }
      break;
    }
    case CONSOLE_MODE:
    {
      if (CurrentTime > CursorTime)
      {
        CursorState = !CursorState;
        CursorTime = System->Time () + 333;
      }

      char buf [256];
      sprintf (buf, CursorState ? "cs# %s_" : "cs# %s",  LineCommand);

      int const lastline = strlen (Line[LineNumber]) == 0 ?
	 LineNumber : LineNumber + 1; // Account for partial lines.

      if (console_transparent_bg)
      {
        for (i = 0; i < lastline; i++)
          WRITE2 (1, th * i, console_fg, console_bg, Line [i], dblbuff);
        WRITE2 (1, th * lastline, console_fg, console_bg, buf, dblbuff);
      }
      else
      {
        Gfx2D->Clear (console_bg);
        if (dblbuff && area)
          area->Union (0, 0, System->FrameWidth - 1, System->FrameHeight - 1);
        for (i = 0; i < lastline; i++)
          WRITE (1, th * i, console_fg, -1, Line [i], false);
        WRITE (1, th * lastline, console_fg, -1, buf, false);
      }
      break;
    }
  }
}

void csSimpleConsole::AddChar (int c)
{
  switch (c)
  {
    case CSKEY_TAB:
      Hide ();
      break;

    case CSKEY_ENTER:
      ExecuteCommand (LineCommand);
      LineCommand[0] = '\0';
      LineCommandCount = 0;
      HistoryCurrent = HistoryCount;
      break;

    case CSKEY_BACKSPACE:
      if (LineCommandCount >= 0)
        LineCommand[--LineCommandCount] = '\0';
      break;

    case CSKEY_DOWN:
      if (HistoryCurrent < HistoryCount)
        HistoryCurrent++;
      strcpy (LineCommand, History[HistoryCurrent]);
      LineCommandCount = strlen (LineCommand);
      break;

    case CSKEY_UP:
      if (HistoryCurrent > 0)
        HistoryCurrent--;
      strcpy (LineCommand, History[HistoryCurrent]);
      LineCommandCount = strlen (LineCommand);
      break;

    default:
      if (c >= ' ' && c < 256)
        if (LineCommandCount < LineCommandMax)
        {
          LineCommand[LineCommandCount++] = c;
          LineCommand[LineCommandCount] = '\0';
        }
      break;
  }
}

void csSimpleConsole::SetupColors (ITextureManager* txtmgr)
{
  txtmgr->FindRGB (console_fg_r, console_fg_g, console_fg_b, console_fg);
  txtmgr->FindRGB (console_bg_r, console_bg_g, console_bg_b, console_bg);
}
<|endoftext|>


<commit_before><commit_msg>A comment that I will need to act on.<commit_after><|endoftext|>