/* @(#) 1.11 nt/src/samples/mandel/iodmandl.cpp, odmandelpart, od96nt, odnt9712d 3/4/97 18:22:51 [3/21/97 17:36:44] */
//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: odother
//
//   CLASSES: none
//
//   ORIGINS: 82,27
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//

#ifndef SOM_Module_mandel_Source
#define SOM_Module_mandel_Source
#endif
#define Mandelbrot_Class_Source
#define M_Mandelbrot_Class_Source

#include <stdio.h>

// Include ODExcept.h before OpenDoc SOM headers
#include <ODExcept.h>

#include <ODRes.h>

#include <ODTypesF.h>
#include <tempobj.h>
#include <Platcanv.xh>

#ifndef SOM_ODCanvas_xh
#include <Canvas.xh>
#endif

#ifndef SOM_ODFacet_xh
#include <Facet.xh>
#endif

#ifndef SOM_ODFrame_xh
#include <Frame.xh>
#endif

#ifndef SOM_ODFrameFacetIterator_xh
#include <FrFaItr.xh>
#endif

#ifndef SOM_ODSession_xh
#include <ODSessn.xh>
#endif

#ifndef SOM_ODShape_xh
#include <Shape.xh>
#endif

#ifndef SOM_ODTransform_xh
#include <Trnsform.xh>
#endif

#ifndef SOM_ODStorageUnit_xh
#include <StorageU.xh>
#endif

#ifndef _FOCUSLIB_
#include <focuslib.h>
#endif

#ifndef SOM_ODMenuBar_xh
#include <MenuBar.xh>
#endif

#ifndef _ODUTILS_
#include "ODUtils.h"
#endif

#ifndef _ODMATH_
#include "ODMath.h"
#endif

#include "iodmandl.h"

#define VARIABLE_MACROS
#include "iodmandl.xih"


/////////////////////////////////////////////////////////////////////////////
//
// void somInit(Mandelbrot *somSelf)
//
// Description:  override of standard object initialization
//
// Parameters:   somSelf	the object
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotsomInit(Mandelbrot *somSelf)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotsomInit");

    Mandelbrot_parent_SimplePart_somInit(somSelf);
    somThis->fSession = kODNULL;
    somThis->fPartWrapper = kODNULL;
    somThis->fIterationLimit = kODIterationStep;
    somThis->fResetZoom = kODTrue;
}


/////////////////////////////////////////////////////////////////////////////
//
// void somUninit(Mandelbrot *somSelf)
//
// Description:  override of standard object destruction
//
// Parameters:   somSelf	the object
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotsomUninit(Mandelbrot *somSelf)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","ManjdelbrotsomUninit");

    Mandelbrot_parent_SimplePart_somUninit(somSelf);
}


/////////////////////////////////////////////////////////////////////////////
//
// void InstallMenus()
//
// Description:  Create the Mandelbrot menu and add it to the menu bar
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotInstallMenus(Mandelbrot *somSelf,
                                                Environment *ev)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotInstallMenus");

    ODMenuBar		*menuBar;
    ODPlatformMenuItem	*mi;
    ODPlatformMenu	mandelMenu;

    try
    {
	// Get the menu bar
	menuBar = somSelf->GetMenuBar(ev);

        // Add the Mandelbrot menu to the menu bar
        mi = new ODPlatformMenuItem;
        mi->afAttribute = 0;
        mi->id = kODMandelbrotMenuID;
        mandelMenu = (ODPlatformMenu)CreateMenu();
        menuBar->AddMenuLast(ev, kODMandelbrotMenuID, mandelMenu,
                               _fPartWrapper);
        menuBar->SetMenuItemText(ev, ID_BASEMENUBAR, mi->id, "Mandelbrot");

        // Add the "Zoom In" menu item
        mi->id = kODCommandZoom;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);
        menuBar->SetMenuItemText(ev, kODMandelbrotMenuID,
				    kODCommandZoom, "Zoom In");

        // Add the "Zoom Out" menu item
        mi->id = kODCommandUnzoom;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);
        menuBar->SetMenuItemText(ev, kODMandelbrotMenuID,
				    kODCommandUnzoom, "Zoom Out");

        // Add the "Reset" menu item
        mi->id = kODCommandReset;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);
        menuBar->SetMenuItemText(ev, kODMandelbrotMenuID,
				    kODCommandReset, "Reset Zoom");

        // Add a separator
        mi->id = kODCommandSeparator;
        mi->afAttribute = MF_SEPARATOR;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);

        // Add the "Increase Iterations" menu item
        mi->id = kODCommandIncreaseIterations;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);
        menuBar->SetMenuItemText(ev, kODMandelbrotMenuID,
			   kODCommandIncreaseIterations, "Increase Iterations");

        // Add the "Reset Iterations" menu item
        mi->id = kODCommandResetIterations;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);
        menuBar->SetMenuItemText(ev, kODMandelbrotMenuID,
			    kODCommandResetIterations, "Reset Iterations");

        // Add a separator
        mi->id = kODCommandSeparator2;
        mi->afAttribute = MF_SEPARATOR;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);

        // Add the "Info..." menu item
        mi->id = kODCommandInfo;
        menuBar->AddMenuItemLast(ev, kODMandelbrotMenuID, kODNULL, mi);
        menuBar->SetMenuItemText(ev, kODMandelbrotMenuID,
			    kODCommandInfo, "Info...");
    }

    catch(ODException _exception)
    {
    }
}

