//-----------------------------------------------------------------------------
// Name: FontMakerWnd.cpp
//
// Desc: The window and scroll view class for the fontmaker app
//
// Hist: 09.06.02 - Revised Fontmaker sample
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "FontMaker.h"
#include "Glyphs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CTextureFont g_Font;
BOOL        g_bIsGlyphSelected     = FALSE;
int         g_iSelectedGlyphNum    = 0;
WCHAR       g_cSelectedGlyph       = '\0';
GLYPH_ATTR* g_pSelectedGylph       = NULL;

// Colors
#define COLOR_WHITE   ( RGB(255,255,255) )
#define COLOR_BLACK   ( RGB(  0,  0,  0) )
#define COLOR_BLUE    ( RGB(  0,  0,255) )
#define COLOR_RED     ( RGB(255,  0,  0) )
#define COLOR_DARKRED ( RGB(128,  0,  0) )

//-----------------------------------------------------------------------------
// CFontMakerFrameWnd
//-----------------------------------------------------------------------------

IMPLEMENT_DYNCREATE(CFontMakerFrameWnd, CFrameWnd)

BEGIN_MESSAGE_MAP(CFontMakerFrameWnd, CFrameWnd)
    //{{AFX_MSG_MAP(CFontMakerFrameWnd)
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

int CFontMakerFrameWnd::OnCreate( LPCREATESTRUCT pCreateStruct )
{
    if( CFrameWnd::OnCreate( pCreateStruct ) == -1 )
        return -1;

    // Create a docked dialog bar
    EnableDocking( CBRS_ALIGN_ANY );
    if( !m_wndDialogBar.Create( this, IDD_DIALOGBAR,
                                CBRS_LEFT, IDD_DIALOGBAR ) )
    {
        TRACE0("Failed to create DlgBar\n");
        return -1;
    }

    return 0;
}

//-----------------------------------------------------------------------------
// CFontMakerView
//-----------------------------------------------------------------------------

IMPLEMENT_DYNCREATE(CFontMakerView, CScrollView)

BEGIN_MESSAGE_MAP(CFontMakerView, CScrollView)
    //{{AFX_MSG_MAP(CFontMakerView)
    ON_WM_LBUTTONDOWN()
    ON_WM_ERASEBKGND()
    ON_WM_KEYDOWN()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//-----------------------------------------------------------------------------
// Name: ~CFontMakerView()
// Desc: Destructor with special cleanup
//-----------------------------------------------------------------------------
CFontMakerView::~CFontMakerView()
{
    // Cleanup before exitting
    m_memDC.DeleteDC();
}

//-----------------------------------------------------------------------------
// Name: OnInitialUpdate()
// Desc: Called when the view is created.
//-----------------------------------------------------------------------------
void CFontMakerView::OnInitialUpdate()
{
    // Set the scroll bars
    CScrollView::OnInitialUpdate();
    CSize szTotal( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight );
    SetScrollSizes( MM_TEXT, szTotal );
    CPoint ptCenter( 0, 0 );
    CenterOnPoint( ptCenter );

    // Create a secondary DC, used for drawing
    m_memDC.CreateCompatibleDC( GetDC() );
}

//-----------------------------------------------------------------------------
// Name: OnEraseBkgnd()
// Desc: Overridden function to prevent the view from flickering during resizes
//       and redraws
//-----------------------------------------------------------------------------
BOOL CFontMakerView::OnEraseBkgnd( CDC* pDC ) 
{
    return TRUE;
}

