// #################################
//
//           Prescribble
//
//        (C)opyright 2001 
//           by Kent Dahl 
//
//        MenThal@bigfoot.com
//  http://www.bigfoot.com/~MenThal/
//
//    Released under the GPL 
//     (Gnu Public License)
//
//       Use at own risk. 
//
// ##################################

#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Window.H>
#include <FL/x.H>

#include <cstdio>
#include <cmath>

#include "prescribblearea.hpp"


#ifndef DEBUG
#define DEBUG 1
#endif



PresXServer::PresXServer()
    : m_pixmap(0),
      m_scale(1),
      m_upperLeft(0,0)
{
//    int depth = 4;
//    m_display=XOpenDisplay("");
//    std::printf("So far..\n");
//    if (!m_display) {std::printf ("No X server found\n");exit(1);}

    m_pixmap = 0;
//    m_pPixmap = 0;
}

PresXServer::~PresXServer()
{    
    if(m_pixmap)fl_delete_offscreen(m_pixmap);
}


void PresXServer::create( int width, int height )
{
    Pixmap tmppixmap = m_pixmap;

    if(tmppixmap) fl_delete_offscreen(tmppixmap);
    tmppixmap = fl_create_offscreen(width,height);

 //   if(m_pPixmap) delete m_pPixmap;
   // char *data = new char[width*height];
 //   m_pPixmap = new Fl_Pixmap( &data );

    fl_begin_offscreen( tmppixmap );//tmppixmap);

    fl_color(FL_WHITE);
    fl_rectf(0,0,width,height);
    //m_pPixmap->draw(0,0);

    fl_end_offscreen();
    //fl_delete_offscreen(tmppixmap);

    m_pixmap = tmppixmap;

}

void PresXServer::splatAt( int dest_x, int dest_y,
                           int width, int height,
                           int src_x, int src_y)
{
//    if( m_pPixmap )
//        m_pPixmap->draw(dest_x,dest_y);

    if(m_pixmap)
        XCopyArea( fl_display, m_pixmap, fl_window, fl_gc,
                   src_x, src_y,
                   width,height,
                   dest_x, dest_y);

}


/*void PresXServer::resetView()
{
    m_scale = 1.0;
    m_upperLeft = Point2D( 0, 0 );
    restrain();
}*/

void PresXServer::zoom(bool in)
{
    if(in)
        m_scale *= 2.0;
    else
        m_scale /= 2.0;
    restrain();
}

void PresXServer::zoom( Point2D a, Point2D b )
{
    // a and b is worldspace
    //std::printf("a==(%i, %i)",a.x,a.y);
    //std::printf("   b==(%i, %i)\n",b.x,b.y);
    //std::printf("   m_upperLeft==(%i, %i)\n",m_upperLeft.x,m_upperLeft.y);

    int w = a.x - b.x; w = (w<0)?-w:w;
    int h = a.y - b.y; h = (h<0)?-h:h;

    Point2D center( (a.x+b.x)/2, (a.y+b.y)/2 );

    //std::printf("   w,h,m_scale==(%i, %i, %f)\n",w,h,m_scale);

    m_scale = 240.0/(float)h;
    m_upperLeft = center + Point2D( -80/m_scale, -110/m_scale );
//= Point2D( (a.x<b.x?a.x:b.x),                           (a.y<b.y?a.y:b.y) );


    

    //std::printf("   w,h,m_scale==(%i, %i, %f)\n",w,h,m_scale);
//        m_upperLeft = translateFromScreen( m_upperLeft );
    
//    m_scale = 240.0/(float)h;
        
    restrain();
    //std::printf("   m_upperLeft==(%i, %i)\n",m_upperLeft.x,m_upperLeft.y);

}





