/*************************************************************************
**
**    OLE 2 Sample Code
**
**    outltxtl.c
**
**    This file contains TextLine methods and related support functions.
**
**    (c) Copyright Microsoft Corp. 1992 - 1996 All Rights Reserved
**
*************************************************************************/


#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;


/* TextLine_Create
 * ---------------
 *
 *      Create a text line object and return the pointer
 */
LPTEXTLINE TextLine_Create(HDC hDC, UINT nTab, LPSTR lpszText)
{
        LPTEXTLINE lpTextLine;

        lpTextLine=(LPTEXTLINE) New((DWORD)sizeof(TEXTLINE));
        if (lpTextLine == NULL) {
                OleDbgAssertSz(lpTextLine!=NULL,"Error allocating TextLine");
                return NULL;
        }

        TextLine_Init(lpTextLine, nTab, hDC);

        if (lpszText) {
                lpTextLine->m_nLength = lstrlen(lpszText);
                lstrcpy((LPSTR)lpTextLine->m_szText, lpszText);
        } else {
                lpTextLine->m_nLength = 0;
                lpTextLine->m_szText[0] = '\0';
        }

        TextLine_CalcExtents(lpTextLine, hDC);

        return(lpTextLine);
}


/* TextLine_Init
 * -------------
 *
 *      Calculate the width/height of a text line object.
 */
void TextLine_Init(LPTEXTLINE lpTextLine, int nTab, HDC hDC)
{
        Line_Init((LPLINE)lpTextLine, nTab, hDC);   // init the base class fields

        ((LPLINE)lpTextLine)->m_lineType = TEXTLINETYPE;
        lpTextLine->m_nLength = 0;
        lpTextLine->m_szText[0] = '\0';
}


/* TextLine_Delete
 * ---------------
 *
 *      Delete the TextLine structure
 */
void TextLine_Delete(LPTEXTLINE lpTextLine)
{
        Delete((LPVOID)lpTextLine);
}


/* TextLine_Edit
 * -------------
 *
 *      Edit the text line object.
 *
 *      Returns TRUE if line was changed
 *              FALSE if the line was NOT changed
 */
BOOL TextLine_Edit(LPTEXTLINE lpLine, HWND hWndDoc, HDC hDC)
{
#if defined( USE_FRAMETOOLS )
        LPFRAMETOOLS lptb = OutlineApp_GetFrameTools(g_lpApp);
#endif
        BOOL fStatus = FALSE;

#if defined( USE_FRAMETOOLS )
        FrameTools_FB_GetEditText(lptb, lpLine->m_szText, sizeof(lpLine->m_szText));
#else
        if (! InputTextDlg(hWndDoc, lpLine->m_szText, "Edit Line"))
                return FALSE;
#endif

        lpLine->m_nLength = lstrlen(lpLine->m_szText);
        TextLine_CalcExtents(lpLine, hDC);
        fStatus = TRUE;

        return fStatus;
}


/* TextLine_CalcExtents
 * --------------------
 *
 *      Calculate the width/height of a text line object.
 */
void TextLine_CalcExtents(LPTEXTLINE lpTextLine, HDC hDC)
{
        SIZE size;
        LPLINE lpLine = (LPLINE)lpTextLine;

        if (lpTextLine->m_nLength) {
                GetTextExtentPoint(hDC, lpTextLine->m_szText,
                                                        lpTextLine->m_nLength, &size);
                lpLine->m_nWidthInHimetric=size.cx;
                lpLine->m_nHeightInHimetric=size.cy;
        } else {
                // we still need to calculate proper height even for NULL string
                TEXTMETRIC tm;
                GetTextMetrics(hDC, &tm);

                // required to set height
                lpLine->m_nHeightInHimetric = tm.tmHeight;
                lpLine->m_nWidthInHimetric = 0;
        }

#if defined( _DEBUG )
        {
                RECT rc;
                rc.left = 0;
                rc.top = 0;
                rc.right = XformWidthInHimetricToPixels(hDC,
                                lpLine->m_nWidthInHimetric);
                rc.bottom = XformHeightInHimetricToPixels(hDC,
                                lpLine->m_nHeightInHimetric);

                OleDbgOutRect3("TextLine_CalcExtents", (LPRECT)&rc);
        }
#endif
}



