<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/browser_action_view.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/commands/command_service_factory.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/browser_actions_container.h"
#include "chrome/browser/ui/views/toolbar_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skbitmap_operations.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"

using extensions::Extension;

namespace {

// Return a more transparent |image|, with 25% of its original opacity.
SkBitmap MakeTransparent(const SkBitmap& image) {
  SkBitmap alpha;
  alpha.setConfig(SkBitmap::kARGB_8888_Config, image.width(), image.height());
  alpha.allocPixels();
  alpha.eraseColor(SkColorSetARGB(64, 0, 0, 0));

  return SkBitmapOperations::CreateMaskedBitmap(image, alpha);
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// BrowserActionButton

BrowserActionButton::BrowserActionButton(const Extension* extension,
                                         BrowserActionsContainer* panel)
    : ALLOW_THIS_IN_INITIALIZER_LIST(
          MenuButton(this, string16(), NULL, false)),
      browser_action_(extension->browser_action()),
      extension_(extension),
      ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)),
      panel_(panel),
      context_menu_(NULL) {
  set_border(NULL);
  set_alignment(TextButton::ALIGN_CENTER);
  set_context_menu_controller(this);

  // No UpdateState() here because View hierarchy not setup yet. Our parent
  // should call UpdateState() after creation.

  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
                 content::Source<ExtensionAction>(browser_action_));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
                 content::Source<Profile>(
                     panel_->profile()->GetOriginalProfile()));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
                 content::Source<Profile>(
                     panel_->profile()->GetOriginalProfile()));
}

void BrowserActionButton::Destroy() {
  MaybeUnregisterExtensionCommand(false);

  if (context_menu_) {
    context_menu_->Cancel();
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
  } else {
    delete this;
  }
}

void BrowserActionButton::ViewHierarchyChanged(
    bool is_add, View* parent, View* child) {
  if (is_add && child == this) {
    // The Browser Action API does not allow the default icon path to be
    // changed at runtime, so we can load this now and cache it.
    std::string relative_path = browser_action_->default_icon_path();
    if (!relative_path.empty()) {
      // LoadImage is not guaranteed to be synchronous, so we might see the
      // callback OnImageLoaded execute immediately. It (through UpdateState)
      // expects parent() to return the owner for this button, so this
      // function is as early as we can start this request.
      tracker_.LoadImage(extension_, extension_->GetResource(relative_path),
                         gfx::Size(Extension::kBrowserActionIconMaxSize,
                                   Extension::kBrowserActionIconMaxSize),
                         ImageLoadingTracker::DONT_CACHE);
    } else {
      // Set the icon to be the default extensions icon.
      default_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
          IDR_EXTENSIONS_FAVICON).ToSkBitmap();
      UpdateState();
    }

    MaybeRegisterExtensionCommand();
  }

  MenuButton::ViewHierarchyChanged(is_add, parent, child);
}

bool BrowserActionButton::CanHandleAccelerators() const {
  // View::CanHandleAccelerators() checks to see if the view is visible before
  // allowing it to process accelerators. This is not appropriate for browser
  // actions buttons, which can be hidden inside the overflow area.
  return true;
}

void BrowserActionButton::ButtonPressed(views::Button* sender,
                                        const views::Event& event) {
  panel_->OnBrowserActionExecuted(this);
}

void BrowserActionButton::ShowContextMenuForView(View* source,
                                                 const gfx::Point& point) {
  if (!extension()->ShowConfigureContextMenus())
    return;

  SetButtonPushed();

  // Reconstructs the menu every time because the menu's contents are dynamic.
  scoped_refptr<ExtensionContextMenuModel> context_menu_contents_(
      new ExtensionContextMenuModel(extension(), panel_->browser()));
  views::MenuModelAdapter menu_model_adapter(context_menu_contents_.get());
  views::MenuRunner menu_runner(menu_model_adapter.CreateMenu());

  context_menu_ = menu_runner.GetMenu();
  gfx::Point screen_loc;
  views::View::ConvertPointToScreen(this, &screen_loc);
  if (menu_runner.RunMenuAt(GetWidget(), NULL, gfx::Rect(screen_loc, size()),
          views::MenuItemView::TOPLEFT, views::MenuRunner::HAS_MNEMONICS) ==
      views::MenuRunner::MENU_DELETED)
    return;

  SetButtonNotPushed();
  context_menu_ = NULL;
}

void BrowserActionButton::OnImageLoaded(const gfx::Image& image,
                                        const std::string& extension_id,
                                        int index) {
  if (!image.IsEmpty())
    default_icon_ = *image.ToSkBitmap();

  // Call back to UpdateState() because a more specific icon might have been set
  // while the load was outstanding.
  UpdateState();
}

void BrowserActionButton::UpdateState() {
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id < 0)
    return;

  if (!IsEnabled(tab_id)) {
    SetState(views::CustomButton::BS_DISABLED);
  } else {
    SetState(menu_visible_ ?
             views::CustomButton::BS_NORMAL :
             views::CustomButton::BS_PUSHED);
  }

  SkBitmap icon(browser_action()->GetIcon(tab_id));
  if (icon.isNull())
    icon = default_icon_;
  if (!icon.isNull()) {
    if (!browser_action()->GetIsVisible(tab_id))
      icon = MakeTransparent(icon);
    SkPaint paint;
    paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

    SkBitmap bg;
    rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg,
        SkBitmap::kARGB_8888_Config);
    SkCanvas bg_canvas(bg);
    bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2),
        SkIntToScalar((bg.height() - icon.height()) / 2), &paint);
    SetIcon(bg);

    SkBitmap bg_h;
    rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h,
        SkBitmap::kARGB_8888_Config);
    SkCanvas bg_h_canvas(bg_h);
    bg_h_canvas.drawBitmap(icon,
        SkIntToScalar((bg_h.width() - icon.width()) / 2),
        SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint);
    SetHoverIcon(bg_h);

    SkBitmap bg_p;
    rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p,
        SkBitmap::kARGB_8888_Config);
    SkCanvas bg_p_canvas(bg_p);
    bg_p_canvas.drawBitmap(icon,
        SkIntToScalar((bg_p.width() - icon.width()) / 2),
        SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint);
    SetPushedIcon(bg_p);
  }

  // If the browser action name is empty, show the extension name instead.
  string16 name = UTF8ToUTF16(browser_action()->GetTitle(tab_id));
  if (name.empty())
    name = UTF8ToUTF16(extension()->name());
  SetTooltipText(name);
  SetAccessibleName(name);

  parent()->SchedulePaint();
}

bool BrowserActionButton::IsPopup() {
  int tab_id = panel_->GetCurrentTabId();
  return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id);
}

GURL BrowserActionButton::GetPopupUrl() {
  int tab_id = panel_->GetCurrentTabId();
  return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id);
}

void BrowserActionButton::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED:
      UpdateState();
      // The browser action may have become visible/hidden so we need to make
      // sure the state gets updated.
      panel_->OnBrowserActionVisibilityChanged();
      break;
    case chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED:
    case chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
      std::pair<const std::string, const std::string>* payload =
          content::Details<std::pair<const std::string, const std::string> >(
              details).ptr();
      if (extension_->id() == payload->first &&
          payload->second ==
              extension_manifest_values::kBrowserActionKeybindingEvent) {
        if (type == chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED)
          MaybeRegisterExtensionCommand();
        else
          MaybeUnregisterExtensionCommand(true);
      }
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}

bool BrowserActionButton::Activate() {
  if (!IsPopup())
    return true;

  panel_->OnBrowserActionExecuted(this);

  // TODO(erikkay): Run a nested modal loop while the mouse is down to
  // enable menu-like drag-select behavior.

  // The return value of this method is returned via OnMousePressed.
  // We need to return false here since we're handing off focus to another
  // widget/view, and true will grab it right back and try to send events
  // to us.
  return false;
}

bool BrowserActionButton::OnMousePressed(const views::MouseEvent& event) {
  if (!event.IsRightMouseButton()) {
    return IsPopup() ? MenuButton::OnMousePressed(event)
                     : TextButton::OnMousePressed(event);
  }

  // See comments in MenuButton::Activate() as to why this is needed.
  SetMouseHandler(NULL);

  ShowContextMenu(gfx::Point(), true);
  return false;
}

void BrowserActionButton::OnMouseReleased(const views::MouseEvent& event) {
  if (IsPopup() || context_menu_) {
    // TODO(erikkay) this never actually gets called (probably because of the
    // loss of focus).
    MenuButton::OnMouseReleased(event);
  } else {
    TextButton::OnMouseReleased(event);
  }
}

void BrowserActionButton::OnMouseExited(const views::MouseEvent& event) {
  if (IsPopup() || context_menu_)
    MenuButton::OnMouseExited(event);
  else
    TextButton::OnMouseExited(event);
}

bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& event) {
  return IsPopup() ? MenuButton::OnKeyReleased(event)
                   : TextButton::OnKeyReleased(event);
}

bool BrowserActionButton::AcceleratorPressed(
    const ui::Accelerator& accelerator) {
  panel_->OnBrowserActionExecuted(this);
  return true;
}

void BrowserActionButton::SetButtonPushed() {
  SetState(views::CustomButton::BS_PUSHED);
  menu_visible_ = true;
}

void BrowserActionButton::SetButtonNotPushed() {
  SetState(views::CustomButton::BS_NORMAL);
  menu_visible_ = false;
}

