// #################################
//
//           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_Button.H>
#include <FL/Fl_Browser.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Pack.H>
#include <FL/Fl_Counter.H>

#include <FL/Fl_Menu_Button.H>
#include <FL/fl_draw.H>
#include <FL/fl_message.H>

//#include <expat.h>

#include <algorithm>

//#include <flpda/Widget_Factory.h>

#define my_fl_file_chooser fl_ag_file_chooser
#include "modifiedFLTK/fl_ag_file_chooser.H"

#include "My_About_Dialog.h"

#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <vector>



#define VERSION "0.10"


#include "prescribble.hpp"
#include "prescrib_fltk.hpp"

#include "prescribblereader.hpp"

#define XSIZE 160
#define YSIZE 240
#define MENUYSIZE 16

#ifndef DEBUG
#define DEBUG 0
#endif


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

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








//============ PrescribbleApp {
void PrescribbleApp::resetDefaultNotes()
{
    for(int i = 0;i<4;i++)
        m_notes.push_back( new PrescribbleNote(m_config, this ) );
    m_currentNote = 0;
}
 
void PrescribbleApp::removeNotes(){
    while( !m_notes.empty())
    {
        delete m_notes.back();
        m_notes.pop_back();
    }
}

    PrescribbleApp::PrescribbleApp( PresConfig &a_conf)
        : m_pFeedbackString(0),
          m_config(a_conf),
          m_quitter(     this, &PrescribbleApp::quit           ),
          m_loader(      this, &PrescribbleApp::loadNotes      ),
          m_loaderFrom(  this, &PrescribbleApp::loadNotesFrom  ),
          m_makeNew(     this, &PrescribbleApp::clearNotes     ),
          m_saver(       this, &PrescribbleApp::saveNotes      ),
          m_saverAs(     this, &PrescribbleApp::saveNotesTo    ),
          m_about(       this, &PrescribbleApp::about          ),
          m_toPrev(      this, &PrescribbleApp::prevNote       ),
          m_toNext(      this, &PrescribbleApp::nextNote       ),
          m_inserter(    this, &PrescribbleApp::insertNote, this ),
          m_appender(    this, &PrescribbleApp::insertNote,0   ),

          m_noteForward( this, &PrescribbleApp::moveNote, this ),
          m_noteBackward( this, &PrescribbleApp::moveNote, 0    ),
          m_noteDelete(  this, &PrescribbleApp::deleteNote     )



        {
            resetDefaultNotes();
        }


void PrescribbleApp::start()
{
    if(m_config.quietLoadOnEntry)
        loadNotes(0);
    m_pArea->redrawArea(0);
}


    void PrescribbleApp::writeto( ostream & out ){
        NotesVector::iterator it    = m_notes.begin();
        NotesVector::iterator itend = m_notes.end();

        out << "<notebook>\n";
        while( it != itend )
        {
            (*it)->writeto( out );
            it++;
        }
        out << "</notebook>\n";
    }




    int PrescribbleApp::handleKeyboard(int evt)
        {
            return 0;
        }



int PrescribbleApp::saveNotesTo(void*)
{
    char *file = my_fl_file_chooser("Save notes to...", 
                                 "*.dat", m_config.filename.c_str() );

    if(file!=0)
    {
        if(DEBUG)std::cout<<"file: "<<file<<"\n";
        m_config.filename = file;
        saveNotes(0);
    }
    m_pArea->redrawArea(0);
    return 0;
}
int PrescribbleApp::saveNotes(void*)
{
    setFeedbackLabel("saving");
    const char *filename = m_config.filename.c_str();

    // zip hack
    bool doZipHack = m_config.allowZipUsage 
        && std::strstr(filename,m_config.zipExtension)!=0;
    if(doZipHack){
        filename = m_config.unzipTmpFile;
    }
    std::printf("filename: %s\n", filename);

    // scope to make file close...
    {
        ofstream out( filename );
        writeto( out );
    }

    if(doZipHack){
        //gzip it
        std::string s = "gzip -f ";
        s+=filename;
        if(DEBUG)std::printf("system: %s\n",s.c_str());
        std::system( s.c_str() );

        // copy to real location
        s = "cp ";
        s+= m_config.unzipTmpFile; 
        s+= m_config.zipExtension; 
        s+= " ";
        s+= m_config.filename.c_str();  

        if(DEBUG)std::printf("system: %s\n",s.c_str());
        std::system( s.c_str() );

        // remove temp file
        s  = "rm ";
        s += m_config.unzipTmpFile; s += m_config.zipExtension ;
        if(DEBUG)std::printf("system: %s\n",s.c_str());
        std::system( s.c_str() );

    } 


    feedbackNotePage();
    m_pArea->setDirty(true);
    return 0;
}