void PresXServer::restrain()
{
    if(m_scale>8.0) m_scale = 8.0;
    if(m_scale<(1.0)) m_scale = 1.0; ///2.0;

    int xsize = 160;
    int ysize = 240;


    int xlim = static_cast<int>(xsize - xsize/m_scale);
    int ylim = static_cast<int>(ysize - ysize/m_scale);
    if( m_upperLeft.x > xlim ) m_upperLeft.x = xlim;
    if( m_upperLeft.y > ylim ) m_upperLeft.y = ylim;


    if( m_upperLeft.x < 0 ) m_upperLeft.x = 0;
    if( m_upperLeft.y < 0 ) m_upperLeft.y = 0;
 //   std::printf("upperLeft ==(%i,%i)",m_upperLeft.x, m_upperLeft.y);

}

void PresXServer::moveUpperLeft(Point2D diff){
    m_upperLeft = m_upperLeft + diff;
    restrain();
}


void PresXServer::set_fl_matrix()
{
    restrain();

    fl_push_matrix();
    fl_scale( m_scale, m_scale );
    fl_translate( -m_upperLeft.x, -m_upperLeft.y );
//    fl_scale( m_scale, m_scale );
}

void PresXServer::reset_fl_matrix()
{
    fl_pop_matrix();
 
}


Point2D PresXServer::translateFromScreen( Point2D screenPos )
{

    return Point2D( screenPos.x/m_scale + m_upperLeft.x,
                    screenPos.y/m_scale + m_upperLeft.y );
}
Point2D PresXServer::translateToScreen( Point2D worldPos )
{
    return Point2D( (worldPos.x - m_upperLeft.x)*m_scale,
                    (worldPos.y - m_upperLeft.y)*m_scale );

}



//PresXServer PresXServer::m_theXServer;



// ===========================================
/**
 * configuration for prescribble
 */

PresConfig::PresConfig() 
    : PresNoteConfig(16, 10), 
      horizlines(true), vertlines(false),
      horizlinespace(16), vertlinespace(16),
      pointrange(0),
      filename("prescribble.dat"),
      quietSaveOnExit(false),
      quietLoadOnEntry(false),
      onlyCheatRedrawDuringMouseDown(true),
      allowZipUsage(false),
      unzipTmpFile("/tmp/prescribble.dat"),
      zipExtension(".gz")
{}


void PresConfig::sanitize()
{
    if(horizlinespace<1){ horizlines = false; horizlinespace=16; }
    if(vertlinespace<1){  vertlines  = false; vertlinespace =16; }
    if(pointrange<0) pointrange = 0;
    if(m_maxRedoStrokes>256) m_maxRedoStrokes = 256;
}
  



MouseStrokeAdapter::MouseStrokeAdapter( PrescribbleArea *a_area )
    : m_pArea( a_area ) { }


//int MouseStrokeAdapter::mousePush( Point2D ){ return 0; }
//int MouseStrokeAdapter::mouseDrag( Point2D ){ return 0; }
//int MouseStrokeAdapter::mouseRelease( Point2D ){ return 0; }



// ============= StrokeEraser =============
StrokeEraser::StrokeEraser( PrescribbleArea *a_area )
    : StrokeBox( a_area ),
      m_pActions(0),
      m_width(10)
{ }