bool BrowserActionButton::IsEnabled(int tab_id) const {
  return browser_action_->GetIsVisible(tab_id);
}

BrowserActionButton::~BrowserActionButton() {
}

void BrowserActionButton::MaybeRegisterExtensionCommand() {
  extensions::CommandService* command_service =
      extensions::CommandServiceFactory::GetForProfile(
          panel_->browser()->profile());
  extensions::Command browser_action_command;
  if (command_service->GetBrowserActionCommand(
          extension_->id(),
          extensions::CommandService::ACTIVE_ONLY,
          &browser_action_command,
          NULL)) {
    keybinding_.reset(new ui::Accelerator(
        browser_action_command.accelerator()));
    panel_->GetFocusManager()->RegisterAccelerator(
        *keybinding_.get(), ui::AcceleratorManager::kHighPriority, this);
  }
}

void BrowserActionButton::MaybeUnregisterExtensionCommand(bool only_if_active) {
  if (!keybinding_.get() || !panel_->GetFocusManager())
    return;

  extensions::CommandService* command_service =
      extensions::CommandServiceFactory::GetForProfile(
          panel_->browser()->profile());

  extensions::Command browser_action_command;
  if (!only_if_active || !command_service->GetBrowserActionCommand(
          extension_->id(),
          extensions::CommandService::ACTIVE_ONLY,
          &browser_action_command,
          NULL)) {
    panel_->GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this);
  }
}

////////////////////////////////////////////////////////////////////////////////
// BrowserActionView

BrowserActionView::BrowserActionView(const Extension* extension,
                                     BrowserActionsContainer* panel)
    : panel_(panel) {
  button_ = new BrowserActionButton(extension, panel);
  button_->set_drag_controller(panel_);
  AddChildView(button_);
  button_->UpdateState();
}

BrowserActionView::~BrowserActionView() {
  RemoveChildView(button_);
  button_->Destroy();
}

gfx::Canvas* BrowserActionView::GetIconWithBadge() {
  int tab_id = panel_->GetCurrentTabId();

  SkBitmap icon = button_->extension()->browser_action()->GetIcon(tab_id);
  if (icon.isNull())
    icon = button_->default_icon();

  // Dim the icon if our button is disabled.
  if (!button_->IsEnabled(tab_id))
    icon = MakeTransparent(icon);

  gfx::Canvas* canvas =
      new gfx::Canvas(gfx::ImageSkiaRep(icon, ui::SCALE_FACTOR_100P), false);

  if (tab_id >= 0) {
    gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing);
    button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id);
  }

  return canvas;
}

void BrowserActionView::Layout() {
  // We can't rely on button_->GetPreferredSize() here because that's not set
  // correctly until the first call to
  // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be
  // called before that when the initial bounds are set (and then not after,
  // since the bounds don't change).  So instead of setting the height from the
  // button's preferred size, we use IconHeight(), since that's how big the
  // button should be regardless of what it's displaying.
  button_->SetBounds(0, ToolbarView::kVertSpacing, width(),
                     BrowserActionsContainer::IconHeight());
}

void BrowserActionView::GetAccessibleState(ui::AccessibleViewState* state) {
  state->name = l10n_util::GetStringUTF16(
      IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION);
  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
}

void BrowserActionView::PaintChildren(gfx::Canvas* canvas) {
  View::PaintChildren(canvas);
  ExtensionAction* action = button()->browser_action();
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id >= 0)
    action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id);
}
<commit_msg>Fixed browser action button pushedness on views.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/browser_action_view.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/commands/command_service_factory.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/browser_actions_container.h"
#include "chrome/browser/ui/views/toolbar_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skbitmap_operations.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"

using extensions::Extension;

namespace {

// Return a more transparent |image|, with 25% of its original opacity.
SkBitmap MakeTransparent(const SkBitmap& image) {
  SkBitmap alpha;
  alpha.setConfig(SkBitmap::kARGB_8888_Config, image.width(), image.height());
  alpha.allocPixels();
  alpha.eraseColor(SkColorSetARGB(64, 0, 0, 0));

  return SkBitmapOperations::CreateMaskedBitmap(image, alpha);
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// BrowserActionButton

BrowserActionButton::BrowserActionButton(const Extension* extension,
                                         BrowserActionsContainer* panel)
    : ALLOW_THIS_IN_INITIALIZER_LIST(
          MenuButton(this, string16(), NULL, false)),
      browser_action_(extension->browser_action()),
      extension_(extension),
      ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)),
      panel_(panel),
      context_menu_(NULL) {
  set_border(NULL);
  set_alignment(TextButton::ALIGN_CENTER);
  set_context_menu_controller(this);

  // No UpdateState() here because View hierarchy not setup yet. Our parent
  // should call UpdateState() after creation.

  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
                 content::Source<ExtensionAction>(browser_action_));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
                 content::Source<Profile>(
                     panel_->profile()->GetOriginalProfile()));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
                 content::Source<Profile>(
                     panel_->profile()->GetOriginalProfile()));
}

void BrowserActionButton::Destroy() {
  MaybeUnregisterExtensionCommand(false);

  if (context_menu_) {
    context_menu_->Cancel();
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
  } else {
    delete this;
  }
}

void BrowserActionButton::ViewHierarchyChanged(
    bool is_add, View* parent, View* child) {
  if (is_add && child == this) {
    // The Browser Action API does not allow the default icon path to be
    // changed at runtime, so we can load this now and cache it.
    std::string relative_path = browser_action_->default_icon_path();
    if (!relative_path.empty()) {
      // LoadImage is not guaranteed to be synchronous, so we might see the
      // callback OnImageLoaded execute immediately. It (through UpdateState)
      // expects parent() to return the owner for this button, so this
      // function is as early as we can start this request.
      tracker_.LoadImage(extension_, extension_->GetResource(relative_path),
                         gfx::Size(Extension::kBrowserActionIconMaxSize,
                                   Extension::kBrowserActionIconMaxSize),
                         ImageLoadingTracker::DONT_CACHE);
    } else {
      // Set the icon to be the default extensions icon.
      default_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
          IDR_EXTENSIONS_FAVICON).ToSkBitmap();
      UpdateState();
    }

    MaybeRegisterExtensionCommand();
  }

  MenuButton::ViewHierarchyChanged(is_add, parent, child);
}

bool BrowserActionButton::CanHandleAccelerators() const {
  // View::CanHandleAccelerators() checks to see if the view is visible before
  // allowing it to process accelerators. This is not appropriate for browser
  // actions buttons, which can be hidden inside the overflow area.
  return true;
}

void BrowserActionButton::ButtonPressed(views::Button* sender,
                                        const views::Event& event) {
  panel_->OnBrowserActionExecuted(this);
}

void BrowserActionButton::ShowContextMenuForView(View* source,
                                                 const gfx::Point& point) {
  if (!extension()->ShowConfigureContextMenus())
    return;

  SetButtonPushed();

  // Reconstructs the menu every time because the menu's contents are dynamic.
  scoped_refptr<ExtensionContextMenuModel> context_menu_contents_(
      new ExtensionContextMenuModel(extension(), panel_->browser()));
  views::MenuModelAdapter menu_model_adapter(context_menu_contents_.get());
  views::MenuRunner menu_runner(menu_model_adapter.CreateMenu());

  context_menu_ = menu_runner.GetMenu();
  gfx::Point screen_loc;
  views::View::ConvertPointToScreen(this, &screen_loc);
  if (menu_runner.RunMenuAt(GetWidget(), NULL, gfx::Rect(screen_loc, size()),
          views::MenuItemView::TOPLEFT, views::MenuRunner::HAS_MNEMONICS) ==
      views::MenuRunner::MENU_DELETED)
    return;

  SetButtonNotPushed();
  context_menu_ = NULL;
}

void BrowserActionButton::OnImageLoaded(const gfx::Image& image,
                                        const std::string& extension_id,
                                        int index) {
  if (!image.IsEmpty())
    default_icon_ = *image.ToSkBitmap();

  // Call back to UpdateState() because a more specific icon might have been set
  // while the load was outstanding.
  UpdateState();
}

void BrowserActionButton::UpdateState() {
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id < 0)
    return;

  if (!IsEnabled(tab_id)) {
    SetState(views::CustomButton::BS_DISABLED);
  } else {
    SetState(menu_visible_ ?
             views::CustomButton::BS_PUSHED :
             views::CustomButton::BS_NORMAL);
  }

  SkBitmap icon(browser_action()->GetIcon(tab_id));
  if (icon.isNull())
    icon = default_icon_;
  if (!icon.isNull()) {
    if (!browser_action()->GetIsVisible(tab_id))
      icon = MakeTransparent(icon);
    SkPaint paint;
    paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

    SkBitmap bg;
    rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg,
        SkBitmap::kARGB_8888_Config);
    SkCanvas bg_canvas(bg);
    bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2),
        SkIntToScalar((bg.height() - icon.height()) / 2), &paint);
    SetIcon(bg);

    SkBitmap bg_h;
    rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h,
        SkBitmap::kARGB_8888_Config);
    SkCanvas bg_h_canvas(bg_h);
    bg_h_canvas.drawBitmap(icon,
        SkIntToScalar((bg_h.width() - icon.width()) / 2),
        SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint);
    SetHoverIcon(bg_h);

    SkBitmap bg_p;
    rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p,
        SkBitmap::kARGB_8888_Config);
    SkCanvas bg_p_canvas(bg_p);
    bg_p_canvas.drawBitmap(icon,
        SkIntToScalar((bg_p.width() - icon.width()) / 2),
        SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint);
    SetPushedIcon(bg_p);
  }

  // If the browser action name is empty, show the extension name instead.
  string16 name = UTF8ToUTF16(browser_action()->GetTitle(tab_id));
  if (name.empty())
    name = UTF8ToUTF16(extension()->name());
  SetTooltipText(name);
  SetAccessibleName(name);

  parent()->SchedulePaint();
}