int PrescribbleApp::loadNotesFrom(void*)
{
    fl_message_font(0,8);
    char *file = my_fl_file_chooser("Load notes from...", 
                                 "*.dat", m_config.filename.c_str() );

    if(file!=0)
    {
        if(DEBUG)std::cout<<"file: "<<file<<"\n";
        m_config.filename = file;
        loadNotes(0);
    }
    m_pArea->redrawArea(0);
    m_pArea->setDirty(true);
    return 0;

}






int PrescribbleApp::loadNotes(void*)
{
    setFeedbackLabel("loading");
    // clear out the old first?
    removeNotes();

    const char* filename = m_config.filename.c_str();

    bool doZipHack = m_config.allowZipUsage 
        && std::strstr(filename,m_config.zipExtension)!=0;
    if(doZipHack){

        std::string s = "cp ";
        s+= m_config.filename.c_str();  
        s+= " ";
        s+= m_config.unzipTmpFile; 
        s+= m_config.zipExtension; 
        if(DEBUG)std::printf("system: %s\n",s.c_str());
        std::system( s.c_str() );

        //gzip it
        s = "gunzip -f ";
        s+= m_config.unzipTmpFile; 
        s+= m_config.zipExtension; 
        if(DEBUG)std::printf("system: %s\n",s.c_str());
        std::system( s.c_str() );


        filename = m_config.unzipTmpFile;
    }

    // actual writing
    PrescribbleXMLReader reader(m_config, this);
    bool readOk =
        reader.loadInto( filename, m_notes );
    
    if(doZipHack){
        //cleanup
        // remove temp file
        std::string s  = "rm ";
        s += m_config.unzipTmpFile; //s += m_config.zipExtension ;
        if(DEBUG)std::printf("system: %s\n",s.c_str());
        std::system( s.c_str() );
    }

    
    if(DEBUG)printf("reading..done!!!!!!\n");
    

    m_currentNote=0;
    
    //what if something failed terribly?
    if( m_notes.size()<1 || !readOk )
    {
        resetDefaultNotes();
        m_pArea->setCurrentNote( m_notes[m_currentNote] );
        
        if(DEBUG) std::printf("No notes loaded! Notes cleared.");
        fl_message_font(0,8);
        fl_alert("Load error.\nNotes cleared.");
        //setFeedbackLabel("load error");               
    }
    feedbackNotePage();
    //if(DEBUG)printf("feedbackNotePage...\n");
    m_pArea->setCurrentNote( m_notes[m_currentNote] );
    m_pArea->setDirty(true);
    return 0;
}



int PrescribbleApp::clearNotes(void*)
{
    if(fl_ask("Do you really want to\n"
              "delete ALL the notes?"))
    {
        removeNotes();
        resetDefaultNotes();
        m_pArea->setCurrentNote( m_notes[m_currentNote] );
        m_pArea->redrawArea(0);
        feedbackNotePage();
        m_pMainWindow->redraw();
    }
    return 1;
}