int StrokeEraser::mousePush(    Point2D ) 
{
    m_pActions = new PresComplexAction();
    return 1;
}
int StrokeEraser::mouseDrag(    Point2D p )
{
    bool eraseAgain = !p.isWithinRange( m_prev, m_width );

    PrescribbleNote *note = m_pArea->getCurrentNote();
    if( eraseAgain && note )
    { 
        //PrescribbleNote::FindResult find 
        //    = note->findPoint( p );
        //if(find.found){
        //if(DEBUG)std::printf("found point: %i\n",find.manhattan);
        //PrescribbleStroke *oldstroke=*find.foundStroke;
            fl_begin_offscreen( m_pArea->m_theXServer.m_pixmap );
            m_pArea->m_theXServer.set_fl_matrix();
//            fl_color( FL_WHITE );
            //oldstroke->drawAllLines( *m_pArea );

            //PresAction *action = note->splitAtPoint( find );
            // change to a box cutting?
            Point2D diff(-m_width>>1,-m_width>>1);
            Point2D ul = p + diff;
            Point2D br = p + Point2D(m_width,m_width);
            PresAction *action 
                = note->eraseRectAction( Rect2D(ul, br), m_pArea );
//            fl_rectf( ul.x, ul.y, m_width, m_width ); // quick crude erase

            if(action) {
                action->redo();
                if(m_pActions){
                    m_pActions->add(*action);
                    if(DEBUG)std::printf(" stroke erase action added\n");
                }
            


                PrescribbleNote *note = m_pArea->getCurrentNote();
                fl_color( FL_BLACK );
                if(note->m_strokes.size()>0)
                    for(int i=1;i<4 && note->m_strokes.size()-i>0;i++)
                        note->m_strokes[ note->m_strokes.size()-i]
                            ->drawAllLines( *m_pArea );

            }
            m_pArea->m_theXServer.reset_fl_matrix();
            fl_end_offscreen();

            m_pArea->redraw();
            
        //}
    }
    return 1;
}




int StrokeEraser::mouseRelease( Point2D ) 
{
    // reset back to normal mode
    //m_pArea->resetStrokeMode(0);
    if( m_pActions )
    {
        PrescribbleNote *note = m_pArea->getCurrentNote();
        if( !m_pActions->empty() )
            note->doAction(*m_pActions);
        else{
            if(DEBUG)std::printf(" complex action was EMPTY!\n");
            delete m_pActions;
        }
        m_pArea->redrawArea(0);
    }
    return 1;



}



// ============= StrokeDeleter =============
StrokeDeleter::StrokeDeleter( PrescribbleArea *a_area )
    : StrokeEraser( a_area ) { }


int StrokeDeleter::mouseDrag(    Point2D p )
{
    PrescribbleNote *note = m_pArea->getCurrentNote();
    if( note )
    { 
        PrescribbleNote::FindResult find 
            = note->findPoint( p );
        if(find.found){
            if(DEBUG)std::printf("found point: %i\n",find.manhattan);


            fl_begin_offscreen( m_pArea->m_theXServer.m_pixmap );
            m_pArea->m_theXServer.set_fl_matrix();
            fl_color( FL_WHITE );
            (*find.foundStroke)->drawAllLines( *m_pArea );

            m_pArea->m_theXServer.reset_fl_matrix();
            fl_end_offscreen();

            PresAction *action = note->erase( find.foundStroke );
            action->redo();
            m_pActions->add(*action);


            m_pArea->redraw();
        }
    }
    return 1;

}

// ============= StrokeFlattener =============
StrokeFlattener::StrokeFlattener( PrescribbleArea *a_area )
    : StrokeEraser( a_area ) { }
int StrokeFlattener::mouseDrag(    Point2D p )
{
    PrescribbleNote *note = m_pArea->getCurrentNote();
    if( note )
    { 
        PrescribbleNote::FindResult find 
            = note->findPoint( p );
        if(find.found){
            if(DEBUG)std::printf("found point: %i\n",find.manhattan);
            note->erasePoint( find );
            m_pArea->redrawArea(0);
        }
    }
    return 1;
}


// ============= StrokeBox =============
StrokeBox::StrokeBox( PrescribbleArea *a_area )
    : MouseStrokeAdapter( a_area ) { }

int StrokeBox::mousePush(    Point2D p )
{
    m_first = m_pArea->m_theXServer.translateToScreen(p); 
    return 1;
}
int StrokeBox::mouseDrag(    Point2D p )
{
   Fl_Window *win = m_pArea->window();//->make_current();
   if(win) win->make_current();

   p = m_pArea->m_theXServer.translateToScreen(p);

    fl_overlay_rect( m_first.x, m_first.y,
                     p.x - m_first.x, p.y - m_first.y );
    
    return 1;
}
int StrokeBox::mouseRelease(    Point2D p )
{
    m_pArea->window()->make_current();
    fl_overlay_clear();
    m_last = p; 

    m_first = m_pArea->m_theXServer.translateFromScreen(m_first);


    // box stroke
    m_pArea->mousePush( m_first );
    p = m_first; p.x = m_last.x;
    m_pArea->mouseDrag( p );

    m_pArea->mouseDrag( m_last );
    p = m_first; p.y = m_last.y;
    m_pArea->mouseDrag( p );

    m_pArea->mouseRelease( m_first );

    return 1;
}
// ===========================================