bool BrowserActionButton::IsPopup() {
  int tab_id = panel_->GetCurrentTabId();
  return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id);
}

GURL BrowserActionButton::GetPopupUrl() {
  int tab_id = panel_->GetCurrentTabId();
  return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id);
}

void BrowserActionButton::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED:
      UpdateState();
      // The browser action may have become visible/hidden so we need to make
      // sure the state gets updated.
      panel_->OnBrowserActionVisibilityChanged();
      break;
    case chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED:
    case chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
      std::pair<const std::string, const std::string>* payload =
          content::Details<std::pair<const std::string, const std::string> >(
              details).ptr();
      if (extension_->id() == payload->first &&
          payload->second ==
              extension_manifest_values::kBrowserActionKeybindingEvent) {
        if (type == chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED)
          MaybeRegisterExtensionCommand();
        else
          MaybeUnregisterExtensionCommand(true);
      }
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}

bool BrowserActionButton::Activate() {
  if (!IsPopup())
    return true;

  panel_->OnBrowserActionExecuted(this);

  // TODO(erikkay): Run a nested modal loop while the mouse is down to
  // enable menu-like drag-select behavior.

  // The return value of this method is returned via OnMousePressed.
  // We need to return false here since we're handing off focus to another
  // widget/view, and true will grab it right back and try to send events
  // to us.
  return false;
}

bool BrowserActionButton::OnMousePressed(const views::MouseEvent& event) {
  if (!event.IsRightMouseButton()) {
    return IsPopup() ? MenuButton::OnMousePressed(event)
                     : TextButton::OnMousePressed(event);
  }

  // See comments in MenuButton::Activate() as to why this is needed.
  SetMouseHandler(NULL);

  ShowContextMenu(gfx::Point(), true);
  return false;
}

void BrowserActionButton::OnMouseReleased(const views::MouseEvent& event) {
  if (IsPopup() || context_menu_) {
    // TODO(erikkay) this never actually gets called (probably because of the
    // loss of focus).
    MenuButton::OnMouseReleased(event);
  } else {
    TextButton::OnMouseReleased(event);
  }
}

void BrowserActionButton::OnMouseExited(const views::MouseEvent& event) {
  if (IsPopup() || context_menu_)
    MenuButton::OnMouseExited(event);
  else
    TextButton::OnMouseExited(event);
}

bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& event) {
  return IsPopup() ? MenuButton::OnKeyReleased(event)
                   : TextButton::OnKeyReleased(event);
}

bool BrowserActionButton::AcceleratorPressed(
    const ui::Accelerator& accelerator) {
  panel_->OnBrowserActionExecuted(this);
  return true;
}

void BrowserActionButton::SetButtonPushed() {
  SetState(views::CustomButton::BS_PUSHED);
  menu_visible_ = true;
}

void BrowserActionButton::SetButtonNotPushed() {
  SetState(views::CustomButton::BS_NORMAL);
  menu_visible_ = false;
}

bool BrowserActionButton::IsEnabled(int tab_id) const {
  return browser_action_->GetIsVisible(tab_id);
}

BrowserActionButton::~BrowserActionButton() {
}

void BrowserActionButton::MaybeRegisterExtensionCommand() {
  extensions::CommandService* command_service =
      extensions::CommandServiceFactory::GetForProfile(
          panel_->browser()->profile());
  extensions::Command browser_action_command;
  if (command_service->GetBrowserActionCommand(
          extension_->id(),
          extensions::CommandService::ACTIVE_ONLY,
          &browser_action_command,
          NULL)) {
    keybinding_.reset(new ui::Accelerator(
        browser_action_command.accelerator()));
    panel_->GetFocusManager()->RegisterAccelerator(
        *keybinding_.get(), ui::AcceleratorManager::kHighPriority, this);
  }
}

void BrowserActionButton::MaybeUnregisterExtensionCommand(bool only_if_active) {
  if (!keybinding_.get() || !panel_->GetFocusManager())
    return;

  extensions::CommandService* command_service =
      extensions::CommandServiceFactory::GetForProfile(
          panel_->browser()->profile());

  extensions::Command browser_action_command;
  if (!only_if_active || !command_service->GetBrowserActionCommand(
          extension_->id(),
          extensions::CommandService::ACTIVE_ONLY,
          &browser_action_command,
          NULL)) {
    panel_->GetFocusManager()->UnregisterAccelerator(*keybinding_.get(), this);
  }
}

////////////////////////////////////////////////////////////////////////////////
// BrowserActionView

BrowserActionView::BrowserActionView(const Extension* extension,
                                     BrowserActionsContainer* panel)
    : panel_(panel) {
  button_ = new BrowserActionButton(extension, panel);
  button_->set_drag_controller(panel_);
  AddChildView(button_);
  button_->UpdateState();
}

BrowserActionView::~BrowserActionView() {
  RemoveChildView(button_);
  button_->Destroy();
}

gfx::Canvas* BrowserActionView::GetIconWithBadge() {
  int tab_id = panel_->GetCurrentTabId();

  SkBitmap icon = button_->extension()->browser_action()->GetIcon(tab_id);
  if (icon.isNull())
    icon = button_->default_icon();

  // Dim the icon if our button is disabled.
  if (!button_->IsEnabled(tab_id))
    icon = MakeTransparent(icon);

  gfx::Canvas* canvas =
      new gfx::Canvas(gfx::ImageSkiaRep(icon, ui::SCALE_FACTOR_100P), false);

  if (tab_id >= 0) {
    gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing);
    button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id);
  }

  return canvas;
}

void BrowserActionView::Layout() {
  // We can't rely on button_->GetPreferredSize() here because that's not set
  // correctly until the first call to
  // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be
  // called before that when the initial bounds are set (and then not after,
  // since the bounds don't change).  So instead of setting the height from the
  // button's preferred size, we use IconHeight(), since that's how big the
  // button should be regardless of what it's displaying.
  button_->SetBounds(0, ToolbarView::kVertSpacing, width(),
                     BrowserActionsContainer::IconHeight());
}

void BrowserActionView::GetAccessibleState(ui::AccessibleViewState* state) {
  state->name = l10n_util::GetStringUTF16(
      IDS_ACCNAME_EXTENSIONS_BROWSER_ACTION);
  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
}