/*

    int PrescribbleApp::loadNotes(void*)
        {
            setFeedbackLabel("loading");
            // clear out the old first?
            ifstream in( m_config.filename.c_str() );
            removeNotes();

            std::string s;

            bool appending = false;
            if(DEBUG)printf("reading...\n");
            while( in >> s ){
                //std::cout<<"read:'"<<s<<"'\n";
                if( 0==s.compare( Pres::STROKE_TAG_BEGIN ) )
                {
                    appending = false;

                }
                else if( 0==s.compare( Pres::STROKE_TAG_END ) )
                    ;


                else if( 0==s.compare( Pres::NOTE_TAG_BEGIN ) )
                {
                    PrescribbleNote *p = new PrescribbleNote(m_config);
                    m_notes.push_back( p );
                    m_pArea->setCurrentNote( p );
  
                }
                else if( 0==s.compare( Pres::NOTE_TAG_END ) )
                    ;

                else if( 0==s.compare( Pres::NOTEBOOK_TAG_BEGIN ) )
                {
                    ;
                }
                else if( 0==s.compare( Pres::NOTEBOOK_TAG_END ) )
                    ;

                else {
                    //printf("hi?\n");
                    char *endptr;
                    long l1 = std::strtol( s.c_str(), &endptr, 10);
                    long l2 = std::strtol( endptr+1, &endptr, 10);
                
                    //std::cout<<" number:"<<l1<<","<<l2<<"\n" ;
                    Point2D p( (int)l1, (int)l2 );
                    if(appending)
                        m_pArea->getCurrentNote()->continueStroke( p );
                    else
                        m_pArea->getCurrentNote()->beginStroke( p );
                    appending = true;
                }
            }
            if(DEBUG)printf("reading..done!!\n");
           

            m_currentNote=0;
            
            //what if something failed terribly?
            if( m_notes.size()<1 )
            {
                resetDefaultNotes();
                m_pArea->setCurrentNote( m_notes[m_currentNote] );

                if(DEBUG) std::printf("No notes loaded! Notes cleared.");
                fl_message_font(0,8);
                fl_alert("Load error.\nNotes cleared.");
                //setFeedbackLabel("load error");               
            }
            feedbackNotePage();

            m_pArea->setCurrentNote( m_notes[m_currentNote] );
            m_pArea->setDirty(true);
            return 0;
        }
*/










    int PrescribbleApp::quit(void*){
        if(m_config.quietSaveOnExit)
            saveNotes(0);

        delete m_pMainWindow;
        return 0;
    }

    int PrescribbleApp::about(void*){

#ifdef FLPDA
        new My_About_Dialog("Prescribble", VERSION );
#else
        fl_message_font(0,8);
//        static Fl_Pixmap *pixmap = 0;
//        const char *const * xpm = prescribble_xpm;
//        if(!pixmap) pixmap = new Fl_Pixmap( xpm );
//        pixmap->label(fl_message_icon());
        fl_message("--<[ Prescribble ]>--\n"
                   "  (C)2001 Kent Dahl");
#endif
        return 0;
    }


void PrescribbleApp::setFeedbackLabel( const char *a_str )
{
    delete m_pFeedbackString;
    m_pFeedbackString = std::strdup(a_str);
    m_pFeedback->label( m_pFeedbackString );
    m_pFeedback->redraw();
    //m_pMainWindow->redraw(); //
}


    void PrescribbleApp::feedbackNotePage(){
        delete m_pFeedbackString;
        m_pFeedbackString = std::strdup("%i/%i\0\0\0\0\0");
        std::sprintf(m_pFeedbackString,
                     "%i/%i", m_currentNote+1,m_notes.size() );
        m_pFeedback->label( m_pFeedbackString );
        m_pFeedback->redraw();


        if(m_currentNote == 0)
            m_pLeftButton->deactivate();
        else
            m_pLeftButton->activate();

        if( static_cast<unsigned int>(m_currentNote) == m_notes.size()-1 )
            m_pRightButton->deactivate();
        else
            m_pRightButton->activate();

    }

    int PrescribbleApp::nextNote(void*){
        if (m_currentNote < (int)m_notes.size() - 1)
            m_currentNote++;
        m_pArea->setCurrentNote( m_notes[m_currentNote] );
        feedbackNotePage();
        return 0;
    }

    int PrescribbleApp::prevNote(void*){
        if (m_currentNote > 0)
            m_currentNote--;
        m_pArea->setCurrentNote( m_notes[m_currentNote] );
        feedbackNotePage();
        return 0;
    }

    int PrescribbleApp::insertNote(void*a){
        if(!a){
            m_notes.push_back( new PrescribbleNote(m_config, this) );
            m_currentNote = m_notes.size()-1;
        }
        else
        {
            m_notes.insert( find(m_notes.begin(), m_notes.end(),
                                 m_notes[m_currentNote]),
                            new PrescribbleNote(m_config, this));
        }
        m_pArea->setCurrentNote( m_notes[m_currentNote] );
        feedbackNotePage();
        return 0;
    }