ScrollStroke::ScrollStroke( PrescribbleArea *a_area )
    : MouseStrokeAdapter( a_area )
{
}
int ScrollStroke::mousePush(    Point2D p)
{
    m_prev = m_pArea->m_theXServer.translateToScreen(p);
    return 1; 
}
int ScrollStroke::mouseDrag(    Point2D p )
{
   Fl_Window *win = m_pArea->window();//->make_current();
   if(win) win->make_current();

    m_curr = m_pArea->m_theXServer.translateToScreen(p);
    Point2D orig = m_pArea->m_theXServer.m_upperLeft;
    Point2D diff( (m_curr.x - m_prev.x - orig.x),
                  (m_curr.y - m_prev.y - orig.y) );
//    m_pArea->m_theXServer.m_upperLeft = diff;
    m_pArea->m_theXServer.moveUpperLeft(diff);

//    m_pArea->setDirty(true);
//    m_pArea->redraw();
//    m_prev = m_curr;

    fl_overlay_rect( m_pArea->m_theXServer.m_upperLeft.x,
                     m_pArea->m_theXServer.m_upperLeft.y,
                     static_cast<int>( m_pArea->w()/m_pArea
                                       ->m_theXServer.m_scale ),
                     static_cast<int>( m_pArea->h()/m_pArea
                                       ->m_theXServer.m_scale) );




    return 1;
}
int ScrollStroke::mouseRelease( Point2D )
{
    m_pArea->window()->make_current();
    fl_overlay_clear();

    m_pArea->setDrawMode(0);
    m_pArea->setDirty(true);
    m_pArea->redraw();
    return 1;
}

    
// ===========================================
ZoomStroke::ZoomStroke( PrescribbleArea *a_area )
    : StrokeBox( a_area )
{
}
int ZoomStroke::mouseRelease( Point2D p)
{
    m_first = m_pArea->m_theXServer.translateFromScreen(m_first);
    m_last  = p;

    m_pArea->window()->make_current();
    fl_overlay_clear();

    if(!m_first.isWithinRange(m_last, 4))
        m_pArea->m_theXServer.zoom( m_first, m_last );
    else
        m_pArea->m_theXServer.zoom(false); //zoom out!

    m_pArea->setDirty(true);
    m_pArea->redraw();

    return 1;
}



// ===========================================
EllipseStroke::EllipseStroke( PrescribbleArea *a_area )
    : StrokeBox( a_area )
{
}
int EllipseStroke::mouseRelease( Point2D p)
{
    m_first = m_pArea->m_theXServer.translateFromScreen(m_first);
    m_last  = p;

    m_pArea->window()->make_current();
    fl_overlay_clear();

    Rect2D rec( m_first, m_last );

    int rh,rv; //radiuses
    rh = rec.width()/2;
    rv = rec.height()/2;

    Point2D center( rec.ul + Point2D( rh, rv ) );

   m_pArea->mousePush( center  + Point2D( rh, 0   ) );

   for(double i = 0; i<M_PI*2 ; i=i+ (M_PI) / 8)
       m_pArea->mouseDrag( center  
                           + Point2D(   std::cos(i)*rh, std::sin(i)*rv ) );
   m_pArea->mouseRelease( center  + Point2D( rh, 0) );    



    m_pArea->setDirty(true);
    m_pArea->redraw();

    return 1;
}




NewStrokeEraser::NewStrokeEraser( PrescribbleArea *a_area )
    : StrokeBox(a_area){}