void BrowserActionView::PaintChildren(gfx::Canvas* canvas) {
  View::PaintChildren(canvas);
  ExtensionAction* action = button()->browser_action();
  int tab_id = panel_->GetCurrentTabId();
  if (tab_id >= 0)
    action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

class Player
{
public:
	player(std::string, std::string, std::string, int, int, int);

	void setName(std::string);
	void setArea(std::string);
	void setWeapon(std::string);

	void setLevel(int);
	void setEXP(int);

	void setHealth();
	void setMaxHealth();
	void setDamage();
	void setEXP();
	void setEXPReq();

	std::string getName();
	std::string getArea();

	int getLevel();
	int getHealth();
	int getMaxHealth();
	int getDamage();
	int getEXP();
	int getEXPReq();

private:
	std::string playerName;
	std::string playerArea;
	int playerLevel;
	int playerHealth;
	int playerMaxHealth;
	int playerDamage;
	int EXP;
	int EXPreq;
};
<commit_msg>Update player.hpp<commit_after>#ifndef PLAYER_HPP
#define PLAYER_HPP

#include <iostream>

class Player
{
public:
	player(std::string, std::string, std::string, int, int, int, int);

	void setName(std::string);
	void setArea(std::string);
	void setWeapon(std::string);

	void setLevel(int);
	void setEXP(int);
	void setHealth(int);
	void setMaxHealth(int);

	void setDamage();
	void setEXP();
	void setEXPReq();

	std::string getName();
	std::string getArea();

	int getLevel();
	int getHealth();
	int getMaxHealth();
	int getDamage();
	int getEXP();
	int getEXPReq();

private:
	std::string playerName;
	std::string playerArea;
	int playerLevel;
	int playerHealth;
	int playerMaxHealth;
	int playerDamage;
	int EXP;
	int EXPreq;
};

#endif
<|endoftext|>


<commit_before>/*********************************************************************************************************
* InitializeAttribute.hpp
* Note: Phoenix InitializeFile NT Library
* Date: @2015.04
* E-mail:<forcemz@outlook.com>
* Copyright (C) 2015 The ForceStudio All Rights Reserved.
**********************************************************************************************************/
#ifndef INITIALIZEATTRIBUTE_HPP
#define INITIALIZEATTRIBUTE_HPP

#ifndef _WIN32
#error "Only Support Windows System"
#endif
#include <unordered_map>
#include <string>
#include <vector>

class InitializeStructure{
public:
    struct Section{
        std::wstring keyName;
        std::unordered_map<std::wstring,std::wstring> attrTable;
        std::unordered_map<unsigned,std::wstring> comments;
    };
    std::vector<Section*> attrVector
    ~InitializeStructure()
    {
        for(auto &i:attrVector)
        {
            if(i)
                delete i;
        }
        attrVector.clear();
    }
    std::wstring get(const wchar_t *sec,const wchar_t *key,const wchar_t *preset,int Order=0)
    {
        return preset;
    }
};

class InitializeAttribute{
private:
    std::wstring mfile;
public:
    InitializeAttribute &operator=(const InitializeAttribute &rhs){
        ///value=value
        return *this;
    }
    InitializeAttribute(const InitializeAttribute &iattr){operator=(iattr);}
    InitializeAttribute(const wchar_t *filePath):mfile(filePath)
    {
        ////
    }
};

#endif
<commit_msg>Changed InitializeStructture internal struct<commit_after>/*********************************************************************************************************
* InitializeAttribute.hpp
* Note: Phoenix InitializeFile NT Library
* Date: @2015.04
* E-mail:<forcemz@outlook.com>
* Copyright (C) 2015 The ForceStudio All Rights Reserved.
**********************************************************************************************************/
#ifndef INITIALIZEATTRIBUTE_HPP
#define INITIALIZEATTRIBUTE_HPP

#ifndef _WIN32
//#error "Only Support Windows System"
#endif
#include <unordered_map>
#include <string>
#include <map>
#include <vector>

class InitializeStructure{
private:
    bool isChanged;
public:
    struct Parameters{
        std::wstring key;
        std::wstring value;
        std::wstring comments;
        int nOrder;
        Parameters(std::wstring k,
            std::wstring v,
            std::wstring c,
            int nOrder=0):key(k),value(v),comments(c),nOrder(nOrder){ } ///////
        Parameters(){}
    };
    struct IniSection{
        typedef std::vector<Parameters>::iterator iterator;
        iterator begin(){return items.begin();}
        iterator end(){return items.end();}
        std::wstring comment;
        std::vector<Parameters> items;
    };
    std::unordered_map<std::wstring,IniSection*> attrTable;
    ~InitializeStructure()
    {
        for(auto &i:attrTable)
        {
            if(i.second)
                delete i.second;
        }
        attrTable.clear();
    }
    std::wstring get(const wchar_t *sec,const wchar_t *key,const wchar_t *preset,int Order=0)
    {
        return preset;
    }
    bool IsChanged(){return this->isChanged;}
};

class InitializeAttribute{
private:
    std::wstring mfile;
    InitializeStructure initializeStructure;
public:
    InitializeAttribute &operator=(const InitializeAttribute &rhs){
        ///value=value
        return *this;
    }
    InitializeAttribute(const InitializeAttribute &iattr){operator=(iattr);}
    InitializeAttribute(const wchar_t *filePath):mfile(filePath)
    {
        ////
    }
};

#endif
<|endoftext|>


<commit_before>#pragma once

#include <functional>

#include <cppformat/format.h>

#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
#include "blackhole/sandbox.hpp"
#endif

#include "blackhole/attributes.hpp"
#include "blackhole/cpp17/string_view.hpp"

namespace blackhole {

namespace cppformat = fmt;

class writer_t {
public:
    cppformat::MemoryWriter inner;

    template<typename... Args>
    inline auto write(const Args&... args) -> void {
        inner.write(args...);
    }
};

typedef view_of<attributes_t>::type attribute_list;

/// Logging facade wraps the underlying logger providing convenient format methods.
///
/// \tparam Logger must meet the requirements of `Logger`.
template<typename Logger>
class logger_facade {
public:
    typedef Logger wrapped_type;

private:
    std::reference_wrapper<const wrapped_type> wrapped;

public:
    constexpr explicit logger_facade(const wrapped_type& wrapped) noexcept:
        wrapped(wrapped)
    {}

    /// Log a message with the given severity level.
    auto log(int severity, string_view format) const -> void;

    /// Log a message with the given severity level and further formatting using the given pattern
    /// and arguments.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<typename T, typename... Args>
    auto log(int severity, string_view format, const T& arg, const Args&... args) const -> void;

    /// Log a message with the given severity level and attributes.
    ///
    /// \overload
    auto log(int severity, const attribute_list& attributes, string_view format) const -> void;

    /// Log a message with the given severity level and attributes and further formatting using the
    /// given pattern and arguments.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<typename T, typename... Args>
    auto log(int severity, const attribute_list& attributes, string_view format, const T& arg, const Args&... args) const -> void;

#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
    /// Log a message with the given severity level and further formatting using the given pattern
    /// and arguments.
    ///
    /// This is more fast alternative comparing with default formatting, because the given pattern
    /// string is parsed into literals during compile time.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<std::size_t N, typename T, typename... Args>
    auto log(int severity, const detail::formatter<N>& formatter, const T& arg, const Args&... args) const -> void;

    /// Log a message with the given severity level and attributes and further formatting using the
    /// given pattern and arguments.
    ///
    /// This is more fast alternative comparing with default formatting, because the given pattern
    /// string is parsed into literals during compile time.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<std::size_t N, typename T, typename... Args>
    auto log(int severity, const attribute_list& attributes, const detail::formatter<N>& formatter, const T& arg, const Args&... args) const -> void;
#endif

private:
    constexpr auto inner() const noexcept -> const wrapped_type& {
        return wrapped.get();
    }
};

namespace gcc {

/// Workaround for GCC versions up to 4.9, which fails to expand variadic pack inside lambdas.
template<class... Args>
inline void write_all(writer_t& wr, const char* pattern, const Args&... args) {
    wr.write(pattern, args...);
}

}  // namespace gcc

template<typename Logger>
inline
auto
logger_facade<Logger>::log(int severity, string_view format) const -> void {
    range_t range;
    inner().log(severity, format, range);
}

template<typename Logger>
template<typename T, typename... Args>
inline
auto
logger_facade<Logger>::log(int severity, string_view format, const T& arg, const Args&... args) const -> void {
    const auto fn = std::bind(&gcc::write_all<T, Args...>, std::placeholders::_1, format.data(), std::cref(arg), std::cref(args)...);

    range_t range;
    inner().log(severity, format, range, std::cref(fn));
}

template<typename Logger>
inline
auto
logger_facade<Logger>::log(int severity, const attribute_list& attributes, string_view format) const -> void {
    range_t range{attributes};
    inner().log(severity, format, range);
}

template<typename Logger>
template<typename T, typename... Args>
inline
auto
logger_facade<Logger>::log(int severity, const attribute_list& attributes, string_view format, const T& arg, const Args&... args) const -> void {
    const auto fn = std::bind(&gcc::write_all<T, Args...>, std::placeholders::_1, format.data(), std::cref(arg), std::cref(args)...);

    range_t range{attributes};
    inner().log(severity, format, range, std::cref(fn));
}

#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304

template<typename Logger>
template<std::size_t N, typename T, typename... Args>
inline
auto
logger_facade<Logger>::log(int severity, const detail::formatter<N>& formatter, const T& arg, const Args&... args) const -> void {
    const auto fn = [&](writer_t& wr) {
        formatter.format(wr.inner, arg, args...);
    };

    range_t range;
    inner().log(severity, "", range, std::cref(fn));
}

#endif

}  // namespace blackhole
<commit_msg>chore(facade): add planning node<commit_after>#pragma once

#include <functional>

#include <cppformat/format.h>

#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
#include "blackhole/sandbox.hpp"
#endif

#include "blackhole/attributes.hpp"
#include "blackhole/cpp17/string_view.hpp"

namespace blackhole {

namespace cppformat = fmt;

class writer_t {
public:
    cppformat::MemoryWriter inner;

    template<typename... Args>
    inline auto write(const Args&... args) -> void {
        inner.write(args...);
    }
};

typedef view_of<attributes_t>::type attribute_list;

/// Logging facade wraps the underlying logger providing convenient format methods.
///
/// \tparam Logger must meet the requirements of `Logger`.
template<typename Logger>
class logger_facade {
public:
    typedef Logger wrapped_type;

private:
    std::reference_wrapper<const wrapped_type> wrapped;

public:
    constexpr explicit logger_facade(const wrapped_type& wrapped) noexcept:
        wrapped(wrapped)
    {}

    /// Log a message with the given severity level.
    auto log(int severity, string_view format) const -> void;

    /// Log a message with the given severity level and further formatting using the given pattern
    /// and arguments.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<typename T, typename... Args>
    auto log(int severity, string_view format, const T& arg, const Args&... args) const -> void;

    /// Log a message with the given severity level and attributes.
    ///
    /// \overload
    auto log(int severity, const attribute_list& attributes, string_view format) const -> void;

    /// Log a message with the given severity level and attributes and further formatting using the
    /// given pattern and arguments.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    // TODO: Find a way to make the `attribute_list` argument last.
    template<typename T, typename... Args>
    auto log(int severity, const attribute_list& attributes, string_view format, const T& arg, const Args&... args) const -> void;

#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
    /// Log a message with the given severity level and further formatting using the given pattern
    /// and arguments.
    ///
    /// This is more fast alternative comparing with default formatting, because the given pattern
    /// string is parsed into literals during compile time.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<std::size_t N, typename T, typename... Args>
    auto log(int severity, const detail::formatter<N>& formatter, const T& arg, const Args&... args) const -> void;

    /// Log a message with the given severity level and attributes and further formatting using the
    /// given pattern and arguments.
    ///
    /// This is more fast alternative comparing with default formatting, because the given pattern
    /// string is parsed into literals during compile time.
    ///
    /// \overload
    /// \tparam T and Args... must meet the requirements of `StreamFormatted`.
    template<std::size_t N, typename T, typename... Args>
    auto log(int severity, const attribute_list& attributes, const detail::formatter<N>& formatter, const T& arg, const Args&... args) const -> void;
#endif

private:
    constexpr auto inner() const noexcept -> const wrapped_type& {
        return wrapped.get();
    }
};

namespace gcc {

/// Workaround for GCC versions up to 4.9, which fails to expand variadic pack inside lambdas.
template<class... Args>
inline void write_all(writer_t& wr, const char* pattern, const Args&... args) {
    wr.write(pattern, args...);
}

}  // namespace gcc

template<typename Logger>
inline
auto
logger_facade<Logger>::log(int severity, string_view format) const -> void {
    range_t range;
    inner().log(severity, format, range);
}

template<typename Logger>
template<typename T, typename... Args>
inline
auto
logger_facade<Logger>::log(int severity, string_view format, const T& arg, const Args&... args) const -> void {
    const auto fn = std::bind(&gcc::write_all<T, Args...>, std::placeholders::_1, format.data(), std::cref(arg), std::cref(args)...);

    range_t range;
    inner().log(severity, format, range, std::cref(fn));
}

template<typename Logger>
inline
auto
logger_facade<Logger>::log(int severity, const attribute_list& attributes, string_view format) const -> void {
    range_t range{attributes};
    inner().log(severity, format, range);
}

template<typename Logger>
template<typename T, typename... Args>
inline
auto
logger_facade<Logger>::log(int severity, const attribute_list& attributes, string_view format, const T& arg, const Args&... args) const -> void {
    const auto fn = std::bind(&gcc::write_all<T, Args...>, std::placeholders::_1, format.data(), std::cref(arg), std::cref(args)...);

    range_t range{attributes};
    inner().log(severity, format, range, std::cref(fn));
}

#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304

template<typename Logger>
template<std::size_t N, typename T, typename... Args>
inline
auto
logger_facade<Logger>::log(int severity, const detail::formatter<N>& formatter, const T& arg, const Args&... args) const -> void {
    const auto fn = [&](writer_t& wr) {
        formatter.format(wr.inner, arg, args...);
    };

    range_t range;
    inner().log(severity, "", range, std::cref(fn));
}

#endif

}  // namespace blackhole
<|endoftext|>


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

/**
 * @file mixer.cpp
 *
 * Control channel input/output mixer and failsafe.
 */

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdbool.h>
#include <string.h>

#include <drivers/drv_pwm_output.h>
#include <drivers/drv_hrt.h>

#include <systemlib/mixer/mixer.h>

extern "C" {
//#define DEBUG
#include "px4io.h"
}

/*
 * Maximum interval in us before FMU signal is considered lost
 */
#define FMU_INPUT_DROP_LIMIT_US		200000

/* XXX need to move the RC_CHANNEL_FUNCTION out of rc_channels.h and into systemlib */
#define ROLL     0
#define PITCH    1
#define YAW      2
#define THROTTLE 3
#define OVERRIDE 4

/* current servo arm/disarm state */
static bool mixer_servos_armed = false;

/* selected control values and count for mixing */
enum mixer_source {
	MIX_NONE,
	MIX_FMU,
	MIX_OVERRIDE,
	MIX_FAILSAFE
};
static mixer_source source;

static int	mixer_callback(uintptr_t handle,
			       uint8_t control_group,
			       uint8_t control_index,
			       float &control);

static MixerGroup mixer_group(mixer_callback, 0);

void
mixer_tick(void)
{
	/* check that we are receiving fresh data from the FMU */
	if ((hrt_absolute_time() - system_state.fmu_data_received_time) > FMU_INPUT_DROP_LIMIT_US) {

		/* too long without FMU input, time to go to failsafe */
		if (r_status_flags & PX4IO_P_STATUS_FLAGS_FMU_OK) {
			debug("AP RX timeout");
		}
		r_status_flags |= PX4IO_P_STATUS_FLAGS_OVERRIDE;
		r_status_flags &= ~(PX4IO_P_STATUS_FLAGS_FMU_OK | PX4IO_P_STATUS_FLAGS_RAW_PWM);
		r_status_alarms |= PX4IO_P_STATUS_ALARMS_FMU_LOST;
	}

	source = MIX_FAILSAFE;

	/*
	 * Decide which set of controls we're using.
	 */
	if (r_status_flags & PX4IO_P_STATUS_FLAGS_RAW_PWM) {

		/* don't actually mix anything - we already have raw PWM values */
		source = MIX_NONE;

	} else {

		if (!(r_status_flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) &&
		     (r_status_flags & PX4IO_P_STATUS_FLAGS_MIXER_OK)) {

			/* mix from FMU controls */
			source = MIX_FMU;
		}

		if ( (r_status_flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) &&
		     (r_status_flags & PX4IO_P_STATUS_FLAGS_RC_OK)) {

		 	/* if allowed, mix from RC inputs directly */
			source = MIX_OVERRIDE;
		}
	}

	/*
	 * Run the mixers.
	 */
	if (source == MIX_FAILSAFE) {

		/* copy failsafe values to the servo outputs */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++)
			r_page_servos[i] = r_page_servo_failsafe[i];

	} else if (source != MIX_NONE) {

		float	outputs[IO_SERVO_COUNT];
		unsigned mixed;

		/* mix */
		mixed = mixer_group.mix(&outputs[0], IO_SERVO_COUNT);

		/* scale to PWM and update the servo outputs as required */
		for (unsigned i = 0; i < mixed; i++) {

			/* save actuator values for FMU readback */
			r_page_actuators[i] = FLOAT_TO_REG(outputs[i]);

			/* scale to servo output */
			r_page_servos[i] = (outputs[i] * 500.0f) + 1500;

		}
		for (unsigned i = mixed; i < IO_SERVO_COUNT; i++)
			r_page_servos[i] = 0;
	}

#if 0
		/* if everything is ok */

		if (!system_state.mixer_manual_override && system_state.mixer_fmu_available) {
			/* we have recent control data from the FMU */
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];

		} else if (system_state.rc_channels > 0) {
			/* when override is on or the fmu is not available, but RC is present */
			control_count = system_state.rc_channels;

			sched_lock();

			/* remap roll, pitch, yaw and throttle from RC specific to internal ordering */
			rc_channel_data[ROLL]     = system_state.rc_channel_data[system_state.rc_map[ROLL] - 1];
			rc_channel_data[PITCH]    = system_state.rc_channel_data[system_state.rc_map[PITCH] - 1];
			rc_channel_data[YAW]      = system_state.rc_channel_data[system_state.rc_map[YAW] - 1];
			rc_channel_data[THROTTLE] = system_state.rc_channel_data[system_state.rc_map[THROTTLE] - 1];
			//rc_channel_data[OVERRIDE] = system_state.rc_channel_data[system_state.rc_map[OVERRIDE] - 1];

			/* get the remaining channels, no remapping needed */
			for (unsigned i = 4; i < system_state.rc_channels; i++) {
				rc_channel_data[i] = system_state.rc_channel_data[i];
			}

			/* scale the control inputs */
			rc_channel_data[THROTTLE] = ((float)(rc_channel_data[THROTTLE] - system_state.rc_min[THROTTLE]) /
				(float)(system_state.rc_max[THROTTLE] - system_state.rc_min[THROTTLE])) * 1000.0f + 1000;

			if (rc_channel_data[THROTTLE] > 2000) {
				rc_channel_data[THROTTLE] = 2000;
			}

			if (rc_channel_data[THROTTLE] < 1000) {
				rc_channel_data[THROTTLE] = 1000;
			}

			// lib_lowprintf("Tmin: %d Ttrim: %d Tmax: %d T: %d \n",
			// 	(int)(system_state.rc_min[THROTTLE]), (int)(system_state.rc_trim[THROTTLE]),
			// 	(int)(system_state.rc_max[THROTTLE]), (int)(rc_channel_data[THROTTLE]));

			control_values = &rc_channel_data[0];
			sched_unlock();
		} else {
			/* we have no control input (no FMU, no RC) */

			// XXX builtin failsafe would activate here
			control_count = 0;
		}
		//lib_lowprintf("R: %d P: %d Y: %d T: %d \n", control_values[0], control_values[1], control_values[2], control_values[3]);

	/* this is for multicopters, etc. where manual override does not make sense */
	} else {
		/* if the fmu is available whe are good */
		if (system_state.mixer_fmu_available) {
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];
		/* we better shut everything off */
		} else {
			control_count = 0;
		}
	}