/* TextLine_SetHeightInHimetric
 * ----------------------------
 *
 *      Set the height of a textline object.
 */
void TextLine_SetHeightInHimetric(LPTEXTLINE lpTextLine, int nHeight)
{
        if (!lpTextLine)
                return;

        ((LPLINE)lpTextLine)->m_nHeightInHimetric = nHeight;
}



/* TextLine_GetTextLen
 * -------------------
 *
 * Return length of string of the TextLine (not considering the tab level).
 */
int TextLine_GetTextLen(LPTEXTLINE lpTextLine)
{
        return lstrlen((LPSTR)lpTextLine->m_szText);
}


/* TextLine_GetTextData
 * --------------------
 *
 * Return the string of the TextLine (not considering the tab level).
 */
void TextLine_GetTextData(LPTEXTLINE lpTextLine, LPSTR lpszBuf)
{
        lstrcpy(lpszBuf, (LPSTR)lpTextLine->m_szText);
}


/* TextLine_GetOutlineData
 * -----------------------
 *
 * Return the CF_OUTLINE format data for the TextLine.
 */
BOOL TextLine_GetOutlineData(LPTEXTLINE lpTextLine, LPTEXTLINE lpBuf)
{
        TextLine_Copy((LPTEXTLINE)lpTextLine, lpBuf);
        return TRUE;
}


/* TextLine_Draw
 * -------------
 *
 *      Draw a text line object on a DC.
 * Parameters:
 *      hDC     - DC to which the line will be drawn
 *      lpRect  - the object rectangle in logical coordinates
 *      lpRectWBounds - bounding rect of the metafile underneath hDC
 *                      (NULL if hDC is not a metafile DC)
 *                      this is used by ContainerLine_Draw to draw the OLE obj
 *      fHighlight    - TRUE use selection highlight text color
 */
void TextLine_Draw(
                LPTEXTLINE  lpTextLine,
                HDC         hDC,
                LPRECT      lpRect,
                LPRECT      lpRectWBounds,
                BOOL        fHighlight
)
{
        RECT rc;
        int nBkMode;
        COLORREF clrefOld;

        if (!lpTextLine)
                return;

        rc = *lpRect;
        rc.left += ((LPLINE)lpTextLine)->m_nTabWidthInHimetric;
        rc.right += ((LPLINE)lpTextLine)->m_nTabWidthInHimetric;

        nBkMode = SetBkMode(hDC, TRANSPARENT);

        if (fHighlight) {
                /*Get proper txt colors */
                clrefOld = SetTextColor(hDC,GetSysColor(COLOR_HIGHLIGHTTEXT));
        }
        else {
                clrefOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
        }

        ExtTextOut(
                        hDC,
                        rc.left,
                        rc.top,
                        ETO_CLIPPED,
                        (LPRECT)&rc,
                        lpTextLine->m_szText,
                        lpTextLine->m_nLength,
                        (LPINT) NULL /* default char spacing */
        );

        SetTextColor(hDC, clrefOld);
        SetBkMode(hDC, nBkMode);
}

/* TextLine_DrawSelHilight
 * -----------------------
 *
 *      Handles selection of textline
 */
void TextLine_DrawSelHilight(LPTEXTLINE lpTextLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState)
{
        if (itemAction & ODA_SELECT) {
                // check if there is a selection state change, ==> invert rect
                if (itemState & ODS_SELECTED) {
                        if (!((LPLINE)lpTextLine)->m_fSelected) {
                                ((LPLINE)lpTextLine)->m_fSelected = TRUE;
                                InvertRect(hDC, (LPRECT)lpRect);
                        }
                } else {
                        if (((LPLINE)lpTextLine)->m_fSelected) {
                                ((LPLINE)lpTextLine)->m_fSelected = FALSE;
                                InvertRect(hDC, lpRect);
                        }
                }
        } else if (itemAction & ODA_DRAWENTIRE) {
                ((LPLINE)lpTextLine)->m_fSelected=((itemState & ODS_SELECTED) ? TRUE : FALSE);
                InvertRect(hDC, lpRect);
        }
}