int PrescribbleApp::deleteNote(void*)
{
    if(fl_ask("Do you really want to\n"
              "delete the current note?"))
    {
        if(m_notes.size()>1){
            
            m_notes.erase( find(m_notes.begin(), m_notes.end(),
                                m_notes[m_currentNote]) );
            if(m_notes.size()<=static_cast<unsigned int>(m_currentNote)) m_currentNote--;
        }else{
            m_pArea->cleanArea(0);
        }

    }
    m_pArea->setCurrentNote( m_notes[m_currentNote] );
    feedbackNotePage();
    return 0;

    return 0;
}
int PrescribbleApp::moveNote(void* a)
{

    if(a){
        if( static_cast<unsigned int>(m_currentNote+1)<m_notes.size() ){
            PrescribbleNote *note = m_notes[m_currentNote];
            m_notes[m_currentNote] = m_notes[m_currentNote+1];
            m_notes[m_currentNote+1] = note;
            m_currentNote++;
        }
        else
        {
            m_appender.callback();
            m_currentNote--;
        }
    }
    else
    {
        if( m_currentNote>0 ){
            PrescribbleNote *note = m_notes[m_currentNote];
            m_notes[m_currentNote] = m_notes[m_currentNote-1];
            m_notes[m_currentNote-1] = note;
            m_currentNote--;
        }
        else
        {
            m_inserter.callback();
            m_currentNote++;
        }
    }
    m_pArea->setCurrentNote( m_notes[m_currentNote] );
    feedbackNotePage();
    return 0;

}




void PrescribbleApp::zoom( int way )
{
    m_pArea->zoom(way);

}
void PrescribbleApp::toolSelect( int way )
{
    m_pEditMenuButton->picked( m_pToolboxMenu->popup(0,0) );

}



Fl_Menu_Item* PrescribbleApp::getFilePopupMenu()
{   
    static Fl_Menu_Item filePopupMenu[] =
            {
                { "Quit",0, &CallbackBase::cb, &m_quitter,
                  FL_MENU_DIVIDER},
                { "Save As...",0, &CallbackBase::cb, &m_saverAs },
                { "Save",0, &CallbackBase::cb, &m_saver },
                { "New", 0, &CallbackBase::cb, &m_makeNew },
                { "Load",0, &CallbackBase::cb, &m_loader, },
                { "Load from...",0, &CallbackBase::cb, &m_loaderFrom,
                  FL_MENU_DIVIDER },
                { "About",0, &CallbackBase::cb, &m_about },


//                { "...", 0, 0,0, FL_SUBMENU },
//                { "Save",0, &CallbackBase::cb, &m_saver },
//                { "Load",0, &CallbackBase::cb, &m_loader },
//                {0},

                {0}
            };
    return filePopupMenu;

}


