/* * Presentation * Copyright (C) 2007 by Martin Sevior * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #define USE_PIXMAP 0 #include #include #include #include #include #include #include #include "xap_Module.h" #include "xap_App.h" #include "xap_Frame.h" #include "fv_View.h" #include "fl_DocLayout.h" #include "ev_EditMethod.h" #include "ie_imp.h" #include "ie_exp.h" #include "ie_types.h" #include "ap_Convert.h" #include "ap_EditMethods.h" #include "ev_EditBits.h" #include "Presentation.h" #include "ap_LoadBindings.h" #include "ev_NamedVirtualKey.h" #include "ut_bytebuf.h" #include "ap_Menu_Id.h" #include "ev_Menu_Actions.h" #include "ev_Menu.h" #include "ev_Menu_Layouts.h" #include "ev_Menu_Labels.h" #include "xap_Menu_Layouts.h" #include "gr_Graphics.h" #include "gr_DrawArgs.h" #include "fp_Page.h" #include "gr_Painter.h" #if USE_PIXMAP #include #include "gr_UnixPangoGraphics.h" #include "gr_UnixPangoPixmapGraphics.h" #endif #ifdef ABI_PLUGIN_BUILTIN #define abi_plugin_register abipgn_presentation_register #define abi_plugin_unregister abipgn_presentation_unregister #define abi_plugin_supports_version abipgn_presentation_supports_version // dll exports break static linking #define ABI_BUILTIN_FAR_CALL extern "C" #else #define ABI_BUILTIN_FAR_CALL ABI_FAR_CALL ABI_PLUGIN_DECLARE("Presentation") #endif #define RES_TO_STATUS(a) ((a) ? 0 : -1) static bool Presentation_start (AV_View * v, EV_EditMethodCallData * d); static bool Presentation_end (AV_View * v, EV_EditMethodCallData * d); static bool Presentation_nextPage (AV_View * v, EV_EditMethodCallData * d); static bool Presentation_prevPage (AV_View * v, EV_EditMethodCallData * d); static bool Presentation_context (AV_View * v, EV_EditMethodCallData * d); Presentation myPresentation; EV_EditMouseContext PresentationContextID = EV_EMC_EMBED; static XAP_Menu_Id presentationID; static const char * szPresentation = "Presentation"; static const char * szPresentationStatus = "View the document in presentation mode"; static const char * szNextSlide = "Next Slide"; static const char * szPrevSlide = "Previous Slide"; static const char * szEndPresentation = "End Presentation"; static XAP_Menu_Id nextSlideID; static XAP_Menu_Id prevSlideID; static XAP_Menu_Id endPresentationID; // // Presentation_registerMethod() // ----------------------- // Adds Presentation_start, Presentation_end to the EditMethod list // static void Presentation_registerMethod () { // First we need to get a pointer to the application itself. XAP_App *pApp = XAP_App::getApp (); // Create an EditMethod that will link our method's name with // it's callback function. This is used to link the name to // the callback. EV_EditMethod *myEditMethod = new EV_EditMethod ("Presentation_start", // name of callback function Presentation_start, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); // Now we need to get the EditMethod container for the application. // This holds a series of Edit Methods and links names to callbacks. EV_EditMethodContainer *pEMC = pApp->getEditMethodContainer (); // We have to add our EditMethod to the application's EditMethodList // so that the application will know what callback to call when a call pEMC->addEditMethod (myEditMethod); myEditMethod = new EV_EditMethod ("Presentation_end", // name of callback function Presentation_end, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); pEMC->addEditMethod (myEditMethod); myEditMethod = new EV_EditMethod ("Presentation_nextPage", // name of callback function Presentation_nextPage, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); pEMC->addEditMethod (myEditMethod); myEditMethod = new EV_EditMethod ("Presentation_prevPage", // name of callback function Presentation_prevPage, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); pEMC->addEditMethod (myEditMethod); myEditMethod = new EV_EditMethod ("Presentation_context", // name of callback function Presentation_context, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); pEMC->addEditMethod (myEditMethod); // Now we need to grab an ActionSet. This is going to be used later // on in our for loop. Take a look near the bottom. EV_Menu_ActionSet* pActionSet = pApp->getMenuActionSet(); XAP_Menu_Factory * pFact = pApp->getMenuFactory(); // Put it after presentationID= pFact->addNewMenuAfter("Main",NULL,AP_MENU_ID_VIEW_SHOWPARA,EV_MLF_Normal); UT_DEBUGMSG(("presentationID %d \n",presentationID)); pFact->addNewLabel(NULL,presentationID,szPresentation,szPresentationStatus); // Create the Action that will be called. EV_Menu_Action* myPresentationAction = new EV_Menu_Action( presentationID, // id that the layout said we could use 0, // no, we don't have a sub menu. 0, // no, we don't raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you "Presentation_start", // callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); // Now what we need to do is add this particular action to the ActionSet // of the application. This forms the link between our new ID that we // got for this particular frame with the EditMethod that knows how to // call our callback function. pActionSet->addAction(myPresentationAction); // // OK Now build a context menu // PresentationContextID = pFact->createContextMenu("PresentationContext"); prevSlideID = pFact->addNewMenuBefore("PresentationContext",NULL,0,EV_MLF_Normal,0); pFact->addNewLabel(NULL,prevSlideID,szPrevSlide, NULL); nextSlideID = pFact->addNewMenuBefore("PresentationContext",NULL,0,EV_MLF_Normal,0); pFact->addNewLabel(NULL,nextSlideID,szNextSlide, NULL); endPresentationID = pFact->addNewMenuBefore("PresentationContext",NULL,0,EV_MLF_Normal,0); pFact->addNewLabel(NULL,endPresentationID,szEndPresentation, NULL); myPresentationAction = new EV_Menu_Action( prevSlideID, // id that the layout said we could use 0, // no, we don't have a sub menu. 0, // no, we don't raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you "Presentation_prevPage", // callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); pActionSet->addAction(myPresentationAction); myPresentationAction = new EV_Menu_Action( nextSlideID, // id that the layout said we could use 0, // no, we don't have a sub menu. 0, // no, we don't raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you "Presentation_nextPage", // callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); pActionSet->addAction(myPresentationAction); myPresentationAction = new EV_Menu_Action( endPresentationID, // id that the layout said we could use 0, // no, we don't have a sub menu. 0, // no, we don't raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you "Presentation_end", // callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); pActionSet->addAction(myPresentationAction); } static void Presentation_RemoveFromMethods () { // First we need to get a pointer to the application itself. XAP_App *pApp = XAP_App::getApp (); // remove the edit method EV_EditMethodContainer *pEMC = pApp->getEditMethodContainer (); EV_EditMethod *pEM = ev_EditMethod_lookup ("Presentation_start"); pEMC->removeEditMethod (pEM); DELETEP (pEM); pEM = ev_EditMethod_lookup ("Presentation_end"); pEMC->removeEditMethod (pEM); DELETEP (pEM); pEM = ev_EditMethod_lookup ("Presentation_nextPage"); pEMC->removeEditMethod (pEM); DELETEP (pEM); pEM = ev_EditMethod_lookup ("Presentation_prevPage"); pEMC->removeEditMethod (pEM); DELETEP (pEM); pEM = ev_EditMethod_lookup ("Presentation_context"); pEMC->removeEditMethod (pEM); DELETEP (pEM); XAP_Menu_Factory * pFact = pApp->getMenuFactory(); pFact->removeMenuItem("Main",NULL,presentationID); } // ----------------------------------------------------------------------- // // Abiword Plugin Interface // // ----------------------------------------------------------------------- ABI_BUILTIN_FAR_CALL int abi_plugin_register (XAP_ModuleInfo * mi) { mi->name = "Presentation"; mi->desc = "This enables AbiWord to make presentations"; mi->version = ABI_VERSION_STRING; mi->author = "Martin Sevior "; mi->usage = "Presentaton_start"; Presentation_registerMethod (); return 1; } ABI_BUILTIN_FAR_CALL int abi_plugin_unregister (XAP_ModuleInfo * mi) { mi->name = 0; mi->desc = 0; mi->version = 0; mi->author = 0; mi->usage = 0; Presentation_RemoveFromMethods (); return 1; } ABI_BUILTIN_FAR_CALL int abi_plugin_supports_version (UT_uint32 /*major*/, UT_uint32 /*minor*/, UT_uint32 /*release*/) { return 1; } // ----------------------------------------------------------------------- // // Presentation_start Invocation Code // // ----------------------------------------------------------------------- // // Presentation_start // ------------------- // This is the function that puts AbiWord into full screen mode and set the // keybindings for a presentation. // static bool Presentation_start (AV_View * v, EV_EditMethodCallData * /*d*/) { myPresentation.start(v); return true; } // // Presentation_end // ------------------- // This functions takes AbiWord out of full screen mode and restores the // previous keybindings. // static bool Presentation_end (AV_View * /*v*/, EV_EditMethodCallData * /*d*/) { myPresentation.end(); return true; } static bool Presentation_nextPage (AV_View * /*v*/, EV_EditMethodCallData * /*d*/) { myPresentation.showNextPage(); return true; } static bool Presentation_prevPage (AV_View * /*v*/, EV_EditMethodCallData * /*d*/) { myPresentation.showPrevPage(); return true; } static bool Presentation_context (AV_View * v, EV_EditMethodCallData * d) { FV_View * pView = static_cast(v); XAP_Frame * pFrame = static_cast (pView->getParentData()); UT_sint32 xPos = d->m_xPos; UT_sint32 yPos = d->m_yPos; const char * szContextMenuName = XAP_App::getApp()->getMenuFactory()->FindContextMenu(PresentationContextID); UT_DEBUGMSG(("Context Menu Name is........ %s \n",szContextMenuName)); if (!szContextMenuName) return false; bool res = pFrame->runModalContextMenu(pView,szContextMenuName, xPos,yPos); pFrame->nullUpdate(); GR_Graphics * pG = pView->getGraphics(); if(pG) pG->allCarets()->disable(); return res; } // Hack into seperate strings because C doesn't allow multi-line strings static UT_String sPresBindings[] = {"name, Presentation\n", "mse,B1,CU,Presentation_nextPage,,,,,,\n", "mse,B1,CL,Presentation_nextPage,,,,,,\n", "mse,B1,CT,Presentation_nextPage,,,,,,\n", "mse,B1,CM,Presentation_nextPage,,,,,,\n", "mse,B1,CR,Presentation_nextPage,,,,,,\n", "mse,B1,CI,Presentation_nextPage,,,,,,\n", "mse,B1,CZ,Presentation_nextPage,,,,,,\n", "mse,B1,CF,Presentation_nextPage,,,,,,\n", "mse,B1,CH,Presentation_nextPage,,,,,,\n", "mse,B1,CV,Presentation_nextPage,,,,,,\n", "mse,B3,CU,Presentation_context,,,,,,\n", "mse,B3,CL,Presentation_context,,,,,,\n", "mse,B3,CT,Presentation_context,,,,,,\n", "mse,B3,CM,Presentation_context,,,,,,\n", "mse,B3,CR,Presentation_context,,,,,,\n", "mse,B3,CI,Presentation_context,,,,,,\n", "mse,B3,CZ,Presentation_context,,,,,,\n", "mse,B3,CF,Presentation_context,,,,,,\n", "mse,B3,CH,Presentation_context,,,,,,\n", "mse,B3,CV,Presentation_context,,,,,,\n", "nvk,ESCAPE,Presentation_end,Presentation_end,Presentation_end,Presentation_end,,,,,\n", "nvk,PAGEUP,Presentation_prevPage,,,,,,\n", "nvk,PAGEDOWN,Presentation_nextPage,,,,,,\n", "nvk,LEFT,Presentation_prevPage,,,,,,\n", "nvk,UP,Presentation_prevPage,,,,,,\n", "nvk,RIGHT,Presentation_nextPage,,,,,,\n", "nvk,DOWN,Presentation_nextPage,,,,,,\n", "nvk,F1,,Presentation_end,Presentation_end,Presentation_end,Presentation_end,,,,,\n", "nvk,F2,,Presentation_end,Presentation_end,Presentation_end,Presentation_end,,,,,\n", "nvk,F3,,Presentation_end,Presentation_end,Presentation_end,Presentation_end,,,,,\n", "nvk,F4,,Presentation_end,Presentation_end,Presentation_end,Presentation_end,,,,,\n" "nvk,F5,,Presentation_end,Presentation_end,Presentation_end,Presentation_end,,,,,\n", ""}; Presentation::Presentation(void): m_pApp(NULL), m_pView(NULL), m_iPage(0), m_bDrewNext(false), m_bDrewPrev(false) { m_pApp = XAP_App::getApp(); } Presentation::~Presentation (void) { } bool Presentation::_loadPresentationBindings(AV_View * pView) { EV_EditMethodContainer * pEMC = m_pApp->getEditMethodContainer(); g_return_val_if_fail (pEMC != 0, FALSE); if(m_pApp->getBindingMap("Presentation") != NULL) { return true; } // get the path where our app data is located XAP_App * pApp = static_cast(XAP_App::getApp()); UT_String data_path( pApp->getAbiSuiteLibDir() ); data_path += G_DIR_SEPARATOR; data_path += "Presentation.xml"; EV_EditMethod * pLoadB = pEMC->findEditMethodByName ("com.abisource.abiword.loadbindings.fromURI"); g_return_val_if_fail (pLoadB != 0, false); EV_EditMethodCallData calldata(data_path.c_str(),data_path.size()); calldata.m_xPos = 0; calldata.m_yPos = 0; return (pLoadB->Fn(pView,&calldata) ? TRUE : FALSE); } bool Presentation::start(AV_View * view) { EV_EditMethodContainer * pEMC = m_pApp->getEditMethodContainer(); g_return_val_if_fail (pEMC != 0, FALSE); m_pView = static_cast(view); m_sPrevBindings = m_pApp->getInputMode(); _loadPresentationBindings(view); UT_sint32 i = m_pApp->setInputMode("Presentation"); if(i < 0 ) return false; // get a handle to the actual EditMethod EV_EditMethod * pFullScreen = pEMC->findEditMethodByName ("viewFullScreen"); g_return_val_if_fail (pFullScreen != 0, false); const char * sz =""; EV_EditMethodCallData calldata(sz,0); calldata.m_xPos = 0; calldata.m_yPos = 0; m_iPage = 0; XAP_Frame * pFrame = static_cast(m_pView->getParentData()); m_OldZoomType = pFrame->getZoomType(); m_iOldZoom = pFrame->getZoomPercentage(); pFrame->hideMenuScroll(true); bool b = false; b = (pFullScreen->Fn(view,&calldata) ? TRUE : FALSE); GR_Graphics * pG = m_pView->getGraphics(); // // Let all the configure events propagate to their full extent // for(i= 0; i<20;i++) pFrame->nullUpdate(); pFrame->setZoomType(XAP_Frame::z_PAGEWIDTH); i = m_pView-> calculateZoomPercentForPageWidth(); pFrame->quickZoom(i); for(i= 0; i<20;i++) pFrame->nullUpdate(); b= showNextPage(); if(pG) pG->allCarets()->disable(); return b; } bool Presentation::end(void) { if(m_sPrevBindings.size() == 0) return false; EV_EditMethodContainer * pEMC = m_pApp->getEditMethodContainer(); g_return_val_if_fail (pEMC != 0, FALSE); UT_sint32 i = m_pApp->setInputMode(m_sPrevBindings.c_str()); if(i <=0 ) return false; // get a handle to the actual EditMethod EV_EditMethod * pFullScreen = pEMC->findEditMethodByName ("viewFullScreen"); g_return_val_if_fail (pFullScreen != 0, false); const char * sz =""; EV_EditMethodCallData calldata(sz,0); calldata.m_xPos = 0; calldata.m_yPos = 0; XAP_Frame * pFrame = static_cast(m_pView->getParentData()); pFrame->hideMenuScroll(false); bool b= (pFullScreen->Fn(static_cast(m_pView),&calldata) ? TRUE : FALSE); pFrame->setZoomType(m_OldZoomType); pFrame->setZoomPercentage(m_iOldZoom); pFrame->quickZoom(m_iOldZoom); return b; } bool Presentation::drawNthPage(UT_sint32 iPage) { GR_Graphics * pG = m_pView->getGraphics(); GR_Painter p(pG); #if USE_PIXMAP GR_Image * pImage = renderPageToImage(iPage,pG->getZoomPercentage()); UT_DEBUGMSG(("Image Display Width %d Image Display Height %d Zoom %d \n",pImage->getDisplayWidth(),pImage->getDisplayHeight(),pG->getZoomPercentage())); p.drawImage(pImage,0,0); delete pImage; #else dg_DrawArgs da; da.pG = pG; da.xoff = 0; da.yoff = 0; m_pView->draw(iPage, &da); fp_Page * pPage = m_pView->getLayout()->getNthPage(iPage); UT_sint32 iTotalHeight = (pPage->getHeight() + m_pView->getPageViewSep())*iPage; m_pView->setYScrollOffset(iTotalHeight); if(pG) pG->allCarets()->disable(); #endif return true; } #if USE_PIXMAP /*! * Caller must delete the returned image. */ GR_Image * Presentation::renderPageToImage(UT_sint32 iPage, UT_uint32 iZoom) { GR_UnixPangoGraphics * pVG = static_cast(m_pView->getGraphics()); UT_sint32 iWidth = pVG->tdu(m_pView->getWindowWidth()); UT_sint32 iHeight = pVG->tdu(m_pView->getWindowHeight()); double ZoomRat = static_cast(iZoom)/static_cast(pVG->getZoomPercentage()); iWidth = static_cast(static_cast(iWidth)*ZoomRat); iHeight = static_cast(static_cast(iHeight)*ZoomRat); // // Create an offscreen Graphics to draw into // UT_DEBUGMSG(("rederpagetoimage Width %d Height %d zoom %d \n",iWidth,iHeight,iZoom)); GdkPixmap* pPixmap = gdk_pixmap_new(pVG->getWindow(),iWidth,iHeight,-1); GR_UnixPixmapAllocInfo ai(pPixmap); GR_UnixPangoPixmapGraphics * pG = (GR_UnixPangoPixmapGraphics*)GR_UnixPangoPixmapGraphics::graphicsAllocator(ai); pG->setZoomPercentage(iZoom); GR_Painter * pPaint = new GR_Painter(pG); pPaint->clearArea(0,0,m_pView->getWindowWidth(),m_pView->getWindowHeight()); dg_DrawArgs da; da.pG = pG; da.xoff = 0; da.yoff = 0; m_pView->getLayout()->setQuickPrint(pG); m_pView->draw(iPage, &da); UT_Rect r; r.left = 0; r.top = 0; r.width = pG->tlu(iWidth); r.height = pG->tlu(iHeight); GR_Image * pImage = pPaint->genImageFromRectangle(r); m_pView->getLayout()->setQuickPrint(NULL); DELETEP(pPaint); DELETEP(pG); return pImage; } #endif bool Presentation::showNext(void) { return showNextPage(); } bool Presentation::showNextPage(void) { if(m_bDrewPrev && (m_iPage + 1< static_cast(m_pView->getLayout()->countPages()))) { m_iPage++; } drawNthPage(m_iPage); if(m_iPage+1 < static_cast(m_pView->getLayout()->countPages())) m_iPage++; m_bDrewNext = true; m_bDrewPrev = false; return true; } bool Presentation::showPrevPage(void) { if(m_iPage > 0) { if(m_iPage > 1 && m_bDrewNext && (m_iPage +1 < m_pView->getLayout()->countPages())) m_iPage--; m_iPage--; } else return false; drawNthPage(m_iPage); m_bDrewNext = false; m_bDrewPrev = true; return true; }