/* 
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "stdafx.h"

#include "mforms/mforms.h"
#include "wf_view.h"
#include "wf_code_editor.h"

#include "wf_box.h"
#include "wf_appview.h"
#include "wf_app.h"

#include "base/log.h"
#include "base/string_utilities.h"

#include "ConvUtils.h"

using namespace Windows::Forms;
using namespace System::Drawing;
using namespace System::IO;

using namespace MySQL;
using namespace MySQL::Forms;
using namespace MySQL::Utilities;
using namespace MySQL::Controls;

using namespace Aga::Controls::Tree;

DEFAULT_LOG_DOMAIN(DOMAIN_MFORMS_WRAPPER)

//----------------- ViewImpl ----------------------------------------------------------------------

ViewImpl::ViewImpl(mforms::View *view)
  : ObjectImpl(view)
{
  tooltip = nullptr;
  backgroundImage = nullptr;
  layoutSuspended = false;
  _resize_mode = AutoResizeMode::ResizeBoth;
}

//--------------------------------------------------------------------------------------------------

ViewImpl::~ViewImpl()
{
  delete tooltip;
}

//--------------------------------------------------------------------------------------------------

/**
 * Determines, depending on the type of the given control, if the layout process should use the control's
 * minimum or its preferred size. 
 * This is necessary because there is a discrepancy between what is considered the minimum size for layouting
 * and the same size for Windows controls. The latter is usually just 0. Instead the preferred size comes close
 * to what we need in the layouting process. Unfortunately, some controls just return their current size
 * (even if they are empty) or the size they need to fit their full text (text box).
 */
bool ViewImpl::use_min_width_for_layout(Control^ control)
{
  TextBox^ text= dynamic_cast<TextBox^>(control);
  bool needsMinWidth= (text != nullptr) && (text->Multiline);
  if (!needsMinWidth)
  {
    System::Type^ type = control->GetType();
    needsMinWidth = (type == TabControl::typeid) || (type == Panel::typeid) || (type == ComboBox::typeid)
      || (type == TreeViewAdv::typeid) || (type == ListBox::typeid) || (type == TextBox::typeid)
      || (type == SplitContainer::typeid) || (type == ScintillaControl::typeid)
      || (type == Windows::Forms::WebBrowser::typeid) || (type == HtmlLabel::typeid) || (type == HtmlPanel::typeid)
      || (type == Windows::Forms::ProgressBar::typeid)
      
      // TODO: investigate if we can remove this and override GetPreferredSize in FlatTabControl instead.
      || (type == FlatTabControl::typeid);
  }

  return needsMinWidth;
}

//--------------------------------------------------------------------------------------------------

bool ViewImpl::use_min_height_for_layout(Control^ control)
{
  TextBox^ text= dynamic_cast<TextBox^>(control);
  bool needsMinHeight= (text != nullptr) && (text->Multiline);
  if (!needsMinHeight)
  {
    System::Type^ type = control->GetType();
    needsMinHeight= (type == TabControl::typeid) || (type == Panel::typeid) || (type == ListBox::typeid)
      || (type == TreeViewAdv::typeid) || (type == SplitContainer::typeid) || (type == ScintillaControl::typeid)
      || (type == Windows::Forms::WebBrowser::typeid)

    // TODO: investigate if we can remove this and override GetPreferredSize in FlatTabControl instead.
    || (type == FlatTabControl::typeid);
  }

  return needsMinHeight;
}

//--------------------------------------------------------------------------------------------------

/**
 * Removes the given mode from the auto resize settings of the given control.
 */
void ViewImpl::remove_auto_resize(Control^ control, AutoResizeMode mode)
{
  ViewImpl ^wrapper = get_wrapper<ViewImpl>(control);
  switch (mode)
  {
    case AutoResizeMode::ResizeBoth:
      wrapper->_resize_mode = AutoResizeMode::ResizeNone;
      break;
    case AutoResizeMode::ResizeHorizontal:
      if (wrapper->_resize_mode == AutoResizeMode::ResizeBoth)
        wrapper->_resize_mode = AutoResizeMode::ResizeVertical;
      else
        wrapper->_resize_mode = AutoResizeMode::ResizeNone;
      break;
    case AutoResizeMode::ResizeVertical:
      if (wrapper->_resize_mode == AutoResizeMode::ResizeBoth)
        wrapper->_resize_mode = AutoResizeMode::ResizeHorizontal;
      else
        wrapper->_resize_mode = AutoResizeMode::ResizeNone;
      break;
  }
}