Fl_Menu_Item* PrescribbleApp::getEditPopupMenu(PrescribbleArea *box)
{ 

static Fl_Menu_Item editPopupMenu[] =
{
    {"Clear",0,&CallbackBase::cb,&box->m_cleaner},
 //   {"Redraw",0,&CallbackBase::cb,&box->m_redrawer},

    {"Undo",0,&CallbackBase::cb,&box->m_undoer},
    {"Redo",0,&CallbackBase::cb,&box->m_redoer,
     FL_MENU_DIVIDER},
    
    {"Note...",0,0,0,
     FL_SUBMENU},
    {"Delete",0,&CallbackBase::cb,&m_noteDelete },
    {"Insert",0,&CallbackBase::cb,&m_inserter },
    {"Append",0,&CallbackBase::cb,&m_appender,
     FL_MENU_DIVIDER},
    
    {"Backward",0,&CallbackBase::cb,&m_noteBackward },
    {"Forward",0,&CallbackBase::cb,&m_noteForward },


    {0},

    {"Redraw",0,&CallbackBase::cb,&box->m_redrawer},
    {"Mode...",0,0,0,
     FL_SUBMENU},
    

    { "Delete", 0,&CallbackBase::cb,&box->m_eraserDel},
    { "Erase Box",  0,&CallbackBase::cb,&box->m_eraser},//FL_MENU_INACTIVE},
    { "Erase Drag", 0,&CallbackBase::cb,&box->m_dragEraser},
    { "Zoom", 0,&CallbackBase::cb,&box->m_setZoomMode},
    { "Ellipse", 0,&CallbackBase::cb,&box->m_setEllipseMode},
    { "Box",   0,&CallbackBase::cb,&box->m_setBoxMode},
    { "Draw",   0,&CallbackBase::cb,&box->m_setDrawMode},
    
//                    { "Erase",0,&CallbackBase::cb,&box->m_eraser},
    
//                     FL_MENU_DIVIDER},

    {0},
//    {"Redraw",0,&CallbackBase::cb,&box->m_redrawer},
    {0}
};
 m_pToolboxMenu = &editPopupMenu[12];

 return editPopupMenu;
}



#ifdef FLPDA
 // specific code that uses Flek and flpda
#include <flpda/Widget_Factory.h>