/////////////////////////////////////////////////////////////////////////////
//
// ODBoolean AdjustMenus(ODFrame *frame)
//
// Description:  Enable / disable the appropriate menu items
//
// Parameters:   frame	// the frame in which the event occurred
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotAdjustMenus(Mandelbrot *somSelf,
                                               Environment *ev,
                                              ODFrame* frame)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotAdjustMenus");

   try
   {
     // Disable unsupported menu items
     ODMenuBar *menuBar = somSelf->GetMenuBar(ev);
     menuBar->EnableMenuItem(ev, IDMS_DOCUMENT, DOC_SETUP, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_DOCUMENT, DOC_PRINT, kODFalse);

     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_CREATE, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_CUT, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_COPY, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_PASTE, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_PASTEAS, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_LINK_MENU, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_DELETE, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_SELECTALL, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_DESELECTALL, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_OPENSEL, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_SELPROPERTIES, kODFalse);
     menuBar->EnableMenuItem(ev, IDMS_EDIT, EDIT_INSERT, kODFalse);
   }
   catch(ODException _exception)
   {
   }

}


/////////////////////////////////////////////////////////////////////////////
//
// ODBoolean HandleEvent(ODEventData *event, ODFrame *frame, ODFacet *facet
//                       ODEventInfo *eventInfo)
//
// Description:  Handle the event
//
// Parameters:   event	// the mouse down event
//               frame	// the frame in which the event occurred
//               facet	// the facet in which the event occurred
//
// Returns:      kODTrue: the event is always marked as handled
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope ODBoolean  SOMLINK MandelbrotHandleEvent(Mandelbrot *somSelf,
                                                    Environment *ev,
                                                    ODEventData* event,
                                                    ODFrame* frame,
                                                    ODFacet* facet,
                                                    ODEventInfo* eventInfo)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotHandleEvent");

    ODBoolean handled = kODFalse;

    try
    {
        switch (event->message)
        {

            case WM_LBUTTONDOWN:
            {
                //qprintf("Received WM_LBUTTONDOWN message\n");
                somSelf->Activate(ev, facet);
                handled = somSelf->HandleMouseDown(ev, event, facet);
            }
            break;

            case WM_LBUTTONUP:
            {
                //qprintf("Received WM_LBUTTONUP message\n");
                handled = somSelf->HandleMouseUp(ev, event, facet);
            }
            break;

            default:
                Mandelbrot_parent_SimplePart_HandleEvent(somSelf, ev, event,
			frame, facet, eventInfo);
        }
    }

    catch(ODException _exception)
    {
    }

    return handled;
}