//-------------------------------------------------------------------------------------------------

AutoResizeMode ViewImpl::get_auto_resize(Control^ control)
{
  ViewImpl ^wrapper = get_wrapper<ViewImpl>(control);
  return wrapper->_resize_mode;
}

//-------------------------------------------------------------------------------------------------

/**
 * Determines if the given control can be resized in horizontal direction.
 */
bool ViewImpl::can_auto_resize_horizontally(Control^ control)
{
  ViewImpl ^wrapper = get_wrapper<ViewImpl>(control);
  AutoResizeMode mode = wrapper->_resize_mode;

  return (mode == AutoResizeMode::ResizeHorizontal) || (mode == AutoResizeMode::ResizeBoth);
}

//-------------------------------------------------------------------------------------------------

/**
 * Determines if the given control can be resized in vertical direction.
 */
bool ViewImpl::can_auto_resize_vertically(Control^ control)
{
  ViewImpl ^wrapper = get_wrapper<ViewImpl>(control);
  AutoResizeMode mode = wrapper->_resize_mode;

  return (mode == AutoResizeMode::ResizeVertical) || (mode == AutoResizeMode::ResizeBoth);
}

//-------------------------------------------------------------------------------------------------

/**
 * Enables resizing of the control in both directions.
 */
void ViewImpl::set_full_auto_resize(Control^ control)
{
  ViewImpl ^wrapper = get_wrapper<ViewImpl>(control);
  wrapper->_resize_mode = AutoResizeMode::ResizeBoth;
}

//-------------------------------------------------------------------------------------------------

/**
 * Sets resize mode whatever the caller specified.
 */
void ViewImpl::set_auto_resize(Control^ control, AutoResizeMode mode)
{
  ViewImpl ^wrapper = get_wrapper<ViewImpl>(control);
  wrapper->_resize_mode = mode;
}

//-------------------------------------------------------------------------------------------------

bool ViewImpl::is_layout_dirty(Control^ control)
{
  mforms::View* view= ViewImpl::get_backend_control<mforms::View>(control);
  return view->is_layout_dirty();
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_layout_dirty(Control^ control, bool value)
{
  mforms::View* view= ViewImpl::get_backend_control<mforms::View>(control);
  view->set_layout_dirty(value);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::destroy(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  delete view;
}

//--------------------------------------------------------------------------------------------------

void ViewImpl::show(mforms::View *self, bool show)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);

  if (view != nullptr)
  {
    Control^ control= view->get_control<Control>();

    // Create the control's window handle if not yet done. This is necessary because otherwise
    // when setting a control to hidden and its window handle is not created, it will be moved to the end
    // of it's parent Controls list, messing up our layout.
    if (!control->IsHandleCreated)
      control->Handle;

    // Use reflection to get the true visible state. The Visible property returns the value for the
    // control itself as well as all its parents.
    bool visible = (bool)Control::typeid
      ->GetMethod("GetState", System::Reflection::BindingFlags::Instance | System::Reflection::BindingFlags::NonPublic)
      ->Invoke(control, gcnew array<Object^> { 2 });
    if (show != visible && self->get_parent() != NULL)
    {
      if (view->layoutSuspended)
        self->get_parent()->set_layout_dirty(true);
      else
        control->PerformLayout(control, "Visible");
    }

    control->Visible = show;
  };
}

//-------------------------------------------------------------------------------------------------

int ViewImpl::get_width(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    return view->get_control<Control>()->Width;
  return 0;
}

//-------------------------------------------------------------------------------------------------

int ViewImpl::get_height(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    return view->get_control<Control>()->Height;
  return 0;
}