#endif

	/*
	 * Decide whether the servos should be armed right now.
	 *
	 * We must be armed, and we must have a PWM source; either raw from
	 * FMU or from the mixer.
	 *
	 * XXX correct behaviour for failsafe may require an additional case
	 * here.
	 */
	bool should_arm = ((r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED) &&
		(r_status_flags & (PX4IO_P_STATUS_FLAGS_RAW_PWM | PX4IO_P_STATUS_FLAGS_MIXER_OK)));

	if (should_arm && !mixer_servos_armed) {
		/* need to arm, but not armed */
		up_pwm_servo_arm(true);
		mixer_servos_armed = true;

	} else if (!should_arm && mixer_servos_armed) {
		/* armed but need to disarm */
		up_pwm_servo_arm(false);
		mixer_servos_armed = false;
	}

	if (mixer_servos_armed) {
		/* update the servo outputs. */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++)
			up_pwm_servo_set(i, r_page_servos[i]);
	}
}

static int
mixer_callback(uintptr_t handle,
	       uint8_t control_group,
	       uint8_t control_index,
	       float &control)
{
	if (control_group != 0)
		return -1;

	switch (source) {
	case MIX_FMU:
		if (control_index < PX4IO_CONTROL_CHANNELS) {
			control = REG_TO_FLOAT(r_page_controls[control_index]);
			break;
		}
		return -1;

	case MIX_OVERRIDE:
		if (r_page_rc_input[PX4IO_P_RC_VALID] & (1 << control_index)) {
			control = REG_TO_FLOAT(r_page_rc_input[PX4IO_P_RC_BASE + control_index]);
			break;
		}
		return -1;

	case MIX_FAILSAFE:
	case MIX_NONE:
		/* XXX we could allow for configuration of per-output failsafe values */
		return -1;
	}

	return 0;
}