int NewStrokeEraser::mouseRelease( Point2D p )
{
    m_pArea->window()->make_current();
    fl_overlay_clear();
    m_last = p; 

    
    PrescribbleNote *note = m_pArea->getCurrentNote();

    note->eraseRect( Rect2D( m_first, m_last ) );
    m_pArea->setDirty(true);
    m_pArea->redraw();


    return 1;
}






// ===========================================
// struct CallbackBase {

void CallbackBase::callback(){
    
}

void CallbackBase::cb( Fl_Widget *w, void *data){
    CallbackBase *p 
        = static_cast<CallbackBase*>(data);
    p->callback();
}






PresArea_Callback::PresArea_Callback( PrescribbleArea *a_pThat,
                      int (PrescribbleArea::*a_pFunc)(void*),
                      void *a_data = 0)
        : m_pThat( a_pThat ),
          m_fptr( a_pFunc ),
          m_data( a_data )
        {}

void PresArea_Callback::callback(){
    m_fptr( m_pThat, m_data );
}










//====================== PrescribbleArea ==================


PrescribbleArea::PrescribbleArea( PrescribbleNote *note,
                                  int x1, int y1, int x2, int y2, 
                                  PresConfig &a_config,
                                  PrescribbleNoteListener *a_pListener )
    : Fl_Box( FL_FLAT_BOX, x1,y1, x2,y2, ""),
      m_pCurrentNote( note  ),
      dirty(true),
      m_addGuideLines( true ),
      m_guideLineSpacing( 32 ),
      m_guideLineColor( fl_gray_ramp(64*FL_NUM_GRAY/256) ),
      m_config(a_config),
      m_pMouseStrokeReciever( this ),
      m_draggingStrokeEraser(  this ),
      m_strokeEraser(  this ),
      m_strokeDeleter( this ),
      m_strokeBox( this ),
      
      m_scrollstroke( this ),
      m_zoomstroke( this ),
      m_ellipsestroke( this ),
      m_theXServer(),

      m_cleaner(this, &PrescribbleArea::cleanArea),
      m_undoer(this, &PrescribbleArea::undoStroke),
      m_redoer(this, &PrescribbleArea::redoStroke),
      m_redrawer(this, &PrescribbleArea::redrawArea),
      m_eraser(this, &PrescribbleArea::setDrawMode, &m_strokeEraser),
      m_dragEraser(this, &PrescribbleArea::setDrawMode, 
                   &m_draggingStrokeEraser),
      m_eraserDel(this, &PrescribbleArea::setDrawMode, &m_strokeDeleter),
      m_setDrawMode(this, &PrescribbleArea::setDrawMode, 0),
      m_setBoxMode(this, &PrescribbleArea::setDrawMode, 
                       &m_strokeBox ),
      m_setScrollMode( this, &PrescribbleArea::setDrawMode, 
                       &m_scrollstroke ),
      m_setZoomMode( this, &PrescribbleArea::setDrawMode, 
                     &m_zoomstroke ),
      m_setEllipseMode( this, &PrescribbleArea::setDrawMode, 
                        &m_ellipsestroke ),
      
      m_pListener( a_pListener )

        {
            color( FL_WHITE ); //white background

        }




    void PrescribbleArea::draw (){
        
        if( dirty 
            || (!m_config.onlyCheatRedrawDuringMouseDown 
                && !mouseIsDown) ) 
        {
            //fl_color( FL_WHITE );
            //Fl_Box::draw();
            dirty = false;

            m_theXServer.create(160,240);
            fl_begin_offscreen( m_theXServer.m_pixmap );
            fl_color( FL_WHITE );
            Fl_Box::draw();
            m_theXServer.set_fl_matrix();

            //fl_rotate(90);
            if (m_config.horizlines){
                fl_color( m_guideLineColor ); 
                //fl_gray_ramp(64*FL_NUM_GRAY/256) );
                
                fl_line_style( FL_DOT );
                int numlines = (this->h())/m_config.horizlinespace;
                int width = this->w();
                for (int i = 1; i<numlines; i++)
                {
                    int y = i*m_config.horizlinespace; 
                    drawLine( Point2D(0,y), Point2D(width,y) );
                }
            }


            if (m_config.vertlines){
                fl_color( m_guideLineColor ); 
                
                fl_line_style( FL_DOT );
                int numlines = (this->h())/m_config.vertlinespace; 
                int heigth = this->h();
                for (int i = 1; i<numlines; i++)
                {
                    int x = i*m_config.vertlinespace;
                    drawLine(Point2D(x,0), Point2D(x,heigth));
                }
            
            }

            fl_line_style( 0 );
            // redraw ALL lines
            fl_color( FL_BLACK );
            m_pCurrentNote->drawAllLines( *this );

            //fl_pop_matrix();
            m_theXServer.reset_fl_matrix();
            fl_end_offscreen();
            //PresXServer::m_theXServer.splatAt(0,0);

        }
        else
        {
            // draws the last line

            //PresXServer::m_theXServer.splatAt(0,0);
            fl_begin_offscreen( m_theXServer.m_pixmap );
            m_theXServer.set_fl_matrix();
            fl_color( FL_BLACK );
            if(!mouseIsDown) m_pCurrentNote->drawLastStroke( *this );
            //fl_line( prevPos.x, prevPos.y,
            //          currPos.x, currPos.y );
            m_theXServer.reset_fl_matrix();
            fl_end_offscreen();// m_pixmap );
        }
        m_theXServer.splatAt(0,0);
    }

    

    int PrescribbleArea::addLine()
        {
            //printf( "(%d,%d)-(%d,%d)\n", 
            //        prevPos.x, prevPos.y,
            //        currPos.x, currPos.y );

            redraw();
            return 1;
        }


    int PrescribbleArea::mousePush(Point2D p)
        {
            prevPos = p;
            currPos = p;
            mouseIsDown = true;
            // start a new stroke
            m_pCurrentNote->beginStroke( p );

            return 1;
        }

    int PrescribbleArea::mouseDrag(Point2D p)
        {
            if( p.isWithinRange( currPos, m_config.pointrange ) )
                return 1;

            prevPos = currPos;
            currPos = p;

            if( p.isWithinRange( prevPos, m_config.pointrange  ) )
                return 1;
            
            m_pCurrentNote->continueStroke( p );

            //Fl_Window *prevCurr = Fl_Window::current();
            Fl_Window *nextCurr = window();
            if(nextCurr)nextCurr->make_current();
            m_theXServer.set_fl_matrix();
            fl_color( FL_BLACK );
            drawLine( prevPos, currPos );
            m_theXServer.reset_fl_matrix();
//            fl_line( prevPos.x, prevPos.y,
//                     currPos.x, currPos.y );
            //if(prevCurr)prevCurr->make_current();
            return 1; //addLine();
        }

    int PrescribbleArea::mouseRelease(Point2D p)
        {
            mouseIsDown = false;
            prevPos = currPos;
            currPos = p;

            m_pCurrentNote->endStroke( p );

            // what if the stroke is a single point?
            PrescribbleStroke *stroke = m_pCurrentNote->lastStroke();
            Rect2D rec = stroke->getBoundingRect();
            if( rec.width()<=2 && rec.height()<=2 )
            {
                // note that this adds the action to the redo list
                m_pCurrentNote->undoAction();

                m_pCurrentNote->beginStroke(    p + Point2D(-1,  0) );
                m_pCurrentNote->continueStroke( p + Point2D(0,   1) );
                m_pCurrentNote->continueStroke( p + Point2D(1,   0) );
                m_pCurrentNote->continueStroke( p + Point2D(0,  -1) );
                m_pCurrentNote->endStroke(      p + Point2D(-1,  0) );
            }
                

            return addLine();
        }

    int PrescribbleArea::handleKeyboard()
        {
            int key = Fl::event_key();

            switch (key){ 
                
            case FL_Left : 
                
                break;
            case FL_Right : 
                
                break;
                
            default: return 0;
                
            };

                     
            return 1;
        }

    int PrescribbleArea::handle( int event )
        {
            //printf("event:%d\n", event );
            Point2D p( Fl::event_x(), Fl::event_y() );
            p = m_theXServer.translateFromScreen(p);
            
            if( event == FL_PUSH )
                return m_pMouseStrokeReciever->mousePush( p );
            if( event == FL_DRAG )
                return m_pMouseStrokeReciever->mouseDrag( p );
            if( event == FL_RELEASE )
                return m_pMouseStrokeReciever->mouseRelease( p );


            if( event == FL_KEYBOARD )
            {
                return 0; //handleKeyboard();
            }
            if( event == FL_FOCUS )
            {
                //if(DEBUG)std::printf("focus\n");
                //redraw();
                setDirty(true);
                return 1;
            
            }
            if( event == FL_UNFOCUS )
            { 
                //if(DEBUG)std::printf("unfocus\n");
                setDirty(true);
                return 1;
            }
            return Fl_Box::handle(event);
        }