//-----------------------------------------------------------------------------
// Name: RenderSelectedGlyph() 
// Desc: Highlight the selected glyph
//-----------------------------------------------------------------------------
VOID RenderSelectedGlyph( CDC* pDC )
{
    // If no glyph is selected, return
    if( FALSE == g_bIsGlyphSelected )
        return;

    HRGN rgn = CreateRectRgn( 0, 0, g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight );
    SelectClipRgn( pDC->m_hDC, rgn );

    // Draw a higlighted background for the selected glyph
    {
        int x = g_pSelectedGylph->x;
        int y = g_pSelectedGylph->y;
        int w = g_pSelectedGylph->w;
        int h = g_pSelectedGylph->h;
        pDC->FillSolidRect( x, y, w, h, COLOR_DARKRED );
    }

    // Setup the DC for drawing text
    pDC->SetTextColor( COLOR_WHITE );
    pDC->SelectObject( g_Font.m_hFont );
    pDC->SetTextAlign( TA_LEFT|TA_TOP );
    pDC->SetMapMode( MM_TEXT );
    pDC->SetBkMode( TRANSPARENT );
    pDC->SetBkColor( COLOR_BLUE );

    CPen pen( PS_SOLID, 1, COLOR_RED );
    pDC->SelectObject( &pen );

    // Render the selected glyph
    GLYPH_ATTR* pGlyph = g_pSelectedGylph;
    {
        WCHAR c = g_cSelectedGlyph;
        WCHAR str[2] = L"A";
        str[0] = c ? c : 0xffff;

        if ( g_Font.m_ValidGlyphs[c] == 2 )
        {
            // Draw a square box for a placeholder for custom glyph graphics
            pDC->FillSolidRect( pGlyph->x, pGlyph->y, pGlyph->w, pGlyph->h, COLOR_BLACK );
        }
        else
        {
            int sx = pGlyph->x;
            int sy = pGlyph->y;

            // Adjust ccordinates to account for the leading edge
            if ( str[0] > 0x1000 )
            {
            }
            else
            {
                sx -= pGlyph->a;

                if ( g_Font.m_bOutlineEffect )
                    sx -= 1;
            }

            if ( g_Font.m_bOutlineEffect )
            {
                sx++;
                sy++;

                pDC->SetTextColor( COLOR_BLACK );
                ExtTextOutW( pDC->m_hDC, sx-1, sy-1, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx+0, sy-1, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx+1, sy-1, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx-1, sy+0, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx+1, sy+0, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx-1, sy+1, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx+0, sy+1, ETO_OPAQUE, NULL, str, 1, NULL );
                ExtTextOutW( pDC->m_hDC, sx+1, sy+1, ETO_OPAQUE, NULL, str, 1, NULL );
            }

            if ( g_Font.m_bShadowEffect )
            {
                pDC->SetTextColor( COLOR_BLACK );
                ExtTextOutW( pDC->m_hDC, sx+2, sy+2, ETO_OPAQUE, NULL, str, 1, NULL );
            }

            // Output the letter
            pDC->SetTextColor( COLOR_WHITE );
            ExtTextOutW( pDC->m_hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL );
        }
    }

    // Draw a red outline around the selected glyph
    {
        // Create a red pen
        CPen pen( PS_SOLID, 1, COLOR_RED );
        pDC->SelectObject( &pen );

        // Draw the outline
        int x1 = pGlyph->x - 1;
        int y1 = pGlyph->y - 1;
        int x2 = pGlyph->x + pGlyph->w;
        int y2 = pGlyph->y + pGlyph->h;

        pDC->MoveTo( x1, y1 );
        pDC->LineTo( x2, y1 );
        pDC->LineTo( x2, y2 );
        pDC->LineTo( x1, y2 );
        pDC->LineTo( x1, y1 );
    }

    SelectClipRgn( pDC->m_hDC, NULL );
    DeleteObject( rgn );
}

//-----------------------------------------------------------------------------
// Name: OnDraw()
// Desc: Overridden draw function. Draws the font glyphs if a font is loaded,
//       else just a black background.
//-----------------------------------------------------------------------------
VOID CFontMakerView::OnNewFontGlyphs()
{
    // Select the resulting bits into our memory DC
    static CBitmap Bitmap;
    Bitmap.DeleteObject();
    Bitmap.CreateBitmap( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight, 1, 32, g_Font.m_pBits );
    m_memDC.SelectObject( &Bitmap );

    // Trigger the view to be re-drawn
    OnUpdate(0,0,0);
}

//-----------------------------------------------------------------------------
// Name: OnDraw()
// Desc: Overridden draw function. Draws the font glyphs if a font is loaded,
//       else just a black background.
//-----------------------------------------------------------------------------
VOID CFontMakerView::OnDraw( CDC* pDC )
{
    RECT rc;
    GetClientRect( &rc );

    // Draw the view
    if ( g_Font.m_hFont == NULL && !g_Font.m_pCustomFilename )
    {
        // Don't display any scroll bars
        CSize sizeTotal( 0, 0 );
        SetScrollSizes( MM_TEXT, sizeTotal );

        // Draw a black background
        pDC->FillSolidRect( 0, 0, rc.right, rc.bottom, COLOR_BLACK );
    }
    else
    {
        // Set the scroll sizes for the view
        CSize sizeTotal( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight );
        SetScrollSizes( MM_TEXT, sizeTotal );

        // Draw the view's black areas
        pDC->FillSolidRect( g_Font.m_dwTextureWidth, 0, max( (int)g_Font.m_dwTextureWidth, rc.right), g_Font.m_dwTextureHeight, COLOR_BLACK );
        pDC->FillSolidRect( 0, g_Font.m_dwTextureHeight, max( (int)g_Font.m_dwTextureWidth, rc.right), max( (int)g_Font.m_dwTextureHeight, rc.bottom), COLOR_BLACK );

        // Display the bitmap of all the rendered glyphs
        pDC->BitBlt( 0, 0, g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight, &m_memDC, 0, 0, SRCCOPY );
    
        // Draw the selected glyph, if any
        RenderSelectedGlyph( pDC );
    }
}