/*
 * XXX error handling here should be more aggressive; currently it is
 * possible to get STATUS_FLAGS_MIXER_OK set even though the mixer has
 * not loaded faithfully.
 */

static char mixer_text[256];		/* large enough for one mixer */
static unsigned mixer_text_length = 0;

void
mixer_handle_text(const void *buffer, size_t length)
{

	px4io_mixdata	*msg = (px4io_mixdata *)buffer;

	debug("mixer text %u", length);

	if (length < sizeof(px4io_mixdata))
		return;

	unsigned	text_length = length - sizeof(px4io_mixdata);

	switch (msg->action) {
	case F2I_MIXER_ACTION_RESET:
		debug("reset");
		mixer_group.reset();
		mixer_text_length = 0;
		r_status_flags &= ~PX4IO_P_STATUS_FLAGS_MIXER_OK;

		/* FALLTHROUGH */
	case F2I_MIXER_ACTION_APPEND:
		debug("append %d", length);

		/* check for overflow - this is really fatal */
		/* XXX could add just what will fit & try to parse, then repeat... */
		if ((mixer_text_length + text_length + 1) > sizeof(mixer_text)) {
			r_status_flags &= ~PX4IO_P_STATUS_FLAGS_MIXER_OK;
			return;
		}

		/* append mixer text and nul-terminate */
		memcpy(&mixer_text[mixer_text_length], msg->text, text_length);
		mixer_text_length += text_length;
		mixer_text[mixer_text_length] = '\0';
		debug("buflen %u", mixer_text_length);

		/* process the text buffer, adding new mixers as their descriptions can be parsed */
		unsigned resid = mixer_text_length;
		mixer_group.load_from_buf(&mixer_text[0], resid);

		/* if anything was parsed */
		if (resid != mixer_text_length) {

			/* ideally, this should test resid == 0 ? */
			r_status_flags |= PX4IO_P_STATUS_FLAGS_MIXER_OK;

			debug("used %u", mixer_text_length - resid);

			/* copy any leftover text to the base of the buffer for re-use */
			if (resid > 0)
				memcpy(&mixer_text[0], &mixer_text[mixer_text_length - resid], resid);

			mixer_text_length = resid;
		}

		break;
	}
}
<commit_msg>Ensured that the mixer output obeys the FMU and IO armed state<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2012 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mixer.cpp
 *
 * Control channel input/output mixer and failsafe.
 */

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdbool.h>
#include <string.h>

#include <drivers/drv_pwm_output.h>
#include <drivers/drv_hrt.h>

#include <systemlib/mixer/mixer.h>

extern "C" {
//#define DEBUG
#include "px4io.h"
}

/*
 * Maximum interval in us before FMU signal is considered lost
 */
#define FMU_INPUT_DROP_LIMIT_US		200000

/* XXX need to move the RC_CHANNEL_FUNCTION out of rc_channels.h and into systemlib */
#define ROLL     0
#define PITCH    1
#define YAW      2
#define THROTTLE 3
#define OVERRIDE 4

/* current servo arm/disarm state */
static bool mixer_servos_armed = false;

/* selected control values and count for mixing */
enum mixer_source {
	MIX_NONE,
	MIX_FMU,
	MIX_OVERRIDE,
	MIX_FAILSAFE
};
static mixer_source source;

static int	mixer_callback(uintptr_t handle,
			       uint8_t control_group,
			       uint8_t control_index,
			       float &control);

static MixerGroup mixer_group(mixer_callback, 0);

void
mixer_tick(void)
{
	/* check that we are receiving fresh data from the FMU */
	if ((hrt_absolute_time() - system_state.fmu_data_received_time) > FMU_INPUT_DROP_LIMIT_US) {

		/* too long without FMU input, time to go to failsafe */
		if (r_status_flags & PX4IO_P_STATUS_FLAGS_FMU_OK) {
			debug("AP RX timeout");
		}
		r_status_flags |= PX4IO_P_STATUS_FLAGS_OVERRIDE;
		r_status_flags &= ~(PX4IO_P_STATUS_FLAGS_FMU_OK | PX4IO_P_STATUS_FLAGS_RAW_PWM);
		r_status_alarms |= PX4IO_P_STATUS_ALARMS_FMU_LOST;
	}

	source = MIX_FAILSAFE;

	/*
	 * Decide which set of controls we're using.
	 */
	if (r_status_flags & PX4IO_P_STATUS_FLAGS_RAW_PWM) {

		/* don't actually mix anything - we already have raw PWM values */
		source = MIX_NONE;

	} else {

		if (!(r_status_flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) &&
		     (r_status_flags & PX4IO_P_STATUS_FLAGS_MIXER_OK)) {

			/* mix from FMU controls */
			source = MIX_FMU;
		}

		if ( (r_status_flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) &&
		     (r_status_flags & PX4IO_P_STATUS_FLAGS_RC_OK)) {

		 	/* if allowed, mix from RC inputs directly */
			source = MIX_OVERRIDE;
		}
	}

	/*
	 * Run the mixers.
	 */
	if (source == MIX_FAILSAFE) {

		/* copy failsafe values to the servo outputs */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++)
			r_page_servos[i] = r_page_servo_failsafe[i];

	} else if (source != MIX_NONE) {

		float	outputs[IO_SERVO_COUNT];
		unsigned mixed;

		/* mix */
		mixed = mixer_group.mix(&outputs[0], IO_SERVO_COUNT);

		/* scale to PWM and update the servo outputs as required */
		for (unsigned i = 0; i < mixed; i++) {

			/* save actuator values for FMU readback */
			r_page_actuators[i] = FLOAT_TO_REG(outputs[i]);

			/* scale to servo output */
			r_page_servos[i] = (outputs[i] * 500.0f) + 1500;

		}
		for (unsigned i = mixed; i < IO_SERVO_COUNT; i++)
			r_page_servos[i] = 0;
	}

#if 0
		/* if everything is ok */

		if (!system_state.mixer_manual_override && system_state.mixer_fmu_available) {
			/* we have recent control data from the FMU */
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];

		} else if (system_state.rc_channels > 0) {
			/* when override is on or the fmu is not available, but RC is present */
			control_count = system_state.rc_channels;

			sched_lock();

			/* remap roll, pitch, yaw and throttle from RC specific to internal ordering */
			rc_channel_data[ROLL]     = system_state.rc_channel_data[system_state.rc_map[ROLL] - 1];
			rc_channel_data[PITCH]    = system_state.rc_channel_data[system_state.rc_map[PITCH] - 1];
			rc_channel_data[YAW]      = system_state.rc_channel_data[system_state.rc_map[YAW] - 1];
			rc_channel_data[THROTTLE] = system_state.rc_channel_data[system_state.rc_map[THROTTLE] - 1];
			//rc_channel_data[OVERRIDE] = system_state.rc_channel_data[system_state.rc_map[OVERRIDE] - 1];

			/* get the remaining channels, no remapping needed */
			for (unsigned i = 4; i < system_state.rc_channels; i++) {
				rc_channel_data[i] = system_state.rc_channel_data[i];
			}

			/* scale the control inputs */
			rc_channel_data[THROTTLE] = ((float)(rc_channel_data[THROTTLE] - system_state.rc_min[THROTTLE]) /
				(float)(system_state.rc_max[THROTTLE] - system_state.rc_min[THROTTLE])) * 1000.0f + 1000;

			if (rc_channel_data[THROTTLE] > 2000) {
				rc_channel_data[THROTTLE] = 2000;
			}

			if (rc_channel_data[THROTTLE] < 1000) {
				rc_channel_data[THROTTLE] = 1000;
			}

			// lib_lowprintf("Tmin: %d Ttrim: %d Tmax: %d T: %d \n",
			// 	(int)(system_state.rc_min[THROTTLE]), (int)(system_state.rc_trim[THROTTLE]),
			// 	(int)(system_state.rc_max[THROTTLE]), (int)(rc_channel_data[THROTTLE]));

			control_values = &rc_channel_data[0];
			sched_unlock();
		} else {
			/* we have no control input (no FMU, no RC) */

			// XXX builtin failsafe would activate here
			control_count = 0;
		}
		//lib_lowprintf("R: %d P: %d Y: %d T: %d \n", control_values[0], control_values[1], control_values[2], control_values[3]);

	/* this is for multicopters, etc. where manual override does not make sense */
	} else {
		/* if the fmu is available whe are good */
		if (system_state.mixer_fmu_available) {
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];
		/* we better shut everything off */
		} else {
			control_count = 0;
		}
	}