/////////////////////////////////////////////////////////////////////////////
//
// ODBoolean HandleMouseDown(ODEventData *event, ODFacet *facet)
//
// Description:  If a zoom operation is in progress use the mouse
//               down coordinates as the initial point of the zoom area
//
// Parameters:   event	// the mouse down event
//               facet	// the facet in which the event occurred
//
// Returns:      kODTrue: the event is always marked as handled
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope ODBoolean  SOMLINK MandelbrotHandleMouseDown(Mandelbrot *somSelf,
                                                        Environment *ev,
                                                       ODEventData* event,
                                                       ODFacet* facet)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotHandleMouseDown");

    //qprintf("Mouse down at (%d,%d)\n", LOWORD(event->lParam),
					//HIWORD(event->lParam));

    if (_fZoomInProgress)
    {
        // Transform from absolute coord's to the frame's coord's
        TempODTransform xform = facet->AcquireWindowFrameTransform(ev, kODNULL);
        ODPoint mouse;
        mouse.x = ODIntToFixed(LOWORD(event->lParam));
        mouse.y = ODIntToFixed(HIWORD(event->lParam));
        xform->InvertPoint(ev, &mouse);
        //qprintf("Mouse down at x(%d,%d)\n", ODFixedRound(mouse.x),
					//ODFixedRound(mouse.y));

        // Save the initial point of the zoom area
        _fx0 = _fwinx0 = ODFixedRound(mouse.x);
        _fy0 = _fwiny0 = ODFixedRound(mouse.y);
        _fZoomWidth = _fZoomHeight = 0;
    }

    return kODTrue;
}


/////////////////////////////////////////////////////////////////////////////
//
// ODBoolean HandleMouseUp(ODEventData *event, ODFacet *facet)
//
// Description:  If a zoom operation is in progress use the mouse
//               up coordinates to complete the zoom.
//
// Parameters:   event	// the mouse up event
//               facet	// the facet in which the event occurred
//
// Returns:      kODTrue: the event is always marked as handled
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope ODBoolean  SOMLINK MandelbrotHandleMouseUp(Mandelbrot *somSelf,
                                                        Environment *ev,
                                                       ODEventData* event,
                                                       ODFacet* facet)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotHandleMouseUp");

    double tw, th;

    if (_fZoomInProgress)
    {
        // Transform from absolute coord's to the frame's coord's
        //qprintf("Mouse up at (%d,%d)\n", LOWORD(event->lParam),
					//HIWORD(event->lParam));
        TempODTransform xform = facet->AcquireWindowFrameTransform(ev, kODNULL);
        ODPoint mouse;
        mouse.x = ODIntToFixed(LOWORD(event->lParam));
        mouse.y = ODIntToFixed(HIWORD(event->lParam));
        xform->InvertPoint(ev, &mouse);
        //qprintf("Mouse down at x(%d,%d)\n", ODFixedRound(mouse.x),
					    //ODFixedRound(mouse.y));

        // Record the zoom data
        _fwinx1 = ODFixedRound(mouse.x);
        _fwiny1 = ODFixedRound(mouse.y);
        if ((_fZoomWidth = _fwinx1 - _fwinx0) < 0)
            _fZoomWidth = -_fZoomWidth;
        if ((_fZoomHeight = _fwiny1 - _fwiny0) < 0)
            _fZoomHeight = -_fZoomHeight;
        if (_fZoomWidth < _fZoomHeight)
            _fZoomWidth = _fZoomHeight;
        _fx0 = (_fwinx1 > _fwinx0) ? _fwinx0 : _fwinx0 - _fZoomWidth;
        _fy0 = (_fwiny1 > _fwiny0) ? _fwiny0 : _fwiny0 - _fZoomWidth;
        _fx1 = _fx0 + _fZoomWidth;
        _fy1 = _fy0 + _fZoomWidth;
        tw = _fZoom->ux - _fZoom->lx;
        th = _fZoom->uy - _fZoom->ly;
        _fNewZoom = (struct ZoomType*) malloc(sizeof (struct ZoomType));
        _fNewZoom->zp = _fZoom; // push onto the stack
        _fNewZoom->ux = _fZoom->lx + ((double)_fx1/(double)_fWidth) * tw;
        _fNewZoom->lx = _fZoom->lx + ((double)_fx0/(double)_fWidth) * tw;
        _fNewZoom->ly = _fZoom->uy - ((double)_fy1/(double)_fHeight) * th;
        _fNewZoom->uy = _fZoom->uy - ((double)_fy0/(double)_fHeight) * th;
        _fZoom = _fNewZoom;

        // Now recalculate and draw
	somSelf->Draw(ev, facet, kODNULL);

        // Clean up
        _fZoomInProgress = kODFalse;
    }

    return kODTrue;
}

