/* 
 * © 2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/**
 * Implementation of the selector (combobox) Windows mforms wrapper.
 */

#include "stdafx.h"
#include "wf_selector.h"

using namespace MySQL::Forms;

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

SelectorImpl::SelectorImpl(::mforms::Selector *self)
  : ViewImpl(self)
{
}

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

bool SelectorImpl::create(::mforms::Selector *self)
{
  SelectorImpl ^selector= gcnew SelectorImpl(self);

  if (selector != nullptr)
  {
    ComboBox ^combo= ViewImpl::create<ComboBox>(self, selector);
    combo->DropDownStyle= ComboBoxStyle::DropDownList;
    combo->SelectedIndexChanged += gcnew System::EventHandler(&SelectorImpl::selection_changed);
    combo->Width= 100;
    combo->DropDownHeight= 100;
    combo->DrawMode= DrawMode::OwnerDrawVariable;
    combo->MeasureItem += gcnew MeasureItemEventHandler(measure_item);
    combo->DrawItem += gcnew DrawItemEventHandler(draw_item);
    return true;
  }
  return false;
}

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

/**
 * Computes the width of the widest entry in the given combobox. Can be used to resize the combobox
 * or only its dropdown list.
 */
int compute_content_width(ComboBox^ box)
{
  int width= 0;
  Graphics^ g= box->CreateGraphics();
  Font^ font= box->Font;
  int vertScrollBarWidth= (box->Items->Count > box->MaxDropDownItems) ? SystemInformation::VerticalScrollBarWidth : 0;

  int newWidth;
  for each (Object^ item in box->Items)
  {
    if (item->GetType() == SeparatorItem::typeid)
      newWidth= 30;
    else
      newWidth = (int) g->MeasureString((String^) item, font).Width + vertScrollBarWidth;
    if (width < newWidth)
      width= newWidth;
  }
  return width;
}

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

const int separatorHeight= 5;
const int verticalItemPadding= 4;

void SelectorImpl::measure_item(Object^ sender, MeasureItemEventArgs^ args)
{
  // Fetch the current item we’re painting as specified by the index.
  ComboBox^ box= (ComboBox^) sender;
  Object^ comboBoxItem= box->Items[args->Index];

  // If we are a separator item, add in room for the separator.
  if (comboBoxItem->GetType() == SeparatorItem::typeid)
  {
    args->ItemHeight = separatorHeight;
    args->ItemWidth= 50;
  }
  else
  {
    // Measure the text of the item;
    String^ s= comboBoxItem->ToString();
    if (s == "")
      s= "Ag";
    Size textSize= args->Graphics->MeasureString(s, box->Font).ToSize();
    args->ItemHeight= textSize.Height + verticalItemPadding;
    args->ItemWidth= textSize.Width;
  }
}

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

void SelectorImpl::draw_item(Object^ sender, DrawItemEventArgs^ args)
{
  if (args->Index == -1) 
    return;
  else
  {
    ComboBox^ box= (ComboBox^) sender;
    Object^ comboBoxItem = box->Items[args->Index];

    bool isSeparatorItem= (comboBoxItem->GetType() == SeparatorItem::typeid);

    Drawing::Rectangle bounds= args->Bounds;

    // Let the box handle the default stuff.
    args->DrawBackground();
    args->DrawFocusRectangle();

    if (isSeparatorItem)
    {
      // Start with the background.
      Brush^ b = gcnew SolidBrush(box->BackColor);
      args->Graphics->FillRectangle(b, bounds);

      // Now the gradient line.
      Drawing::Drawing2D::LinearGradientBrush gradientBrush(
        Point(0, 1),
        Point(bounds.Width, 1),
        Color::FromArgb(255, 66, 111, 166),
        SystemColors::Window);

      Pen pen(%gradientBrush);

      int center= (bounds.Bottom + bounds.Top) / 2;
      args->Graphics->DrawLine(%pen, bounds.Left + 2, center, bounds.Right - 2, center);
    }
    else
    {
      // Draw the string vertically centered but on the left.
      Brush^ textBrush= gcnew SolidBrush(args->ForeColor);
      StringFormat^ format= gcnew StringFormat();
      format->LineAlignment= StringAlignment::Center;
      format->Alignment= StringAlignment::Near;

      args->Graphics->DrawString(comboBoxItem->ToString(), box->Font, textBrush, bounds, format);
    }
  }
}

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

void SelectorImpl::selection_changed(System::Object ^sender, System::EventArgs ^e)
{
  Windows::Forms::ComboBox^ combo= (Windows::Forms::ComboBox^)sender;

  if (combo->Tag != nullptr)
  {
    ::mforms::Selector* sel= ViewImpl::get_backend_control<::mforms::Selector>(combo);
    if (sel != 0)
      sel->callback();
  }
}

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

void SelectorImpl::clear(::mforms::Selector *self)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr)
    selector->get_control<ComboBox>()->Items->Clear();
}

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

int SelectorImpl::add_item(::mforms::Selector *self, const std::string &item)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr)
  {
    ComboBox^ combobox= selector->get_control<ComboBox>();
    if (item == "-")
      combobox->Items->Add(gcnew SeparatorItem(""));
    else
      combobox->Items->Add(CppStringToNative(item));

    int width= compute_content_width(combobox);

    // Do some sanity checks.
    if (width < 50)
      width= 50;
    else
      if (width > 500)
        width= 500;
    combobox->Width= width + 20; // Account for the dropdown arrow.
    combobox->MinimumSize= Size(width + 20, combobox->PreferredSize.Height + 5);
  }
  return 0;
}

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

void SelectorImpl::add_items(::mforms::Selector *self, const std::list<std::string> &items)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr)
  {
    cli::array<Object^> ^strings= gcnew cli::array<Object^>(items.size());
    int i= 0;

    for (std::list<std::string>::const_iterator iter= items.begin(); iter != items.end(); ++iter)
    {
      if (*iter == "-")
        strings[i++]= gcnew SeparatorItem("");
      else
        strings[i++]= CppStringToNative(*iter);
    }

    ComboBox^ combobox= selector->get_control<ComboBox>();
    combobox->Items->AddRange(strings);

    int width= compute_content_width(combobox);

    // Do some sanity checks.
    if (width < 50)
      width= 50;
    else
      if (width > 500)
        width= 500;
    combobox->Width= width + 20; // Account for the dropdown arrow.
    combobox->MinimumSize= Size(width + 20, combobox->PreferredSize.Height);
  }
}

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

std::string SelectorImpl::get_text(::mforms::Selector *self)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr)
  {
    if (selector->get_control<ComboBox>()->SelectedItem != nullptr)
      return NativeToCppString((String^)selector->get_control<ComboBox>()->SelectedItem);
  }
  return "";
}

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

void SelectorImpl::set_index(::mforms::Selector *self, int index)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr && selector->get_control<ComboBox>()->Items->Count > index)
  {
    selector->get_control<ComboBox>()->SelectedIndex= index;
  }
}

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

int SelectorImpl::get_index(::mforms::Selector *self)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr)
  {
    return selector->get_control<ComboBox>()->SelectedIndex;
  }
  return -1;
}

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

int SelectorImpl::get_item_count(::mforms::Selector *self)
{
  SelectorImpl^ selector= (SelectorImpl^)ObjectImpl::FromUnmanaged(self);

  if (selector != nullptr)
  {
    return selector->get_control<ComboBox>()->Items->Count;
  }
  return -1;
}

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