#endif

	/*
	 * Decide whether the servos should be armed right now.
	 *
	 * We must be armed, and we must have a PWM source; either raw from
	 * FMU or from the mixer.
	 *
	 * XXX correct behaviour for failsafe may require an additional case
	 * here.
	 */
	bool should_arm = (/* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) &&
	 		   /* IO is armed */  (r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED) &&
	/* there is valid input */ (r_status_flags & (PX4IO_P_STATUS_FLAGS_RAW_PWM | PX4IO_P_STATUS_FLAGS_MIXER_OK)));

	if (should_arm && !mixer_servos_armed) {
		/* need to arm, but not armed */
		up_pwm_servo_arm(true);
		mixer_servos_armed = true;

	} else if (!should_arm && mixer_servos_armed) {
		/* armed but need to disarm */
		up_pwm_servo_arm(false);
		mixer_servos_armed = false;
	}

	if (mixer_servos_armed) {
		/* update the servo outputs. */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++)
			up_pwm_servo_set(i, r_page_servos[i]);
	}
}

static int
mixer_callback(uintptr_t handle,
	       uint8_t control_group,
	       uint8_t control_index,
	       float &control)
{
	if (control_group != 0)
		return -1;

	switch (source) {
	case MIX_FMU:
		if (control_index < PX4IO_CONTROL_CHANNELS) {
			control = REG_TO_FLOAT(r_page_controls[control_index]);
			break;
		}
		return -1;

	case MIX_OVERRIDE:
		if (r_page_rc_input[PX4IO_P_RC_VALID] & (1 << control_index)) {
			control = REG_TO_FLOAT(r_page_rc_input[PX4IO_P_RC_BASE + control_index]);
			break;
		}
		return -1;

	case MIX_FAILSAFE:
	case MIX_NONE:
		/* XXX we could allow for configuration of per-output failsafe values */
		return -1;
	}

	return 0;
}

/*
 * XXX error handling here should be more aggressive; currently it is
 * possible to get STATUS_FLAGS_MIXER_OK set even though the mixer has
 * not loaded faithfully.
 */

static char mixer_text[256];		/* large enough for one mixer */
static unsigned mixer_text_length = 0;

void
mixer_handle_text(const void *buffer, size_t length)
{

	px4io_mixdata	*msg = (px4io_mixdata *)buffer;

	debug("mixer text %u", length);

	if (length < sizeof(px4io_mixdata))
		return;

	unsigned	text_length = length - sizeof(px4io_mixdata);

	switch (msg->action) {
	case F2I_MIXER_ACTION_RESET:
		debug("reset");
		mixer_group.reset();
		mixer_text_length = 0;
		r_status_flags &= ~PX4IO_P_STATUS_FLAGS_MIXER_OK;

		/* FALLTHROUGH */
	case F2I_MIXER_ACTION_APPEND:
		debug("append %d", length);

		/* check for overflow - this is really fatal */
		/* XXX could add just what will fit & try to parse, then repeat... */
		if ((mixer_text_length + text_length + 1) > sizeof(mixer_text)) {
			r_status_flags &= ~PX4IO_P_STATUS_FLAGS_MIXER_OK;
			return;
		}

		/* append mixer text and nul-terminate */
		memcpy(&mixer_text[mixer_text_length], msg->text, text_length);
		mixer_text_length += text_length;
		mixer_text[mixer_text_length] = '\0';
		debug("buflen %u", mixer_text_length);

		/* process the text buffer, adding new mixers as their descriptions can be parsed */
		unsigned resid = mixer_text_length;
		mixer_group.load_from_buf(&mixer_text[0], resid);

		/* if anything was parsed */
		if (resid != mixer_text_length) {

			/* ideally, this should test resid == 0 ? */
			r_status_flags |= PX4IO_P_STATUS_FLAGS_MIXER_OK;

			debug("used %u", mixer_text_length - resid);

			/* copy any leftover text to the base of the buffer for re-use */
			if (resid > 0)
				memcpy(&mixer_text[0], &mixer_text[mixer_text_length - resid], resid);

			mixer_text_length = resid;
		}

		break;
	}
}
<|endoftext|>


<commit_before>#include "movement_system.h"
#include "event.h"
#include "gameengine.h"
#include "entity.h"
#include <iostream>

void MovementSystem::handleEvent (const Event* event)
{
    switch (event->getType()) {
        case EVENT_MOVE_ENTITY: {
            const MoveEntityEvent* l_event = dynamic_cast<const MoveEntityEvent*> (event);
            EntityId l_entity = l_event->entity;
            LocationComponent* l_location = m_engine->getEntities()->getLocations()->get (l_entity);
            if (!l_location) return;
            unsigned int newX = l_location->x;
            unsigned int newY = l_location->y;
            switch (l_event->direction) {
                case Direction::North:  newY--; break;
                case Direction::South:  newY++; break;
                case Direction::West:   newX--; break;
                case Direction::East:   newX++; break;
                default: return;
            }

            //Check if we're running into a collidable or something
            {
                std::map<EntityId, LocationComponent>& l_locations = m_engine->getEntities()->getLocations()->getAll();
                std::map<EntityId, LocationComponent>::iterator it = l_locations.begin();
                for (; it != l_locations.end(); it++) {
                    // There is an entity here
                    if (it->second.x == newX && it->second.y == newY && it->second.z == m_engine->getLevel()) {
                        // Check if it's a collidable
                        if (m_engine->getEntities()->getColliders()->get (it->first)) {
                            return;
                        }
                        StairComponent* l_stair = m_engine->getEntities()->getStairs()->get (it->first);
                        if (l_stair && l_entity == m_engine->getEntities()->getPlayer()) {
                            unsigned int level = m_engine->getLevel();
                            if (l_stair->direction == StairComponent::UP) {
                                if (level > 1) level--;
                            } else {
                                if (level < m_engine->getMaxLevel()) level++;
                            }
                            m_engine->setLevel (level);
                            std::map<EntityId, StairComponent>& l_stairs = m_engine->getEntities()->getStairs()->getAll();
                            std::map<EntityId, StairComponent>::iterator iter = l_stairs.begin();
                            StairComponent::STAIR dir = l_stair->direction == StairComponent::UP ? StairComponent::DOWN : StairComponent::UP;
                            for (; iter != l_stairs.end(); iter++) {
                                LocationComponent* l_stairLoc = m_engine->getEntities()->getLocations()->get (iter->first);
                                if (iter->second.direction == dir && l_stairLoc->z == m_engine->getLevel()) {
                                    l_location->x = l_stairLoc->x;
                                    l_location->y = l_stairLoc->y;
                                    l_location->z = l_stairLoc->z;
                                    return;
                                }
                            }

                        }
                    }
                }
            }

            l_location->x = newX;
            l_location->y = newY;
            break;
        }
        default: break;
    }
}
<commit_msg>Only move to stairs if level changed<commit_after>#include "movement_system.h"
#include "event.h"
#include "gameengine.h"
#include "entity.h"
#include <iostream>

void MovementSystem::handleEvent (const Event* event)
{
    switch (event->getType()) {
        case EVENT_MOVE_ENTITY: {
            const MoveEntityEvent* l_event = dynamic_cast<const MoveEntityEvent*> (event);
            EntityId l_entity = l_event->entity;
            LocationComponent* l_location = m_engine->getEntities()->getLocations()->get (l_entity);
            if (!l_location) return;
            unsigned int newX = l_location->x;
            unsigned int newY = l_location->y;
            switch (l_event->direction) {
                case Direction::North:  newY--; break;
                case Direction::South:  newY++; break;
                case Direction::West:   newX--; break;
                case Direction::East:   newX++; break;
                default: return;
            }

            //Check if we're running into a collidable or something
            {
                std::map<EntityId, LocationComponent>& l_locations = m_engine->getEntities()->getLocations()->getAll();
                std::map<EntityId, LocationComponent>::iterator it = l_locations.begin();
                for (; it != l_locations.end(); it++) {
                    // There is an entity here
                    if (it->second.x == newX && it->second.y == newY && it->second.z == m_engine->getLevel()) {
                        // Check if it's a collidable
                        if (m_engine->getEntities()->getColliders()->get (it->first)) {
                            return;
                        }
                        StairComponent* l_stair = m_engine->getEntities()->getStairs()->get (it->first);
                        if (l_stair && l_entity == m_engine->getEntities()->getPlayer()) {
                            unsigned int level = m_engine->getLevel();
                            if (l_stair->direction == StairComponent::UP) {
                                if (level > 1) level--;
                            } else {
                                if (level < m_engine->getMaxLevel()) level++;
                            }
                            if (level == m_engine->getLevel()) break;
                            m_engine->setLevel (level);
                            std::map<EntityId, StairComponent>& l_stairs = m_engine->getEntities()->getStairs()->getAll();
                            std::map<EntityId, StairComponent>::iterator iter = l_stairs.begin();
                            StairComponent::STAIR dir = l_stair->direction == StairComponent::UP ? StairComponent::DOWN : StairComponent::UP;
                            for (; iter != l_stairs.end(); iter++) {
                                LocationComponent* l_stairLoc = m_engine->getEntities()->getLocations()->get (iter->first);
                                if (iter->second.direction == dir && l_stairLoc->z == m_engine->getLevel()) {
                                    l_location->x = l_stairLoc->x;
                                    l_location->y = l_stairLoc->y;
                                    l_location->z = l_stairLoc->z;
                                    return;
                                }
                            }

                        }
                    }
                }
            }

            l_location->x = newX;
            l_location->y = newY;
            break;
        }
        default: break;
    }
}
<|endoftext|>


<commit_before>#include "tmfs.hh"