void PrescribbleArea::setDirty( bool a_state )
{
    dirty = a_state;
    mouseIsDown = false;
}

int PrescribbleArea::redrawArea(void*){
    setDirty(true);
 
    redraw();
    return 0;
}

    int PrescribbleArea::cleanArea(void*){
        //delete m_pCurrentNote;
        //m_pCurrentNote = new PrescribbleNote();
        m_pCurrentNote->cleanOut();
        redrawArea(0);
        return 0;
    }

    int PrescribbleArea::undoStroke(void*){
        m_pCurrentNote->undoAction();
        updateUndoRedoFeedback();
        redrawArea(0);
        return 0;
    }
    int PrescribbleArea::redoStroke(void*){
        m_pCurrentNote->redoAction();
        updateUndoRedoFeedback();
        redrawArea(0);
        return 0;
    }

void PrescribbleArea::updateUndoRedoFeedback()
{
    if( m_pListener )
    {
        m_pListener->updateUndoStatus( m_pCurrentNote->anyUndosLeft() );
        m_pListener->updateRedoStatus( m_pCurrentNote->anyRedosLeft() );
    }
}


    int PrescribbleArea::setDrawMode(void* data){
        m_pMouseStrokeReciever = static_cast<MouseStrokeReciever*>(data);
        if( !m_pMouseStrokeReciever )
            m_pMouseStrokeReciever = this;
        return 0;
    }