Fl_Window *PrescribbleApp::createArea( )
{
    Fl_App_Window *window; 

    Fl::set_color(FL_SELECTION_COLOR, 0, 0, 0); 
    
    window = new PresAppWindow( XSIZE, 
                                 YSIZE, 
                                 "Prescribble", this);
     window->color(FL_WHITE);
     window->resizable(window);       


    m_pMainWindow = window;
    
    PrescribbleArea *box 
        = new PrescribbleArea( m_notes[m_currentNote], 
                               0,0, 
                               XSIZE , YSIZE ,
                               m_config ,this);
    
    m_pArea = box;

    window->end();
    
    Fl_Dockable_Window* toolbar = WidgetFactory::new_toolbar();
    
    
    
    Fl_Menu_Button *mbut
        = Widget_Factory::new_menu_button( 
            0,YSIZE-MENUYSIZE,
            "File"
            );
    
    
    mbut->menu(getFilePopupMenu());
    
    
    
      
    mbut
        //= new Fl_Menu_Button(
        = Widget_Factory::new_menu_button( 
            XSIZE/6 ,YSIZE-MENUYSIZE, // XSIZE/6,MENUYSIZE,
            "Edit"
            );

    mbut->menu( getEditPopupMenu(box) );
    m_pEditMenuButton = mbut;




    new Fl_Box( FL_NO_BOX, 0,0,6,6,"");//spacing
    
    
    
    
    // UNDO
    Fl_Button *but
        = Widget_Factory::new_button( 
//                = new Fl_Button(
            2*XSIZE/6 + XSIZE/(6*2*2)  ,YSIZE-MENUYSIZE, 
            //                  XSIZE/(6*2),MENUYSIZE,
            "@|<"
            );
    but->labelsize(8);
    but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
    but->labeltype(FL_SYMBOL_LABEL);
    but->callback( &CallbackBase::cb,&box->m_undoer );
    m_pUndoButton = but;
    
    // REDO
    but
        = Widget_Factory::new_button( 
//                = new Fl_Button(
            2*XSIZE/6 + XSIZE/(6*2*2/3) ,YSIZE-MENUYSIZE, 
//                    XSIZE/(6*2),MENUYSIZE,
            "@>|"
            );
    but->labelsize(8);
    but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
    but->labeltype(FL_SYMBOL_LABEL);
    but->callback( &CallbackBase::cb,&box->m_redoer );
    m_pRedoButton = but;
    
    
    new Fl_Box( FL_NO_BOX, 0,0,6,6,""); //spacing
    
    
    // PREV
    but 
        = Widget_Factory::new_button( 
//                = new Fl_Button(
            4*XSIZE/6 ,YSIZE-MENUYSIZE, 
//                    XSIZE/(6*2),MENUYSIZE,
            "@<-");
    but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
    but->callback( &PresApp_Callback::cb, &m_toPrev );
    but->labeltype(FL_SYMBOL_LABEL);
    
    m_pLeftButton = but;

    
    //FEEDBACK
    m_pFeedback
        = new Fl_Button( //FL_DOWN_BOX,
            4*XSIZE/6+XSIZE/(6*2) ,YSIZE-MENUYSIZE, 
            XSIZE-2*XSIZE/(6*2)-4*XSIZE/6,MENUYSIZE,
            "...");
    m_pFeedback->labelsize(8);
    m_pFeedback->size( XSIZE-2*XSIZE/(6*2)-4*XSIZE/6, 
                       Widget_Factory::buttonheight() );
    m_pFeedback->callback(&CallbackBase::cb,&box->m_redrawer);
    feedbackNotePage();
    

    
    // NEXT
    but 
        = Widget_Factory::new_button( 
//                = new Fl_Button(
            XSIZE-XSIZE/(6*2) ,YSIZE-MENUYSIZE, 
//                    XSIZE/(6*2),MENUYSIZE,
            "@->");
    but->labeltype(FL_SYMBOL_LABEL);
    but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
    but->callback( &PresApp_Callback::cb, &m_toNext );
    m_pRightButton = but;
    

    
//            Fl_Page_UpDown_Button* pb = WidgetFactory::new_pagekey();
    //browser->page_updown_button(pb);
    
    
    toolbar->end();
    window->add_dockable(toolbar, 1);
    
    
//            window->end();

#else
    
     Fl_Window *PrescribbleApp::createArea( )
        {
            Fl_Window *window 
                = new PresAppWindow( XSIZE, YSIZE,"Prescribble", this);
                //= Widget_Factory::new_window("Prescribble");
            // |- messes up the keys...

            m_pMainWindow = window;


//            Fl_Scroll *scroll = new Fl_Scroll(0,0,XSIZE,YSIZE-MENUYSIZE);
           
/* 
            PresAppWindow *internalwin 
                = new PresAppWindow( XSIZE, YSIZE- MENUYSIZE,
                                     "Prescribble", this);
            
            window->add( internalwin );
*/

            PrescribbleArea *box 
                = new PrescribbleArea( m_notes[m_currentNote], 
                                       0,0, 
                                       XSIZE, YSIZE-MENUYSIZE,
                                       m_config , this);
            
            m_pArea = box;
//            internalwin->end();

//            scroll->end();
//            window->resizable(scroll);
//            window->end();

//            Fl_Dockable_Window* toolbar = WidgetFactory::new_toolbar();



            Fl_Menu_Button *mbut
                 = new Fl_Menu_Button(              
                     0,YSIZE-MENUYSIZE, XSIZE/6,MENUYSIZE,
                     "File"
                     );

//                = Widget_Factory::new_menu_button( 
//                    "File",
//                        0,YSIZE-MENUYSIZE,
//                    "File"
//                    );
    //        (static_cast<Fl_Widget*>(mbut))
     //           ->size( XSIZE/6, Widget_Factory::buttonheight() );


            mbut->labelsize(8);


            mbut->menu(getFilePopupMenu());

            mbut
                = new Fl_Menu_Button(
//                = Widget_Factory::new_menu_button( 
                    XSIZE/6 ,YSIZE-MENUYSIZE,  XSIZE/6,MENUYSIZE,
                    "Edit"
                    );
            mbut->labelsize(8);
          //  (static_cast<Fl_Widget*>(mbut))
           //     ->size( XSIZE/6, Widget_Factory::buttonheight() );

            mbut->menu( getEditPopupMenu(box) );
            m_pEditMenuButton = mbut;






            //new Fl_Box( FL_NO_BOX, 0,0,6,6,"");//spacing




            // UNDO
            Fl_Button *but
//                = Widget_Factory::new_button( 
                = new Fl_Button(
                    2*XSIZE/6 + XSIZE/(6*2*2)  ,YSIZE-MENUYSIZE, 
                    XSIZE/(6*2),MENUYSIZE,
                    "@|<"
                    );
            but->labelsize(8);
 //           but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
            but->labeltype(FL_SYMBOL_LABEL);
            but->callback( &CallbackBase::cb,&box->m_undoer );
            m_pUndoButton = but;

            // REDO
           but
//                = Widget_Factory::new_button( 
                = new Fl_Button(
                    2*XSIZE/6 + XSIZE/(6*2*2/3) ,YSIZE-MENUYSIZE, 
                    XSIZE/(6*2),MENUYSIZE,
                    "@>|"
                    );
            but->labelsize(8);
//            but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
            but->labeltype(FL_SYMBOL_LABEL);
            but->callback( &CallbackBase::cb,&box->m_redoer );
            m_pRedoButton = but;


            new Fl_Box( FL_NO_BOX, 0,0,6,6,""); //spacing


            // PREV
            but 
//                = Widget_Factory::new_button( 
                = new Fl_Button(
                    4*XSIZE/6 ,YSIZE-MENUYSIZE, 
                    XSIZE/(6*2),MENUYSIZE,
                    "@<-");
//            but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
            but->callback( &PresApp_Callback::cb, &m_toPrev );
            but->labeltype(FL_SYMBOL_LABEL);
            m_pLeftButton = but;


            //FEEDBACK
            m_pFeedback
                = new Fl_Button( //FL_DOWN_BOX,
                             4*XSIZE/6+XSIZE/(6*2) ,YSIZE-MENUYSIZE, 
                             XSIZE-2*XSIZE/(6*2)-4*XSIZE/6,MENUYSIZE,
                             "...");
            m_pFeedback->labelsize(8);
//            m_pFeedback->size( XSIZE-2*XSIZE/(6*2)-4*XSIZE/6, 
//                               Widget_Factory::buttonheight() );
            m_pFeedback->callback(&CallbackBase::cb,&box->m_redrawer);
            feedbackNotePage();



           // NEXT
            but 
//                = Widget_Factory::new_button( 
                = new Fl_Button(
                    XSIZE-XSIZE/(6*2) ,YSIZE-MENUYSIZE, 
                    XSIZE/(6*2),MENUYSIZE,
                    "@->");
            but->labeltype(FL_SYMBOL_LABEL);
//            but->size( XSIZE/(6*2), Widget_Factory::buttonheight() );
            but->callback( &PresApp_Callback::cb, &m_toNext );
            m_pRightButton = but;

//            Fl_Page_UpDown_Button* pb = WidgetFactory::new_pagekey();
            //browser->page_updown_button(pb);
//            toolbar->end();
//            window->add_dockable(toolbar, 1);
            window->end();

#endif
            Fl::visual(FL_DOUBLE|FL_INDEX);

            m_pUndoButton->deactivate();
            m_pRedoButton->deactivate();

            window->show();
            return window;
  
        }
//};



void PrescribbleApp::updateUndoStatus(bool status )
{
    //m_pUndoButton->label( (status? "@|<" : "" ) );
    if(status) 
        m_pUndoButton->activate();
    else 
        m_pUndoButton->deactivate();
    //m_pUndoButton->redraw();
}
void PrescribbleApp::updateRedoStatus(bool status )
{
   // m_pRedoButton->label( (1? "@>|" : "" ) );
    if(status) 
        m_pRedoButton->activate();
    else 
        m_pRedoButton->deactivate();

    //m_pRedoButton->redraw();
}










//============== PresAppWindow

PresAppWindow::PresAppWindow( 
    int width, int height, const char* name, PrescribbleApp *pApp )
    :
#ifdef FLPDA 
    Fl_App_Window( width, height, name ), 
#else
 Fl_Double_Window( width, height, name ), 
#endif
    m_pApp( pApp )
{
}

int PresAppWindow::handleKeyboard(int evt)
{
    int key = Fl::event_key();
    
    switch (key){ 
        
    case FL_Left : 
        if( Fl::event_state(FL_SHIFT) )
            m_pApp->m_noteBackward.callback();
        else
            m_pApp->prevNote(0);

        return 1;
    case FL_Right : 
      if( Fl::event_state(FL_SHIFT) )
            m_pApp->m_noteForward.callback();
        else
            m_pApp->nextNote(0);
        return 1;


    case FL_Page_Up :
        if( Fl::event_state(FL_SHIFT) )
        {
            m_pApp->m_pArea->m_undoer.callback();
        }
        else
        {
            m_pApp->zoom(-1);
            //m_pApp->toolSelect(-1);

        }
        return 1;
    case FL_Page_Down :
        if( Fl::event_state(FL_SHIFT) )
        {
            m_pApp->m_pArea->m_redoer.callback();
        }
        else
        {        
            //m_pApp->zoom(1);
            m_pApp->toolSelect(1);
        }
        return 1;
                
    }

    return Fl_Window::handle(evt);
}


int PresAppWindow::handle( int event )
{
    
    if( event == FL_KEYBOARD )
    {
        return handleKeyboard(event);
    }
    return Fl_Window::handle(event);
}












//================= MAIN =======================

int main( int argc, char **argv )
{

    PresConfig conf;


    // command line arguments
    if(argc>1)
        for(int i = 1;i<argc;i++)
        {
            if( std::strcmp( argv[i],"-hl")==0 ) 
                 conf.horizlines = true;
            if( std::strcmp( argv[i],"-nohl")==0 ) 
                 conf.horizlines = false;
            if( std::strcmp( argv[i],"-hs")==0 && i+1<argc) 
                conf.horizlinespace = std::atoi(argv[i+1]);

            if( std::strcmp( argv[i],"-vl")==0 ) 
                 conf.vertlines = true;
            if( std::strcmp( argv[i],"-novl")==0 ) 
                 conf.vertlines = false;
            if( std::strcmp( argv[i],"-vs")==0 && i+1<argc) 
                conf.vertlinespace = std::atoi(argv[i+1]);

            if( std::strcmp( argv[i],"-auto")==0 )
            { 
                 conf.quietLoadOnEntry = true;
                 conf.quietSaveOnExit  = true; 
            }

            if( std::strcmp( argv[i],"-r")==0 && i+1<argc) 
                conf.pointrange = std::atoi(argv[i+1]);

            if( std::strcmp( argv[i],"-maxredo")==0 && i+1<argc) 
                conf.m_maxRedoStrokes = std::atoi(argv[i+1]);

            if( std::strcmp( argv[i],"-eraserange")==0 && i+1<argc) 
                conf.m_eraseRange = std::atoi(argv[i+1]);
            
            if( std::strcmp( argv[i],"-f")==0 && i+1<argc) 
                conf.filename = argv[i+1];

           if( std::strcmp( argv[i],"-redrawless")==0 ) 
                conf.onlyCheatRedrawDuringMouseDown = false;

           if( std::strcmp( argv[i],"-ziphack")==0 ) 
               conf.allowZipUsage = true;
           if( std::strcmp( argv[i],"-noziphack")==0 ) 
               conf.allowZipUsage = false;


           if( std::strcmp( argv[i],"-X")==0 ) 
               conf.m_experimental = true;


        }



    conf.sanitize();
    PrescribbleApp app(conf);
    app.createArea();
    app.start();
    return Fl::run();
}