/* TextLine_Copy
 * -------------
 *
 *      Duplicate a textline
 */
BOOL TextLine_Copy(LPTEXTLINE lpSrcLine, LPTEXTLINE lpDestLine)
{
        _fmemcpy(lpDestLine, lpSrcLine, sizeof(TEXTLINE));
        return TRUE;
}


/* TextLine_CopyToDoc
 * ------------------
 *
 *      Copy a textline to another Document (usually ClipboardDoc)
 */
BOOL TextLine_CopyToDoc(LPTEXTLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex)
{
        LPTEXTLINE  lpDestLine;
        BOOL        fStatus = FALSE;

        lpDestLine = (LPTEXTLINE) New((DWORD)sizeof(TEXTLINE));
        if (lpDestLine == NULL) {
                OleDbgAssertSz(lpDestLine!=NULL,"Error allocating TextLine");
                return FALSE;
        }

        if (TextLine_Copy(lpSrcLine, lpDestLine)) {
                OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex);
                fStatus = TRUE;
        }

        return fStatus;
}


/* TextLine_SaveToStg
 * ------------------
 *
 *      Save a textline into a storage
 *
 *      Return TRUE if successful, FALSE otherwise
 */
BOOL TextLine_SaveToStm(LPTEXTLINE lpTextLine, LPSTREAM lpLLStm)
{
        HRESULT hrErr;
        ULONG nWritten;
        USHORT nLengthOnDisk;

        nLengthOnDisk = (USHORT) lpTextLine->m_nLength;

        hrErr = lpLLStm->lpVtbl->Write(
                        lpLLStm,
                        (LPVOID)&nLengthOnDisk,
                        sizeof(nLengthOnDisk),
                        &nWritten
        );
        if (hrErr != NOERROR) {
                OleDbgOutHResult("Write TextLine data (1) returned", hrErr);
                return FALSE;
    }

        hrErr = lpLLStm->lpVtbl->Write(
                        lpLLStm,
                        (LPVOID)lpTextLine->m_szText,
                        lpTextLine->m_nLength,
                        &nWritten
        );
        if (hrErr != NOERROR) {
                OleDbgOutHResult("Write TextLine data (2) returned", hrErr);
                return FALSE;
    }

        return TRUE;
}


/* TextLine_LoadFromStg
 * --------------------
 *
 *      Load a textline from storage
 */
LPLINE TextLine_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc)
{
        HRESULT hrErr;
        ULONG nRead;
        LPTEXTLINE lpTextLine;
        USHORT nLengthOnDisk;

        lpTextLine=(LPTEXTLINE) New((DWORD)sizeof(TEXTLINE));
        if (lpTextLine == NULL) {
                OleDbgAssertSz(lpTextLine!=NULL,"Error allocating TextLine");
                return NULL;
        }

        TextLine_Init(lpTextLine, 0, NULL);

        hrErr = lpLLStm->lpVtbl->Read(
                        lpLLStm,
                        (LPVOID)&nLengthOnDisk,
                        sizeof(nLengthOnDisk),
                        &nRead
        );
        if (hrErr != NOERROR) {
                OleDbgOutHResult("Read TextLine data (1) returned", hrErr);
                return NULL;
    }

        lpTextLine->m_nLength = (UINT) nLengthOnDisk;
        OleDbgAssert(lpTextLine->m_nLength < sizeof(lpTextLine->m_szText));

        hrErr = lpLLStm->lpVtbl->Read(
                        lpLLStm,
                        (LPVOID)&lpTextLine->m_szText,
                        lpTextLine->m_nLength,
                        &nRead
        );
        if (hrErr != NOERROR) {
                OleDbgOutHResult("Read TextLine data (1) returned", hrErr);
                return NULL;
    }

        lpTextLine->m_szText[lpTextLine->m_nLength] = '\0'; // add str terminator

        return (LPLINE)lpTextLine;
}
