// IPlusPlus -- MetricsB -- Vertical Scrolling

using namespace System;
using namespace IPlusPlus;
using namespace IPlusPlus::Control;
using namespace IPlusPlus::Windows;
using namespace IPlusPlus::Graphics;

#include "Metrics.h"

void* __stdcall Client(void*,unsigned,void*,void*);

template<class T>
inline T maximum(T a, T b) {return a>b ? a : b;};

template<class T>
inline T minimum(T a, T b) {return a<b ? a : b;};


[STAThreadAttribute]
int main()
{
 WindowClass^ Class = gcnew WindowClass();

 Class->Style     = (unsigned)ClassStyle::HorizontalRedraw | (unsigned)ClassStyle::VerticalRedraw;
 Class->Procedure = Handle((void*)Client);
 Class->Extra     = 0;
 Class->Window    = 0;
 Class->Module    = Base::Getmodule_handle();
 Class->Icon      = Win::LoadIcon(Handle((void*)0),(unsigned)IconIdentity::application);
 Class->Cursor    = Win::LoadCursor(Handle((void*)0),(unsigned)CursorIdentity::arrow);
 Class->Brush     = Gdi::GetStandardObject((int)StandardBrush::white);
 Class->Name      = gcnew String("C Window Class");
 Class->Menu      = gcnew String("");

 unsigned short AtomName = Win::RegisterClass(Class);

 Handle Window = Win::CreateWindow(AtomName,
                                   gcnew String("MetricsA"),
                                   (unsigned)Style::Standard,
                                   (int)Defaults::UseDefault,
                                   (int)Defaults::UseDefault,
                                   (int)Defaults::UseDefault,
                                   (int)Defaults::UseDefault,
                                   Handle((void*)0),
                                   Handle((void*)0),
                                   Handle((void*)0),
                                   Handle((void*)0));

 Win::ShowWindow(Window);

 return Win::Run();
}

void* __stdcall Client(void* window,
                       unsigned Identity,
                       void* parameter1,
                       void* parameter2)
{
 Handle Window(window);
 Handle Parameter1(parameter1);
 Handle Parameter2(parameter2);

 static int WidthOfCharacter,
            HeightOfCharacter,
            WidthOfCapitals,
            PositionOfVerticalScroll,
            HeightOfClient;

 switch(Identity)
  {
   case (unsigned)Message::Create:
    {
     Handle DeviceContext = Gdi::GetDeviceContext(Window);

     TextMetrics^ TextMetricsGet = Gdi::GetTextMetrics(DeviceContext);

     WidthOfCharacter = TextMetricsGet->AverageCharacterWidth;

     WidthOfCapitals = (TextMetricsGet->PitchAndFamily & 1 ? 3 : 2) * WidthOfCharacter/2;

     HeightOfCharacter = TextMetricsGet->Height + TextMetricsGet->ExternalLeading;

     Gdi::ReleaseDeviceContext(Window,DeviceContext);
    }

    Win::SetScrollRange(Window,(int)ScrollbarIdentity::Vertical,0,Lines,false);
    Win::SetScrollPosition(Window,(int)ScrollbarIdentity::Vertical,PositionOfVerticalScroll,true);
    break;

   case (unsigned)Message::Size:
    HeightOfClient = Parameter2.HighPart;
    break;

   case (unsigned)Message::VerticalScroll:
     switch(Parameter1.LowPart)
      {
       case ScrollbarNotify::LineUp:
        PositionOfVerticalScroll -= 1;
        break;

       case ScrollbarNotify::LineDown:
        PositionOfVerticalScroll += 1;
        break;

       case ScrollbarNotify::PageUp:
        PositionOfVerticalScroll -= HeightOfClient / HeightOfCharacter;
        break;

       case ScrollbarNotify::PageDown:
        PositionOfVerticalScroll += HeightOfClient / HeightOfCharacter;
        break;

       case ScrollbarNotify::SliderPosition:
        PositionOfVerticalScroll = Parameter1.HighPart;
        break;
      }

     PositionOfVerticalScroll = maximum(0,minimum(PositionOfVerticalScroll,(int)Lines));

     if (PositionOfVerticalScroll != Win::GetScrollPosition(Window,(int)ScrollbarIdentity::Vertical))
      {
        Win::SetScrollPosition(Window,(int)ScrollbarIdentity::Vertical,PositionOfVerticalScroll,true);
        Win::InvalidateRectangle(Window,true);
      }
     break;

   case (unsigned)Message::Close:
    if (Win::MessageBox(Window,
                        gcnew String("Exit?"),
                        gcnew String("I++"),
                        (unsigned)MessageBoxStyle::OKCancel | (unsigned)MessageBoxStyle::IconQuestion) == (UInt32)ItemIdentity::OK)
       Win::PostQuitMessage(0);
    break;

   case (unsigned)Message::Paint:
    {
     Paint^ PaintStruct = gcnew Paint();

     Handle DeviceContext = Gdi::BeginPaint(Window,PaintStruct);

     enum {Column1=30, Column2=40};

     for (int i=0; i<Lines; i++)
      {
       int y = HeightOfCharacter * (1 - PositionOfVerticalScroll + i);

       Gdi::TextOut(DeviceContext,
                    WidthOfCharacter,
                    y,
                    gcnew String("SystemMetric::") + (Metrics[i].Index).ToString());

       Gdi::TextOut(DeviceContext,
                    WidthOfCharacter + Column1 * WidthOfCapitals,
                    y,
                    gcnew String(Metrics[i].Description));

       Gdi::SetTextAlignment(DeviceContext,(int)TextAlignment::Right | (int)TextAlignment::Top);

       Gdi::TextOut(DeviceContext,
                    WidthOfCharacter + Column1 * WidthOfCapitals + Column2 * WidthOfCharacter,
                    y,
                    Win::GetSystemMetrics((int)Metrics[i].Index).ToString());

       Gdi::SetTextAlignment(DeviceContext,(int)TextAlignment::Left | (int)TextAlignment::Top);
     }

     Gdi::EndPaint(Window,PaintStruct);
    }
    break;

   default:
    return Win::DefaultWindowProcedure(Window,Identity,Parameter1,Parameter2);
  }
 return 0;
}