//-------------------------------------------------------------------------------------------------

int ViewImpl::get_preferred_width(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    return view->get_control<Control>()->PreferredSize.Width;
  }
  return 0;
}

//-------------------------------------------------------------------------------------------------

int ViewImpl::get_preferred_height(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    return view->get_control<Control>()->PreferredSize.Height;
  }
  return 0;
}

//-------------------------------------------------------------------------------------------------

int ViewImpl::get_x(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    return view->get_control<Control>()->Left;
  }
  return 0;
}

//-------------------------------------------------------------------------------------------------

int ViewImpl::get_y(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    return view->get_control<Control>()->Top;
  }
  return 0;
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_size(mforms::View *self, int w, int h)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->set_size(w, h);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_padding(mforms::View *self, int left, int top, int right, int bottom)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    self->set_layout_dirty(true);
    view->set_padding(left, top, right, bottom);
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_position(mforms::View *self, int x, int y)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    if (self->get_parent() != NULL)
      self->get_parent()->set_layout_dirty(true);
    view->set_position(x, y);
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::client_to_screen(mforms::View *self, int& x, int& y)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    System::Drawing::Point location= System::Drawing::Point(x, y);
    location= view->get_control<Control>()->PointToScreen(location);
    x = location.X;
    y = location.Y;
  }
}

//-------------------------------------------------------------------------------------------------