/////////////////////////////////////////////////////////////////////////////
//
// ODBoolean HandleMenuEvent(ODEventData *event, ODFacet *facet)
//
// Description:  Invoke the method corresonding to the selected
//               menu item
//
// Parameters:   event		// the mouse up event
//               focusFrame	// the facet in which the event occurred
//
// Returns:      kODTrue: the event is always marked as handled
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope ODBoolean  SOMLINK MandelbrotHandleMenuEvent(Mandelbrot *somSelf,
                                                        Environment *ev,
                                                       ODFrame* focusFrame,
                                                       ODEventData* event)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotHandleMenuEvent");

    // default return value
    ODBoolean handled = kODFalse;

    //qprintf("Received menu item %d\n", event->wParam);

    try
    {
        // determine the menu item and handle it
        ODCommandID command = event->wParam;
        switch (command)
        {
            case kODCommandZoom:
                // Set the flag indicating a zoom is in progress
                //qprintf("Zoom menu item selected\n");
                _fZoomInProgress = kODTrue;
		handled = kODTrue;
                break;

            case kODCommandUnzoom:
                // Abandon the current zoom and return to the previous one
                //qprintf("Unzoom menu item selected\n");
                if (_fZoom && _fZoom->zp)
                {
                    _fNewZoom = _fZoom->zp;
                    free(_fZoom);
                    _fZoom = _fNewZoom;
                    somSelf->Draw(ev, _fFacet, kODNULL);
                }
		handled = kODTrue;
                break;

            case kODCommandReset:
                // Set the flag indicating a zoom reset is needed, then Draw
                //qprintf("Reset menu item selected\n");
                _fResetZoom = kODTrue;
                somSelf->Draw(ev, _fFacet, kODNULL);
		handled = kODTrue;
                break;

            case kODCommandIncreaseIterations:
                // Increase the iteration limit, then Draw
                //qprintf("IncreaseIterations menu item selected\n");
                _fIterationLimit += kODIterationStep;
                _fCurrentZoom = NULL;   // this will cause a recalc in Draw
                somSelf->Draw(ev, _fFacet, kODNULL);
		handled = kODTrue;
                break;

            case kODCommandResetIterations:
                // Reset the iteration limit to the initial value, then Draw
                //qprintf("ResetIterations menu item selected\n");
                _fIterationLimit = kODIterationStep;
                _fCurrentZoom = NULL;   // this will cause a recalc in Draw
                somSelf->Draw(ev, _fFacet, kODNULL);
		handled = kODTrue;
                break;

            case kODCommandInfo:
                // Display the zoom data dialog
                //qprintf("Info menu item selected\n");
                char msg[256];
                sprintf(msg,
                  "%.14g < x < %.14g\n%.14g < y < %.14g\niteration limit: %d",
	          _fZoom->lx, _fZoom->ux, _fZoom->ly, _fZoom->uy,
                  _fIterationLimit);
                MessageBox(event->hwnd, msg, "Zoom Data", MB_OK | MB_APPLMODAL);
		handled = kODTrue;
                break;

           default:
              break;
        }
    }

    catch(ODException _exception)
    {
    }

    return handled;
}



