#pragma rtGlobals=1 // Use modern global access method. #pragma IgorVersion=6.2 // for URLEncode #pragma version=1.0 // LaTeX Pictures.ipf // // JP, 120208, Version 1. // // This procedure file implements a "LaTeX Pictures" panel which uses a web site to render LaTeX math equations into PNG bitmaps. // // This is mostly a proof-of-concept that would be improved by finding or establishing // an online LaTeX-to-PDF renderer to provide high-resolution equations. // // This is not the place to look for LaTeX expertise, see the "LaTeX Help" button // and search online for "LaTeX math mode syntax". // // Let me take this opportunity to recommend LaTeXIt for Macintosh. // They get the PDF rendering right, and have a terrific user interface: // // http://www.chachatelier.fr/latexit/ // Menu "Misc" "LaTeX Pictures",/Q, LaTeXCreatePicturesPanel() End #if 0 // debugging Menu "Misc" "Show Pictures Table",/Q, LaTeXMemoryTable() "Delete all Latex Pictures",/Q, LaTeXtClear() End #endif Static StrConstant ksPanelName= "LaTeXPanel" Static StrConstant ksNotebookName= "LaTeXPanel#LATEX" Static StrConstant ksLaTeXPrefix= "LaTeXPict" // that is, picture names starting with this are deemed LaTeX pictures Static StrConstant ksLaTeXMatchPattern= "LaTeXPict*" Static StrConstant ksPreviewPictName="LaTeXPreview" Static StrConstant ksTempFolder="Temporary" #ifdef WINDOWS Static Constant kSetvarVPosTweak=3 #else Static Constant kSetvarVPosTweak=0 #endif Function LaTeXCreatePicturesPanel() LaTeXInit() DoWindow/K $ksPanelName NewPanel/K=1/W=(51,60,582,466)/N=$ksPanelName as "LaTeX Pictures" DefaultGuiFont/W=#/Mac popup={"_IgorMedium",12,0},all={"_IgorMedium",12,0} DefaultGuiFont/W=#/Win popup={"_IgorMedium",0,0},all={"_IgorMedium",0,0} SetDrawLayer ProgFront DrawPICT 127,301,1,1,LaTeXPreview CustomControl link,pos={10,4},size={400,16},fsize=10,title="\\JLLaTeX rendering by \\K(0,0,65535)\\f04Roger's Online Equation Editor" CustomControl link,frame=0,value= root:Packages:LaTeXPictures:link,proc=LaTeXLinkcontrolproc Button delete,pos={27,34},size={60,20},proc=LaTeXDeleteButtonProc,title="Delete" PopupMenu LaTeXPictures,pos={122,33},size={177,20},proc=LaTeXPopMenuProc,title="LaTeX Pictures" PopupMenu LaTeXPictures,mode=2,popvalue="_new_",value= #"\"_new_;\"+LaTeXPicturesList(NumVarOrDefault(\"root:Packages:LaTeXPictures:fromTarget\",1))" CheckBox fromTarget,pos={123,66},size={139,16},proc=LaTeXFromTargetCheckProc,title="From Target Window" CheckBox fromTarget,variable= root:Packages:LaTeXPictures:fromTarget SetVariable windows,pos={288,68},size={900,15},title="Window(s) using this PICT:" SetVariable windows,fSize=9,frame=0,value= _STR:"" TitleBox title0,pos={26,78},size={69,32},title="\\JCEnter LaTeX\rexpression:", frame=0 Button example,pos={16,118},size={90,20},proc=LaTeXExampleButtonProc,title="Example 1 ->" Button example2,pos={15,146},size={90,20},proc=LaTeXExampleButtonProc,title="Example 2 ->" Button help,pos={15,176},size={90,20},proc=LaTeXHelpButtonProc,title="LaTeX Help" Slider size,pos={118,192},size={158,45},fSize=9,side= 2,vert= 0,ticks= 8 Slider size,limits={60,600,1},variable=:Packages:LaTeXPictures:dpi SetVariable setvarDPI,pos={289,198-kSetvarVPosTweak},size={68,15},bodyWidth=50,title="DPI" SetVariable setvarDPI,fSize=9 SetVariable setvarDPI,limits={60,600,1},value= root:Packages:LaTeXPictures:dpi PopupMenu textColor,pos={375,195},size={145,20} PopupMenu textColor,mode=1,popvalue="Black Text on White",value= #"\"Black Text on White;White Text on Black;\"" CheckBox antialias,pos={375,226},size={111,16},title="Antialiased Text",value= 1 Button update,pos={129,258},size={105,20},proc=LaTeXUpdateButtonProc,title="Update Picture" Button newDrawPICT,pos={8,329},size={105,20},proc=LaTeXNewDrawPICTButtonProc,title="New DrawPICT" Button newAnnotation,pos={8,299},size={105,20},proc=LaTeXNewAnnotationButtonProc,title="New Annotation" Button pictures,pos={15,370},size={90,20},title="Pictures...",proc=LaTeXPicturesButtonProc DefineGuide UGV0={FR,-25},UGV1={FL,118},UGH0={FT,186} NewNotebook /F=1 /N=LaTeX /W=(122,95,362,291)/FG=(UGV1,,UGV0,UGH0) /HOST=# Notebook kwTopWin, defaultTab=36, statusWidth=0, autoSave=1, showRuler=0, rulerUnits=1 Notebook kwTopWin newRuler=Normal, justification=0, margins={0,0,389}, spacing={0,0,0}, tabs={}, rulerDefaults={"Geneva",10,0,(0,0,0)} Notebook kwTopWin, zdata= "GaqDU%ejN7!Z)ts!+JDOp1=$K)nClX8AL$OXonuhNQhoT!s90qgJ2>bpXHk*Z:\"m$!0cgXb5" Notebook kwTopWin, zdataEnd= 1 RenameWindow #,LaTeX SetActiveSubwindow ## SetWindow $ksPanelName hook(LaTeXPanel)=LaTeXPanelWindowHook LaTeXUpdatePanelForActivate() String/G root:Packages:LaTeXPictures:previousLaTeXPicture = "" // to force an update ControlInfo/W=$ksPanelName LaTeXPictures LaTeXSetControlsByName(S_Value) EndMacro Function LaTeXPanelWindowHook(s) STRUCT WMWinHookStruct &s Variable hookResult = 0 strswitch(s.eventName) case "activate": LaTeXUpdatePanelForActivate() break case "kill": LaTeXPruneMemory() KillPICTs/Z $ksPreviewPictName break endswitch return hookResult End Function LaTeXUpdatePanelForActivate() NVAR fromTarget= root:Packages:LaTeXPictures:fromTarget String windowName= LaTeXTargetWindow() Variable disable if( strlen(windowName) == 0 ) fromTarget= 0 disable= 2 else disable= 0 endif CheckBox fromTarget,win=$ksPanelName,disable=disable LaTeXUpdatePicturesList(fromTarget) LaTeXEnableButtons() End // Debugging Function LaTeXMemoryTable() Wave/T/Z tw= root:Packages:LaTeXPictures:LaTeXMemory if( WaveExists(tw) ) DoWindow/K LaTeXMemoryTable Edit/N=LaTeXMemoryTable root:Packages:LaTeXPictures:LaTeXMemory.ld else DoAlert 0, "The La Text Memory text wave does not exist!" endif End // Debugging Function LaTeXtClear() Wave/T/Z tw= root:Packages:LaTeXPictures:LaTeXMemory if( WaveExists(tw) ) DoWindow/K LaTeXMemoryTable DoWindow/K $ksPanelName Variable row,rows= DimSize(tw,0) for(row=0; row= 0 ) // force an update; the strategy depends on the window type Variable type= WinType(windowName) switch( type ) case 1: // Graph DrawAction /W=$windowName getgroup=LaTeXDummyGroup, delete, begininsert SetDrawEnv /W=$windowName gstart, gname= LaTeXDummyGroup DrawText/W=$windowName 0,0, "Updating "+pictName SetDrawEnv /W=$windowName gstop DrawAction /W=$windowName endinsert DrawAction /W=$windowName getgroup=LaTeXDummyGroup, delete break case 3: // layout ModifyLayout/W=$windowName/Z fidelity=0 DoUpdate/W=$windowName ModifyLayout/W=$windowName/Z fidelity=1 DoUpdate/W=$windowName break case 7: // Panel break // it just works. endswitch endif while(1) End Function/S LaTeXWindowsUsingPICT(pictName) String pictName String list="" String windowName Variable index=0 do windowName= WinName(index,1+4+64) // top graphs, layouts, and panels, INCLUDING $ksPanelName if( strlen(windowName) == 0 ) break endif index += 1 String picts= LaTeXPictsInWindow(windowName) Variable whichItem= WhichListItem(pictName, picts) if( whichItem >= 0 ) list += windowName+";" endif while(1) return list End Function LaTeXRememberSettings(pictName, LaTeX,dpi,isWhiteOnBlack,isAntialiased) String pictName, LaTeX Variable dpi,isWhiteOnBlack,isAntialiased Variable index= -2 // not found if( strlen(pictName) ) Wave/T tw= LaTeXEnsureMemoryWave() // find by name; we use dimension label for each row index= FindDimLabel(tw,0,pictName) // returns -2 if not found (-1 is the overall dimension label) if( index == -2 ) // add a row. We'll put it up front to implement a Most Recently Used priority // this invalidates any indexes stored elsewhere, so don't store indexes (store names). InsertPoints/M=0 0, 1, tw SetDimLabel 0, 0, $pictName, tw index= 0 endif tw[index][%LaTeX]= LaTeX tw[index][%dpi]= num2istr(dpi) tw[index][%isWhiteOnBlack]= num2istr(isWhiteOnBlack) tw[index][%isAntialiased]= num2istr(isAntialiased) endif return index End // returns LaTeX // was LaTeXGetByName() Function/S LaTeXGetSettingsByName(pictName, dpi, isWhiteOnBlack, isAntiAliased) String pictName // can be _new_ Variable &dpi, &isWhiteOnBlack,&isAntiAliased // outputs String LaTeX= "Enter LaTeX expression here.\\\\ \r" // two back slashes to get one (we need two), then a space and a newline LaTeX += "Note: normal spaces are discarded, use \; to insert a space!" dpi=100 isWhiteOnBlack= 0 isAntiAliased= 1 if( strlen(pictName) && !LaTeXIsNew(pictName) ) Wave/T tw= LaTeXEnsureMemoryWave() // find by name; we use dimension label for each row Variable index= FindDimLabel(tw,0,pictName) // returns -2 if not found (-1 is the overall dimension label) if( index >= 0 ) LaTeX= tw[index][%LaTeX] dpi=str2num(tw[index][%dpi]) isWhiteOnBlack= str2num(tw[index][%isWhiteOnBlack]) isAntiAliased= str2num(tw[index][%isAntiAliased]) endif endif return LaTeX End Function/WAVE LaTeXEnsureMemoryWave() Wave/T/Z tw= root:Packages:LaTeXPictures:LaTeXMemory if( !WaveExists(tw) ) Make/T/O/N=(0,4) root:Packages:LaTeXPictures:LaTeXMemory/WAVE=tw SetDimLabel 1, 0, LaTeX, tw SetDimLabel 1, 1, dpi, tw SetDimLabel 1, 2, isWhiteOnBlack, tw SetDimLabel 1, 3, isAntialiased, tw endif return tw End // returns the pictures popup name // The returned string will NOT be "_new_", because if the popup is "_new_", // then a new unique pict name is created and returned. Function/S LaTeXRememberControlSettings(pictName) String pictName if( strlen(pictName) == 0 ) ControlInfo/W=$ksPanelName LaTeXPictures pictName= S_value // can be "_new_" endif Variable isNew= LaTeXIsNew(pictName) if( isNew ) pictName= UniqueName(ksLaTeXPrefix, 13, 0) // unique picture name endif String LaTeX= LaTeXGetNotebookText() ControlInfo/W=$ksPanelName size Variable dpi= V_Value ControlInfo/W=$ksPanelName antialias Variable isAntialiased= V_Value ControlInfo/W=$ksPanelName textColor Variable isWhiteOnBlack= V_Value==2 LaTeXRememberSettings(pictName,LaTeX,dpi,isWhiteOnBlack,isAntialiased) return pictName End Function/S LaTeXUpdateLaTeXPICT() ControlInfo/W=$ksPanelName LaTeXPictures String pictName= S_Value Variable isNew= LaTeXIsNew(pictName) pictName= LATexRememberControlSettings(pictName) Variable dpi, isWhiteOnBlack, isAntiAliased String LaTeX= LaTeXGetSettingsByName(pictName, dpi, isWhiteOnBlack, isAntiAliased) String createdName= LaTeXDownload(LaTeX,dpi,isWhiteOnBlack,isAntialiased,pictName) if( strlen(createdName) ) // mostly to check that all went well, it should be the same as pictName if( isNew ) // new means it's not in use anywhere yet // turn off From Target; it's not in any target window, yet. NVAR fromTarget= root:Packages:LaTeXPictures:fromTarget fromTarget= 0 else LaTeXUpdateWindowsWithPict(pictName) endif endif PopupMenu LaTeXPictures, win=$ksPanelName, popmatch=createdName return createdName End Function LaTeXIsNew(name) String name return CmpStr(name,"_new_") == 0 End Function LaTeXPICTExists(pictName) String pictName String emptyIfNotExists= PICTList(pictName,";","") Variable pictExists= strlen(emptyIfNotExists) return pictExists End Function LaTeXUpdatePicturesList(fromTarget) Variable fromTarget ControlInfo/W=$ksPanelName LaTeXPictures String currentName= S_value Variable wasNew= LaTeXIsNew(currentName) String windowName="_all_" if( fromTarget ) windowName= LaTeXTargetWindow() endif Variable mode=1 // _new_ if( strlen(windowName) ) String picts= LaTeXPictsInWindow(windowName) if( strlen(picts) ) mode=2 endif endif PopupMenu LaTeXPictures, win=$ksPanelName, mode=mode PopupMenu LaTeXPictures, win=$ksPanelName, popMatch=currentName // if possible // Possibly Update the LaTeXt and settings ControlInfo/W=$ksPanelName LaTeXPictures String newName= S_value if( CmpStr(newName, currentName) != 0 ) LaTeXSetControlsByName(newName) endif // always update the window list, because windows come and go, as do their use of the named picture LaTeXtUpdatePICTWindowList() End Function LaTeXtUpdatePICTWindowList() ControlInfo/W=$ksPanelName LaTeXPictures String windows= LaTeXWindowsUsingPICT(S_value) Variable fstyle= 0 String title="Window(s) using this PICT:" if( strlen(windows) ) Variable items= ItemsInList(windows) windows= RemoveEnding(ReplaceString(";", windows, ", "),", ") if( items == 1 ) title= "Window using this PICT:" else title= "Windows using this PICT:" endif fstyle= 1 else windows= "(none)" endif SetVariable windows win=$ksPanelName, fstyle=fstyle, title=title, value= _STR:windows End Function LaTeXSetControlsByName(pictName) String pictName Variable dpi, isWhiteOnBlack, isAntiAliased String LaTeX= LaTeXGetSettingsByName(pictName, dpi, isWhiteOnBlack, isAntiAliased) LaTeXSetNotebookText(LaTeX) Slider size, win=$ksPanelName, value=dpi PopupMenu textColor, win=$ksPanelName, mode=1+isWhiteOnBlack CheckBox antialias, win=$ksPanelName, value=isAntiAliased // sets the global variable, too LaTeXUpdatePreviewFromPICT(pictName) LaTeXEnableButtons() LaTeXtUpdatePICTWindowList() End Function LaTeXUpdatePreviewFromPICT(pictName) String pictName if( LaTeXIsNew(pictName) || !LaTeXPICTExists(pictName) ) LaTeXSetBlankPreview() else // No: this overwrites the clipboard // SavePICT/PICT=$pictName as "Clipboard" // LoadPICT/O/Q "Clipboard", $ksPreviewPictName // No: this requires Igor 6.23 //SavePICT/O/PICT=$pictName/P=_PictGallery_ as ksPreviewPictName // Sigh: use a temp file String fileName= "LaTeXIgorPreview.png" String localPath = SpecialDirPath("Temporary", 0, 0, 0) +fileName SavePICT/O/PICT=$pictName as localPath LoadPICT/Q/O localPath, $ksPreviewPictName // overwrites given name endif End Function LaTeXFromTargetCheckProc(ctrlName,checked) : CheckBoxControl String ctrlName Variable checked LaTeXUpdatePicturesList(checked) End Function/S LaTeXGetNotebookText() GetSelection notebook, $ksNotebookName, 1 // keep current selection Variable hadSelection= V_Flag if( hadSelection ) Variable old_startParagraph= V_startParagraph Variable old_V_startPos= V_startPos Variable old_V_endParagraph= V_endParagraph Variable old_V_endPos= V_endPos endif Notebook $ksNotebookName selection={startOfFile, endOfFile} GetSelection notebook, $ksNotebookName, 2 if( hadSelection ) Notebook $ksNotebookName selection={(old_startParagraph,old_V_startPos), (old_V_endParagraph,old_V_endPos)} endif return S_Selection End Function/S LaTeXSetNotebookText(LaTeX) String LaTeX String oldLaTeX= LaTeXGetNotebookText() Notebook $ksNotebookName selection={startOfFile, endOfFile}, text=LaTeX Notebook $ksNotebookName selection={startOfFile, startOfFile}, findText={"", 1} return oldLaTeX End Function LaTeXPopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl String ctrlName Variable popNum String popStr // new popup value, can be "_new_" // save the previous popup's LaTeX String previousName= StrVarOrDefault("root:Packages:LaTeXPictures:previousLaTeXPicture","") // can be _new_, also! if( CmpStr(previousName,popStr) != 0 ) LaTeXRememberControlSettings(previousName) // restore by name LaTeXSetControlsByName(popStr) String/G root:Packages:LaTeXPictures:previousLaTeXPicture = popStr // can be "_new_" endif End #include Function LaTeXLinkcontrolproc(s) struct WMCustomControlAction &s switch(s.eventCode) case kCCE_mouseup: // Mouse up in control. //Print "s.sVal= \""+s.sVal+"\"" BrowseURL(s.sVal) break endswitch return 0 End Function LaTeXEnableButtons() ControlInfo/W=$ksPanelName LaTeXPictures String pictName= S_Value Variable isNew= LaTeXIsNew(pictName) String LaTeX= LaTeXGetNotebookText() Variable disable= strlen(LaTeX) ? 0 : 2 ModifyControl/Z update, win=$ksPanelName, disable=disable if( disable == 0 ) if( isNew ) disable= 2 // user needs to click Update Picture to generate a persistent PICT name endif endif String windowName= LaTeXTargetWindow() if( disable == 0 ) if( strlen(windowName) == 0 ) disable= 2 // no place to put the pict endif endif ModifyControl/Z newDrawPICT, win=$ksPanelName, disable=disable if( disable == 0 && strlen(windowName) && WinType(windowName) == 7 ) disable= 2 // annotations aren't allowed in panels endif ModifyControl/Z newAnnotation, win=$ksPanelName, disable=disable disable= LaTeXIsNew(pictName) ? 2 : 0 if( disable == 0 ) String windows= LaTeXWindowsUsingPICT(S_value) disable= strlen(windows) ? 2 : 0 endif ModifyControl/Z delete, win=$ksPanelName, disable=disable End Function LaTeXUpdateButtonProc(ctrlName) : ButtonControl String ctrlName LaTeXUpdateLaTeXPICT() LaTeXtUpdatePICTWindowList() End Function LaTeXNewAnnotationButtonProc(ctrlName) : ButtonControl String ctrlName ControlInfo/W=$ksPanelName LaTeXPictures String pictName= S_Value String windowName= LaTeXTargetWindow() if( (!LaTeXIsNew(pictName)) && strlen(pictName) && strlen(windowName) ) Variable type= WinType(windowName) switch (type) case 1: // graph case 3: // layout TextBox/W=$windowName "\\$PICT$name="+pictName+"$/PICT$" LaTeXtUpdatePICTWindowList() break default: Beep endswitch else Beep endif End Function LaTeXNewDrawPICTButtonProc(ctrlName) : ButtonControl String ctrlName ControlInfo/W=$ksPanelName LaTeXPictures String pictName= S_Value String windowName= LaTeXTargetWindow() if( (!LaTeXIsNew(pictName)) && strlen(pictName) && strlen(windowName) ) Variable type= WinType(windowName) switch (type) case 1: // graph case 3: // layout case 7: // Panel SetDrawEnv/W=$windowName xcoord=rel, ycoord=rel DrawPICT/W=$windowName 0.1,0.1,1,1, $pictName LaTeXtUpdatePICTWindowList() break default: Beep endswitch else Beep endif End Function LaTeXPicturesButtonProc(ctrlName) : ButtonControl String ctrlName DoIgorMenu "Misc","Pictures" End Function LaTeXDeleteButtonProc(ctrlName) : ButtonControl String ctrlName ControlInfo/W=$ksPanelName LaTeXPictures String pictName= S_Value Variable isNew= LaTeXIsNew(pictName) if( isNew ) Beep else KillPICTs/Z $pictName LaTeXUpdatePanelForActivate() endif End Function LaTeXExampleButtonProc(ctrlName) : ButtonControl String ctrlName String exampleText strswitch(ctrlName) case "example": exampleText= "x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}" break case "example2": exampleText = "\[ \left[ \begin{array}{ccc} \r" exampleText += "a & b & c \\\ \r" exampleText += "d & e & f \\\ \r" exampleText += "g & h & i \end{array} \\right]\]" break default: exampleText= "" break endswitch Notebook $ksNotebookName selection={startOfFile, endOfFile}, text=exampleText LaTeXEnableButtons() End Function LaTeXHelpButtonProc(ctrlName) : ButtonControl String ctrlName BrowseURL("http://rogercortesi.com/eqn/index.php") // Here are some other useful resources. // BrowseURL("ftp://ftp.ams.org/pub/tex/doc/amsmath/short-math-guide.pdf") //BrowseURL("http://www.artofproblemsolving.com/Wiki/index.php/LaTeX:Commands") End