/*    int PrescribbleArea::setNormalDrawMode(void*){
        m_pMouseStrokeReciever = this;
        return 0;
    }
    int PrescribbleArea::eraseStroke(void*){
        m_pMouseStrokeReciever = &m_strokeEraser;
        return 0;
    }
    int PrescribbleArea::eraseDelStroke(void*){
        m_pMouseStrokeReciever = &m_strokeDeleter;
        return 0;
    }
*/

/**
 * return to normal drawing/scribbling mode
 */
int PrescribbleArea::resetStrokeMode(void*){
    m_pMouseStrokeReciever = this;
    return 0;
}



void PrescribbleArea::zoom( int way )
{

    m_theXServer.zoom(way>0);
//    m_pMouseStrokeReciever = &m_scrollstroke;
    setDirty();
    redraw();
}



void PrescribbleArea::drawLine( Point2D src, Point2D dst )
{
    fl_begin_line();
    fl_vertex( src.x, src.y );
    fl_vertex( dst.x, dst.y );
    fl_end_line();

/*
    src = m_theXServer.translateToScreen( src );
    dst = m_theXServer.translateToScreen( dst );
    fl_line( src.x, src.y, dst.x, dst.y );
*/
}


    void PrescribbleArea::setCurrentNote( PrescribbleNote *a_pNote ){
        m_pCurrentNote = a_pNote;
        redrawArea(0);
    }
    PrescribbleNote *PrescribbleArea::getCurrentNote(){
        return m_pCurrentNote ;
    }