/////////////////////////////////////////////////////////////////////////////
//
// void Draw(ODFacet *facet, ODShape *invalidShape)
//
// Description:  Draws the current view of the Mandelbrot set.
//               A recalculation of the view is performed if necessary.
//
// Parameters:   *facet;		// facet to be redrawn
//               *invalidShape;	// area of the facet to be redrawn
//
// Returns:      none
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotDraw(Mandelbrot *somSelf,  Environment *ev,
                                       ODFacet* facet, ODShape* invalidShape)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotDraw");

    long  w, h;

    //qprintf("Invoked Mandelbrot::Draw()\n");
    try
    {
        if (facet && facet->GetCanvas(ev)->IsDynamic(ev))
        {
            // Reset the view to the original coord's if necessary
            if (_fResetZoom)
            {
                _fZoom = (struct ZoomType *)malloc(sizeof(struct ZoomType));
                _fZoom->zp = NULL;
                _fZoom->lx = -2.25; _fZoom->ux = .75;
                _fZoom->ly = -1.5;  _fZoom->uy = 1.5;
                _fResetZoom = kODFalse;
            }

            // Determine the platform window
            ODWindow *odWindow = facet->GetWindow(ev);
            ODPlatformWindow window = odWindow->GetPlatformWindow(ev);

            // Save these items for future reference
            _fFacet = facet;
            _fShape = invalidShape;

            // Determine the width and height of the facet
            somSelf->CheckSize(ev, facet, &w, &h);

            // Recalculate and draw if view or has changed
            if ((_fCurrentZoom != _fZoom) || (_fWidth != w))
            {
                _fCurrentZoom = _fZoom;
                if (_fWidth != w)
                {
                    // Size has changed so create new bitmaps for the new size
                    _fWidth = w;
                    _fHeight = h;
                    somSelf->SetupBitmap(ev, facet, window, w, h);
                }
                // Now recalulate over the new view
                somSelf->NewSet(ev, window);
            }
            // Otherwise just redraw the current view
            else
                somSelf->Redraw(ev, window);
        }
    }

    catch(ODException _exception)
    {
    }
}

/////////////////////////////////////////////////////////////////////////////
//
// Name: void CheckSize(ODFacet *facet, long *w, long *h)
//
// Description:  Determine the size of the facet
//
// Parameters:   *facet	// the facet to be checked
//               *w, *h	// width and height of the facet
//
// Returns:      The contents of parameters *w and *h are set
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotCheckSize(Mandelbrot *somSelf,
						Environment *ev,
						ODFacet *facet,
						long *w, long *h)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotCheckSize");

    ODRect rect;
    Rect frameRect;

    TempODShape shape = facet->GetFrame(ev)->AcquireFrameShape(ev, kODNULL);
    shape->GetBoundingBox(ev, &rect);
    SetRect(&frameRect, FixedToInt(rect.left), FixedToInt(rect.top),
                   FixedToInt(rect.right), FixedToInt(rect.bottom));
    *w = frameRect.right - frameRect.left;
    *h = frameRect.bottom - frameRect.top;
    //qprintf("CheckSize: width = %d, height = %d\n", *w, *h);
}


/////////////////////////////////////////////////////////////////////////////
//
// Name: void SetupBitmap(ODPlatformWindow window, long w, long h)
//
// Description:  This method is called when the size of the facet has
//               changed.  It will free the old bitmaps and image data
//               and create new ones of the right size.
//
// Parameters:   window	// the window to tie the bitmaps to
//               w, h	// the width and height for the new bitmaps
//
// Returns:      none
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotSetupBitmap(Mandelbrot *somSelf,
						Environment *ev,
						ODFacet *facet,
						ODPlatformWindow window,
						long w, long h)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotSetupBitmap");

    // Free the old bitmaps and image data
    if (_fBitmap)
        DeleteObject(_fBitmap);
    if (_fBitmapRow)
        DeleteObject(_fBitmapRow);
    if (_fImageData)
        free(_fImageData);

    // Create new bitmaps and image data with the new size
    HDC dc = GetDC(window);
    _fMemBitmapDC = CreateCompatibleDC(dc);
    _fMemRowDC = CreateCompatibleDC(dc);
    _fBitmap = CreateCompatibleBitmap(dc, w, h);
    _fBitmapRow = CreateCompatibleBitmap(dc, w, 1);
    _fImageData = (char *)malloc(w * h);
    SelectObject(_fMemBitmapDC, _fBitmap);
    SelectObject(_fMemRowDC, _fBitmapRow);
    ReleaseDC(window, dc);
}