ViewImpl^ ViewImpl::get_parent()
{
  mforms::View* view= get_backend_control<mforms::View>(get_control<Control>());
  if (view != NULL && view->get_parent() != NULL)
    return (ViewImpl^) ObjectImpl::FromUnmanaged(view->get_parent());

  return nullptr;
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::relayout()
{
  Control^ control= get_control<Control>();
  if (control->InvokeRequired)
    control->BeginInvoke(gcnew MethodInvoker(this, &ViewImpl::relayout));
  else
    control->PerformLayout(control, "Bounds");
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_enabled(mforms::View *self, bool flag)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->get_control<Control>()->Enabled= flag;
}

//-------------------------------------------------------------------------------------------------

bool ViewImpl::is_enabled(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    return view->get_control<Control>()->Enabled;
  return false;
}

//-------------------------------------------------------------------------------------------------

View *ViewImpl::find_subview(mforms::View *self, std::string &name)
{
  return 0;
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_name(mforms::View *self, const std::string& text)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    view->get_control<Control>()->Name = CppStringToNative(text);
    view->get_control<Control>()->AccessibleName = CppStringToNative(text);
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::relayout(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->relayout();
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_needs_repaint(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->get_control<Control>()->Refresh();
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::suspend_layout(mforms::View *self, bool flag)
{
  ViewImpl^ view = (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    view->layoutSuspended = flag;
    Control ^control = view->get_control();
    if (flag)
      control->SuspendLayout();
    else
    {
      control->ResumeLayout();
      if (self->is_layout_dirty())
        control->PerformLayout(control, "Bounds");
    }
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_front_color(mforms::View *self, const std::string &color)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->set_front_color(CppStringToNative(color));
}

//-------------------------------------------------------------------------------------------------

std::string ViewImpl::get_front_color(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    return NativeToCppString(view->get_front_color());
  return "#ffffff";
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_back_color(mforms::View *self, const std::string &color)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->set_back_color(CppStringToNative(color));
}

//-------------------------------------------------------------------------------------------------

std::string ViewImpl::get_back_color(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    return NativeToCppString(view->get_back_color());
  return "#000000";
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_back_image(mforms::View *self, const std::string &path, mforms::Alignment align)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->set_back_image(CppStringToNative(path), align);
}


//-------------------------------------------------------------------------------------------------

void ViewImpl::focus(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
  {
    Control^ control = view->get_control();
    if (control->CanFocus)
      control->Focus();
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_tooltip(mforms::View *self, const std::string& text)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->set_tooltip(text);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_font(mforms::View *self, const std::string& fontDescription)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    view->set_font(fontDescription);
}

//-------------------------------------------------------------------------------------------------

bool ViewImpl::is_shown(mforms::View *self)
{
  ViewImpl^ view= (ViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (view != nullptr)
    return view->get_control<Control>()->Visible;
  return false;
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::initialize()
{
  Control^ control= get_control<Control>();

  // Can be null, e.g. for non-control objects like dialogs.
  if (control != nullptr)
  {
    control->Resize += gcnew EventHandler(this, &ViewImpl::Resize);
    control->Enter += gcnew EventHandler(this, &ViewImpl::Enter);
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_size(int width, int height)
{
  Control^ control= get_control<Control>();
  Size newSize= control->Size;
  if (width >= 0)
    newSize.Width= width;
  if (height >= 0)
    newSize.Height= height;
  
  control->MinimumSize = newSize; // TODO: wrong place for this, when we restore loaded settings we don't want to set a min size.
                                  //       Implement an own set_min_size function.
  control->Size = newSize;
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_padding(int left, int top, int right, int bottom)
{
  Control^ control= get_control<Control>();
  control->Padding = Windows::Forms::Padding(left, top, right, bottom);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_position(int x, int y)
{
  get_control<Control>()->Location = Point(x, y);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_tooltip(const std::string& text)
{
  if (tooltip == nullptr)
  {
    tooltip= gcnew ToolTip();
    tooltip->AutoPopDelay = 10000; // 10 sec. show time
    tooltip->InitialDelay = 500;   // 500 ms before showing the tooltip if none was visible before.
    tooltip->ReshowDelay = 250;    // 250 ms before showing the tooltip if another one was active.
    tooltip->ShowAlways = true;    // Show tooltip even if the control is not active.
  }
  tooltip->SetToolTip(get_control<Control>(), CppStringToNative(text));
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_font(const std::string& fontDescription)
{
  std::string font;
  float size;
  bool bold;
  bool italic;
  base::parse_font_description(fontDescription, font, size, bold, italic);

  FontStyle style = FontStyle::Regular;
  if (bold)
    style = (FontStyle) (style | FontStyle::Bold);
  if (italic)
    style = (FontStyle) (style | FontStyle::Italic);

  try
  {
    // Font size in points.
    get_control<Control>()->Font = ControlUtilities::GetFont(CppStringToNativeRaw(font), size, style);
  }
  catch (System::ArgumentException^ e)
  {
    // Argument exception pops up when the system cannot find the Regular font style (corrupt font).
    log_error("ViewImpl::set_font failed. %s\n", e->Message);
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_front_color(String ^color)
{
  get_control<Control>()->ForeColor= System::Drawing::ColorTranslator::FromHtml(color);
}

//-------------------------------------------------------------------------------------------------

String^ ViewImpl::get_front_color()
{
  return System::Drawing::ColorTranslator::ToHtml(get_control<Control>()->ForeColor);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_back_color(String ^color)
{
  if (color == "")
    get_control<Control>()->BackColor = Color::Transparent;
  else
    get_control<Control>()->BackColor = System::Drawing::ColorTranslator::FromHtml(color);
}

//-------------------------------------------------------------------------------------------------

String^ ViewImpl::get_back_color()
{
  if (get_control<Control>()->BackColor == Color::Transparent)
    return "";
  return System::Drawing::ColorTranslator::ToHtml(get_control<Control>()->BackColor);
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_back_image(String ^path, mforms::Alignment layout)
{
  path = AppImpl::get_image_path(path);
  if (File::Exists(path))
  {
    backgroundImage = Image::FromFile(path, true);
    backgroundImageAlignment = layout;
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::set_resize_mode(AutoResizeMode mode)
{
  _resize_mode = mode;
}

//-------------------------------------------------------------------------------------------------

/**
 * Resizes the given control according to its dock state. Sizes of the control which were not changed
 * are also reset in the given Size structure to allow for proper child layouting.
 */
void ViewImpl::resize_with_docking(Control^ control, System::Drawing::Size& size)
{
  // If the control is docked somewhere resizing must be restricted not to destroy the docked
  // appearance.
  // Do not resize if the control has the fill dock style. In that case it must stay as it is.
  if (control->Dock == DockStyle::Fill)
    return;

  if (control->Dock == DockStyle::Left || control->Dock == DockStyle::Right)
    size.Height= control->Size.Height;
  else
    if (control->Dock == DockStyle::Top || control->Dock == DockStyle::Bottom)
      size.Width= control->Size.Width;

  control->Size= size;
  set_layout_dirty(control, true);
}

//-------------------------------------------------------------------------------------------------

/**
 * Removes auto resizing flags if a control is limited in resizing by docking.
 */
void ViewImpl::adjust_auto_resize_from_docking(Control^ control)
{
  if (control->Dock == DockStyle::Fill)
    set_auto_resize(control, AutoResizeMode::ResizeNone);
  else
    if (control->Dock == DockStyle::Left || control->Dock == DockStyle::Right)
      remove_auto_resize(control, AutoResizeMode::ResizeHorizontal);
    else
      if (control->Dock == DockStyle::Top || control->Dock == DockStyle::Bottom)
        remove_auto_resize(control, AutoResizeMode::ResizeVertical);
}

//-------------------------------------------------------------------------------------------------

/**
 * Quick check if it makes sense to start layouting the given control.
 */
bool ViewImpl::can_layout(Control ^control, String ^reason)
{
  // Limit layouting to certain property changes.
  if (reason != nullptr)
  {
    if (reason != "Padding" &&
      reason != "Bounds" &&
      reason != "Visible" &&
      reason != "Parent"
      )
      return false;
  }

  /* Opting out based on a not created handle is a good optimization. Unfortunately, sometimes it
     prevents some forms (e.g. wizards) from layouting properly. So we have to disable this for now.
  if (!control->IsHandleCreated)
    return false;
  */

  if (control->Tag != nullptr)
  {
    mforms::View *backend = ViewImpl::get_backend_control<mforms::View>(control);
    if (backend->is_destroying())
      return false;
  }

  return true;
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::flush_events(mforms::View *)
{
  Application::DoEvents();
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::Resize(System::Object ^sender, EventArgs ^e)
{
  Control^ control = (Control^)sender;

  if (control->Tag != nullptr)
  {
    mforms::View* view = ViewImpl::get_backend_control<mforms::View>(control);
    if (!view->is_destroying())
      (*view->signal_resized())();
  }
}

//-------------------------------------------------------------------------------------------------

void ViewImpl::Enter(System::Object ^sender, EventArgs ^e)
{
  Control^ control = (Control^)sender;

  if (control->Tag != nullptr)
  {
    mforms::View* view = ViewImpl::get_backend_control<mforms::View>(control);
    if (!view->is_destroying())
      view->focus_changed();
  }
}

//-------------------------------------------------------------------------------------------------

/**
 * Draws the background image with the earlier set layout, if there's one.
 */
void ViewImpl::draw_background(PaintEventArgs ^args)
{
  if (backgroundImage != nullptr)
  {
    int left = 0;
    int top = 0;
    Control ^control = get_control();

    // Horizontal alignment.
    switch (backgroundImageAlignment)
    {
    case mforms::BottomCenter:
    case mforms::MiddleCenter:
    case mforms::TopCenter:
      left = (control->Width - backgroundImage->Width) / 2;
      break;

    case mforms::BottomRight:
    case mforms::MiddleRight:
    case mforms::TopRight:
      left = control->Width - backgroundImage->Width;
      break;
    }

    // Vertical alignment.
    switch (backgroundImageAlignment)
    {
    case mforms::MiddleLeft:
    case mforms::MiddleCenter:
    case mforms::MiddleRight:
      top = (control->Height - backgroundImage->Height) / 2;
      break;

    case mforms::BottomLeft:
    case mforms::BottomCenter:
    case mforms::BottomRight:
      top = control->Height - backgroundImage->Height;
      break;
    }

    args->Graphics->DrawImage(backgroundImage, Point(left, top));
  }
}

//-------------------------------------------------------------------------------------------------