static std::string _get_real_path(const std::string & str)
{
  // use the relative path so that the real_path doesn't get replaced
  const auto clean_path = fs::path(str).relative_path();

  fs::path real_path(tmfs::instance().hfs_root());
  real_path /= "Backups.backupdb"; // ${hfs_root}/Backups.backupdb/

  // ok let's copy the 3 first part of the virtual path
  // (${comp_name}, ${date}, ${disk_name})
  auto it = clean_path.begin();
  for (int i = 0; i < 3 && it != clean_path.end(); ++i, ++it)
    real_path /= *it;

  // let's resolv all the parts of the path
  struct stat stbuf;
  for (; it != clean_path.end(); ++it)
  {
    real_path /= *it;
    // Does the file exists ?
    if (lstat(real_path.string().c_str(), &stbuf))
      return real_path.string();

    // Is the file a dir_id ?
    if (S_ISREG(stbuf.st_mode) && stbuf.st_size == 0 && stbuf.st_nlink > 0)
    {
      // build the real path
      std::ostringstream os;
      os << tmfs::instance().hfs_root() << "/.HFS+ Private Directory Data\r/dir_" << stbuf.st_nlink;

      // check if it's really a ${dir_id}
      if (stat(os.str().c_str(), &stbuf))
        continue; // it's not
      real_path = os.str(); // it is
    }
  }
  return real_path.string();
}

std::string get_real_path(const std::string & str)
{
  auto result = _get_real_path(str);
#ifndef NDEBUG
  std::cout << "get_real_path(\"" << str << "\") -> "  << result << std::endl;
#endif
  return result;
}
<commit_msg>Fix get_real_path, broken by previous patch<commit_after>#include "tmfs.hh"

static std::string _get_real_path(const std::string & str)
{
  // use the relative path so that the real_path doesn't get replaced
  const auto clean_path = fs::path(str).relative_path();

  fs::path real_path(tmfs::instance().hfs_root());
  real_path /= "Backups.backupdb"; // ${hfs_root}/Backups.backupdb/

  // ok let's copy the 3 first part of the virtual path
  // (${comp_name}, ${date}, ${disk_name})
  auto it = clean_path.begin();
  for (int i = 0; i < 3 && it != clean_path.end(); ++i, ++it)
    real_path /= *it;

  // let's resolv all the parts of the path
  struct stat stbuf;
  for (; it != clean_path.end(); ++it)
  {
    real_path /= *it;
    // Does the file exists ?
    if (lstat(real_path.string().c_str(), &stbuf))
      return real_path.string();

    // Is the file a dir_id ?
    if (S_ISREG(stbuf.st_mode) && stbuf.st_size == 0 && stbuf.st_nlink > 0)
    {
      // build the real path
      fs::path dir_path = tmfs::instance().hfs_root();
      dir_path /= ".HFS+ Private Directory Data\r/dir_" + std::to_string(stbuf.st_nlink);

      // check if it's really a ${dir_id}
      if (stat(dir_path.c_str(), &stbuf))
        continue; // it's not
      real_path = dir_path; // it is
    }
  }
  return real_path.string();
}

std::string get_real_path(const std::string & str)
{
  auto result = _get_real_path(str);
#ifndef NDEBUG
  std::cout << "get_real_path(\"" << str << "\") -> "  << result << std::endl;
#endif
  return result;
}
<|endoftext|>


<commit_before>/*
* (C) 2015,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ffi.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_pkey.h>
#include <botan/internal/ffi_rng.h>
#include <botan/pubkey.h>

extern "C" {

using namespace Botan_FFI;

BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1);

int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
                               botan_pubkey_t key_obj,
                               const char* padding,
                               uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Encryptor> pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
      *op = new botan_pk_op_encrypt_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
                        botan_rng_t rng_obj,
                        uint8_t out[], size_t* out_len,
                        const uint8_t plaintext[], size_t plaintext_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, {
      return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj)));
      });
   }

/*
* Public Key Decryption
*/
int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
                               botan_privkey_t key_obj,
                               const char* padding,
                               uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Decryptor> pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
      *op = new botan_pk_op_decrypt_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
                        uint8_t out[], size_t* out_len,
                        const uint8_t ciphertext[], size_t ciphertext_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, {
      return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len));
      });
   }

/*
* Signature Generation
*/
int botan_pk_op_sign_create(botan_pk_op_sign_t* op,
                            botan_privkey_t key_obj,
                            const char* hash,
                            uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Signer> pk(new Botan::PK_Signer(safe_get(key_obj),Botan::system_rng(),  hash));
      *op = new botan_pk_op_sign_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_sign_destroy(botan_pk_op_sign_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { o.update(in, in_len); });
   }

int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Signer, op, o, {
      return write_vec_output(out, out_len, o.signature(safe_get(rng_obj)));
      });
   }

int botan_pk_op_verify_create(botan_pk_op_verify_t* op,
                              botan_pubkey_t key_obj,
                              const char* hash,
                              uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Verifier> pk(new Botan::PK_Verifier(safe_get(key_obj), hash));
      *op = new botan_pk_op_verify_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_verify_destroy(botan_pk_op_verify_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, { o.update(in, in_len); });
   }

int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, {
      const bool legit = o.check_signature(sig, sig_len);

      if(legit)
         return BOTAN_FFI_SUCCESS;
      else
         return BOTAN_FFI_INVALID_VERIFIER;
      });
   }

int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op,
                                     botan_privkey_t key_obj,
                                     const char* kdf,
                                     uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Key_Agreement> pk(new Botan::PK_Key_Agreement(safe_get(key_obj), Botan::system_rng(), kdf));
      *op = new botan_pk_op_ka_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_key_agreement_export_public(botan_privkey_t key,
                                            uint8_t out[], size_t* out_len)
   {
   return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
      if(auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&k))
         return write_vec_output(out, out_len, kak->public_value());
      return BOTAN_FFI_ERROR_BAD_FLAG;
      });
   }

int botan_pk_op_key_agreement(botan_pk_op_ka_t op,
                              uint8_t out[], size_t* out_len,
                              const uint8_t other_key[], size_t other_key_len,
                              const uint8_t salt[], size_t salt_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, {
      auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of();
      return write_vec_output(out, out_len, k);
      });
   }

}
<commit_msg>Format nit<commit_after>/*
* (C) 2015,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ffi.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_pkey.h>
#include <botan/internal/ffi_rng.h>
#include <botan/pubkey.h>

extern "C" {

using namespace Botan_FFI;

BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936);
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1);

int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
                               botan_pubkey_t key_obj,
                               const char* padding,
                               uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Encryptor> pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
      *op = new botan_pk_op_encrypt_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
                        botan_rng_t rng_obj,
                        uint8_t out[], size_t* out_len,
                        const uint8_t plaintext[], size_t plaintext_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, {
      return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj)));
      });
   }

/*
* Public Key Decryption
*/
int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
                               botan_privkey_t key_obj,
                               const char* padding,
                               uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Decryptor> pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
      *op = new botan_pk_op_decrypt_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
                        uint8_t out[], size_t* out_len,
                        const uint8_t ciphertext[], size_t ciphertext_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, {
      return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len));
      });
   }

/*
* Signature Generation
*/
int botan_pk_op_sign_create(botan_pk_op_sign_t* op,
                            botan_privkey_t key_obj,
                            const char* hash,
                            uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Signer> pk(new Botan::PK_Signer(safe_get(key_obj), Botan::system_rng(), hash));
      *op = new botan_pk_op_sign_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_sign_destroy(botan_pk_op_sign_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { o.update(in, in_len); });
   }

int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Signer, op, o, {
      return write_vec_output(out, out_len, o.signature(safe_get(rng_obj)));
      });
   }

int botan_pk_op_verify_create(botan_pk_op_verify_t* op,
                              botan_pubkey_t key_obj,
                              const char* hash,
                              uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Verifier> pk(new Botan::PK_Verifier(safe_get(key_obj), hash));
      *op = new botan_pk_op_verify_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_verify_destroy(botan_pk_op_verify_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, { o.update(in, in_len); });
   }

int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, {
      const bool legit = o.check_signature(sig, sig_len);

      if(legit)
         return BOTAN_FFI_SUCCESS;
      else
         return BOTAN_FFI_INVALID_VERIFIER;
      });
   }

int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op,
                                     botan_privkey_t key_obj,
                                     const char* kdf,
                                     uint32_t flags)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
      BOTAN_ASSERT_NONNULL(op);

      *op = nullptr;

      if(flags != 0)
         return BOTAN_FFI_ERROR_BAD_FLAG;

      std::unique_ptr<Botan::PK_Key_Agreement> pk(new Botan::PK_Key_Agreement(safe_get(key_obj), Botan::system_rng(), kdf));
      *op = new botan_pk_op_ka_struct(pk.release());
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op)
   {
   return BOTAN_FFI_CHECKED_DELETE(op);
   }

int botan_pk_op_key_agreement_export_public(botan_privkey_t key,
                                            uint8_t out[], size_t* out_len)
   {
   return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
      if(auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&k))
         return write_vec_output(out, out_len, kak->public_value());
      return BOTAN_FFI_ERROR_BAD_FLAG;
      });
   }

int botan_pk_op_key_agreement(botan_pk_op_ka_t op,
                              uint8_t out[], size_t* out_len,
                              const uint8_t other_key[], size_t other_key_len,
                              const uint8_t salt[], size_t salt_len)
   {
   return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, {
      auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of();
      return write_vec_output(out, out_len, k);
      });
   }

}
<|endoftext|>