/////////////////////////////////////////////////////////////////////////////
//
// Name: void NewSet(ODPlatformWindow window)
//
// Description:  Recalculate and draw the current view of the set
//
// Parameters:   window	// the window to be drawn into
//
// Returns:      none
//
// Caution:      The current implementation assumes a display depth of 8
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotNewSet(Mandelbrot *somSelf, Environment *ev,
						ODPlatformWindow window)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotNewSet");

    HDC screenDC;
    double incrx, incry;		// increment values
    double x, y;			// coord's for each scanline
    register double wx, wy, wx2, wy2;	// current coord's, and those squared
    long i, ix, iy, yy, yyy;		// iterator values
    static long bias = 1;		// bias into color table

    //qprintf("Invoked Mandelbrot::NewSet()\n");

    // Determine the increment values for each dimension
    incrx = (_fZoom->ux - _fZoom->lx)/(long)_fWidth;
    incry = (_fZoom->uy - _fZoom->ly)/(long)_fHeight;

    // Set the initial value of y to the top of the view
    y = _fZoom->uy;

    // Clear the window
    CFocus f(_fFacet, _fShape, &screenDC);
    BitBlt(screenDC, 0, 0, _fWidth, _fHeight, _fMemBitmapDC, 0, 0, WHITENESS);

    // Interleave the drawing of the set in 8 passes: 0, 4, 1, 5, 2, 6, 3, 7
    //     (note: this assumes the depth is 8)
    for (yyy = 0; yyy < 4; yyy++)
    {
	for (yy = yyy; yy < 8; yy += 4)
	{
	    y = _fZoom->uy - (yy * incry);
	    for (iy = yy; iy < (long)_fHeight; iy += 8, y -= (8*incry))
	    {
		x = _fZoom->lx;
		for (ix = 0; ix < (long)_fWidth; ix++, x += incrx)
		{
		    wx = x; wy = y;
		    for (i = 0; i < _fIterationLimit; i++)
		    {
		        if ((wx2 = wx * wx) + (wy2 = wy * wy) > 4)
		            break;
                        wy = 2 * wx * wy + y;
			wx = wx2 - wy2 + x;
                    }
                    // use iteration count as color index
		    _fImageData[iy * _fWidth + ix] = i + bias;
                }

                // Write the image data to the bitmap
		SetBitmapBits(_fBitmapRow, _fWidth, &_fImageData[iy * _fWidth]);

                // Blit the scanline to the screen
		BitBlt(screenDC, 0, iy, _fWidth, 1, _fMemRowDC, 0, 0, SRCCOPY);

                // Blit the scanline to the composite bitmap
		BitBlt(_fMemBitmapDC, 0, iy, _fWidth, 1, _fMemRowDC,
								0, 0, SRCCOPY);
            }
        }
    }
}