//-----------------------------------------------------------------------------
// Name: OnLButtonDown()
// Desc: Overridden function to select a glyph when the user clicks the mouse.
//-----------------------------------------------------------------------------
void CFontMakerView::OnLButtonDown( UINT nFlags, CPoint point ) 
{
	if ( !g_Font.m_hFont )
		return;

    // Correct the mouseclick point to account for the scroll position
    point += GetScrollPosition();

    // Find out which glyph, if any, is selected by the mouse click
    theApp.UpdateSelectedGlyph( FALSE );
    
    for( DWORD i=0; i<g_Font.m_dwNumGlyphs && g_Font.m_pGlyphs; i++ )
    {
        GLYPH_ATTR* pGlyph = &g_Font.m_pGlyphs[i];
    
        if ( point.x >= pGlyph->x-2 && point.x <= pGlyph->x + pGlyph->w )
        {
            if ( point.y >= pGlyph->y-2 && point.y <= pGlyph->y + pGlyph->h )
            {
                theApp.UpdateSelectedGlyph( TRUE, i );
                break;
            }
        }
    }

    // Redraw the view to show the newly selected glyph
    Invalidate( TRUE );

    // Call the base class' handler
    CScrollView::OnLButtonDown( nFlags, point );
}

//-----------------------------------------------------------------------------
// Name: OnKeyDown()
// Desc: Overridden function to select a glyph with the keyboard.
//-----------------------------------------------------------------------------
void CFontMakerView::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) 
{
	if ( !g_Font.m_hFont )
		return;
	
	if( g_Font.m_dwNumGlyphs > 0 )
    {
        if( FALSE == g_bIsGlyphSelected )
        {
            if( nChar == 37 || nChar == 38 || nChar == 39 || nChar == 40 ) // Left, right, up or down
            {
                // Select the first glyph
                theApp.UpdateSelectedGlyph( TRUE, 0 );
            }
        }
        else
        {
            if( nChar == 37 ) // Left
                theApp.UpdateSelectedGlyph( TRUE, max( 0, g_iSelectedGlyphNum-1 ) );
            else if( nChar == 39 ) // Right
                theApp.UpdateSelectedGlyph( TRUE, min( (int)g_Font.m_dwNumGlyphs-1, g_iSelectedGlyphNum+1 ) );
            else if( nChar == 38 || nChar == 40 ) // Up or down
            {
                // Find the closest glyph above or below to move to
                int x = g_pSelectedGylph->x + g_pSelectedGylph->w/2;
                int y = g_pSelectedGylph->y + g_pSelectedGylph->h/2;

                if( nChar == 38 ) y -= g_pSelectedGylph->h;
                if( nChar == 40 ) y += g_pSelectedGylph->h;

                for( DWORD i=0; i<g_Font.m_dwNumGlyphs; i++ )
                {
                    GLYPH_ATTR* pGlyph = &g_Font.m_pGlyphs[i];
                
                    if( x >= pGlyph->x-2 && x <= pGlyph->x + pGlyph->w )
                    {
                        if( y >= pGlyph->y-2 && y <= pGlyph->y + pGlyph->h )
                        {
                            theApp.UpdateSelectedGlyph( TRUE, i );
                            break;
                        }
                    }
                }
            }
			else if ( nChar == 46 )
			{
				// delete a glyph
				theApp.OnGlyphsCustom();

				// mark glyph as invalid
				g_Font.DeleteGlyph( g_cSelectedGlyph );

				// reset to the first glyph
				theApp.UpdateSelectedGlyph( FALSE );
			}
			else if ( nChar == 45 )
			{
				// insert a glyph
				theApp.OnGlyphsCustom();

				// reset to the first glyph
				theApp.UpdateSelectedGlyph( FALSE );
			
				theApp.InsertGlyph();
			}
        }

        // Redraw the view to show the newly selected glyph
        Invalidate( TRUE );
    }

    CScrollView::OnKeyDown( nChar, nRepCnt, nFlags );
}