/////////////////////////////////////////////////////////////////////////////
//
// Name: void Redraw(ODPlatformWindow window)
//
// Description:  Refresh the current view of the set
//
// Parameters:   window	// the window to be redrawn
//
// Returns:      none
//
/////////////////////////////////////////////////////////////////////////////
SOM_Scope void  SOMLINK MandelbrotRedraw(Mandelbrot *somSelf, Environment *ev,
						ODPlatformWindow window)
{
    MandelbrotData *somThis = MandelbrotGetData(somSelf);
    MandelbrotMethodDebug("Mandelbrot","MandelbrotRedraw");

    //qprintf("Invoked Mandelbrot::Redraw()\n");

    // Blit the composite bitmap to the screen
    HDC screenDC;
    CFocus f(_fFacet, _fShape, &screenDC);
    BitBlt(screenDC, 0, 0, _fWidth, _fHeight, _fMemBitmapDC, 0, 0, SRCCOPY);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
SOM_Scope ISOString  SOMLINK M_MandelbrotclsGetODPartHandlerName(
                                   M_Mandelbrot *somSelf, Environment *ev)
{
    /* M_MandelbrotData *somThis = M_MandelbrotGetData(somSelf); */
    M_MandelbrotMethodDebug("M_Mandelbrot",
                            "M_MandelbrotclsGetODPartHandlerName");

    string handlerName = (string)SOMMalloc(strlen(kMandelbrotHandlerName+1));
    strcpy(handlerName,kMandelbrotHandlerName);

    return (ISOString) handlerName;
}


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
SOM_Scope string  SOMLINK M_MandelbrotclsGetODPartHandlerDisplayName(
                                   M_Mandelbrot *somSelf, Environment *ev)
{
    /* M_MandelbrotData *somThis = M_MandelbrotGetData(somSelf); */
    M_MandelbrotMethodDebug("M_Mandelbrot",
                            "M_MandelbrotclsGetODPartHandlerDisplayName");

    string displayName = (string)SOMMalloc(
                                       strlen(kMandelbrotHandlerDisplayName+1));
    strcpy(displayName,kMandelbrotHandlerDisplayName);

    return displayName;
}


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
SOM_Scope _IDL_SEQUENCE_PartKindInfo  SOMLINK M_MandelbrotclsGetODPartKinds(
                                    M_Mandelbrot *somSelf, Environment *ev)
{
    /* M_MandelbrotData *somThis = M_MandelbrotGetData(somSelf); */
    M_MandelbrotMethodDebug("M_Mandelbrot","M_MandelbrotclsGetODPartKinds");

    _IDL_SEQUENCE_PartKindInfo MandelbrotInfo;

    // Create structure PartKindInfo  and allocate memory for its fields
    PartKindInfo * info = (PartKindInfo *)SOMMalloc(sizeof(PartKindInfo));
    info->partKindName = (ISOString) SOMMalloc(strlen(kODKindMandelbrot) + 1);
    info->partKindDisplayName = (string)SOMMalloc(strlen
                                               (kMandelbrotKindDisplayName)+1);
    info->filenameFilters =  (string)SOMMalloc(strlen("")+1);
    info->filenameTypes =  (string)SOMMalloc(strlen("")+1);
    info->categories =  (string)SOMMalloc(strlen(kMandelbrotCategory)+1);
    info->categoryDisplayName =  (string)SOMMalloc(strlen("")+1);
    info->objectID =  (string)SOMMalloc(strlen("")+1);

    // Copy the information into the structure
    strcpy(info->partKindName , kODKindMandelbrot);
    strcpy(info->partKindDisplayName, kMandelbrotKindDisplayName);
    strcpy(info->filenameFilters, "");
    strcpy(info->filenameTypes, "");
    strcpy(info->categories, kMandelbrotCategory);
    strcpy(info->categoryDisplayName, "");
    strcpy(info->objectID, "");

    MandelbrotInfo._maximum = 1;
    MandelbrotInfo._length = 1;
    MandelbrotInfo._buffer = info;

    return MandelbrotInfo;
}


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
SOM_Scope string  SOMLINK M_MandelbrotclsGetOLE2ClassId(M_Mandelbrot *somSelf,
                                                        Environment *ev)
{
    /* M_MandelbrotData *somThis = M_MandelbrotGetData(somSelf); */
    M_MandelbrotMethodDebug("M_Mandelbrot","M_MandelbrotclsGetOLE2ClassId");

    // OLE2 Class ID is determined by running the tool UUIDGEN.EXE
    // or GUIDGEN.EXE found in the IBM VAC++ SDK\BIN directory
    // this tool is guaranteed to generate a unique ID based on your
    // network address and the time of day (DCE Standard)


    string OLE2 = "{b9f70fd0-fced-11cf-9609-08005ac115dc}";
    string OLE2ClassId = (string)SOMMalloc(strlen(OLE2+1));
    strcpy(OLE2ClassId, OLE2);

    return OLE2ClassId;
}


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
SOM_Scope string  SOMLINK M_MandelbrotclsGetWindowsIconFileName(
                                        M_Mandelbrot *somSelf, Environment *ev)
{
    /* M_MandelbrotData *somThis = M_MandelbrotGetData(somSelf); */
    M_MandelbrotMethodDebug("M_Mandelbrot",
                            "M_MandelbrotclsGetWindowsIconFileName");

    string fileName = (string) SOMMalloc (strlen(kMandelbrotIconFileName));
    strcpy(fileName,kMandelbrotIconFileName);
    return fileName;
}

