Before I re-program what has probably been programmed a dozen times, does anyone have some source code for a simple text editor?
Anyone have a simple IDE template
BlitzMax Forums/BlitzMax Programming/Anyone have a simple IDE template Well, I came up with this. The undo/redo stuff was pretty tricky, but I think it is working correctly now:
Framework BRL.Win32MaxGUI Import brl.retro Extern "Win32" Function OpenClipboard%(hwnd%) Function CloseClipboard%() Function EmptyClipboard%() Function IsClipboardFormatAvailable%(format%) Function GetClipboardData:Byte Ptr(Format:Int) Function SetClipboardData(format%, hMem:Byte Ptr) Function GlobalAlloc(Flags:Int, Bytes:Int) Function GlobalFree(Mem:Int) Function GlobalLock:Byte Ptr(Mem:Int) Function GlobalUnlock(Mem:Int) End Extern Const CF_TEXT%=$1 Const CF_BITMAP%=2 Const GMEM_MOVEABLE%=$2 Const GMEM_DDESHARE%=$2000 AppTitle="Script Editor" AppVersion$="1.00" Global REQUESTFILEPATH$ Global MAINWINDOW:TGadget=CreateWindow("Script Editor",0,0,800,600,Null,WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_MENU|WINDOW_STATUS|WINDOW_HIDDEN|WINDOW_CENTER) Global MAINPANEL:TGadget=CreatePanel(0,0,MAINWINDOW.clientwidth(),MAINWINDOW.clientheight(),MAINWINDOW) MAINPANEL.setlayout 1,1,1,1 Global TEXTEDITOR:TGadget=CreateTextArea(0,0,MAINPANEL.clientwidth(),MAINPANEL.clientheight(),MAINPANEL) TEXTEDITOR.setlayout 1,1,1,1 TEXTEDITOR.setcolor 240,240,240 font:TGUIFont=LoadGuiFont("Courier New",10) If font SetGadgetFont TEXTEDITOR,font '================================================================= 'File '================================================================= Type TSourcefile Global list:TList=New TList Global current:TSourcefile Field link:TLink Field path$ Field changed=False Field gadget:TGadget Method New() link=list.addlast(Self) If Not current current=Self EndMethod Method kill() RemoveLink link link=Null path="" gadget=Null If current=Self current=Null EndMethod EndType sourcefile:TSourcefile=New TSourcefile sourcefile.gadget=TEXTEDITOR '================================================================= ' '================================================================= '================================================================= 'Undo '================================================================= Type TUndoContext Field gadget:TGadget Field undostates:TList=New TList Field current:TUndoState Method kill() gadget=Null undostates.clear() undostates=Null flush EndMethod Method Undo() If current If current.link.prevlink() undostate:TUndostate=TUndostate(current.link.prevlink().value()) If undostate undostate.restore EndIf EndIf EndMethod Method Redo() If current If current.link.nextlink() undostate:TUndostate=TUndostate(current.link.nextlink().value()) If undostate undostate.restore EndIf EndIf EndMethod Method Flush() For undostate:TUndostate=EachIn undostates undostate.kill() Next EndMethod Method CreateUndoState() undostate:TUndostate=New TUndostate If current undostate.link=undostates.insertafterlink(undostate,current.link) Else undostate.link=undostates.addlast(undostate) EndIf current=undostate undostate.clearafter If undostates.count()>200 RemoveLink undostates.firstlink() undostate.context=Self undostate.updatetext undostate.updateselection EndMethod Method UndoAvailable:Int() If undostates.count()>1 Return True EndMethod Method RedoAvailable:Int() If current If current.link.nextlink() Return True EndIf EndMethod EndType Function CreateUndoContext:TUndocontext(gadget:TGadget) undocontext:TUndoContext=New TUndoContext undocontext.gadget=gadget Return undocontext EndFunction Type TUndostate Field link:TLink Field context:TUndoContext Field text$ Field selectionposition:Int Field selectionlength:Int Method UpdateText() text=TextAreaText(context.gadget) EndMethod Method UpdateSelection() selectionposition=TextAreaCursor(context.gadget) selectionlength=TextAreaSelLen(context.gadget) EndMethod Method Restore() LockTextArea context.gadget context.gadget.settext text UnlockTextArea context.gadget SelectTextAreaText context.gadget,selectionposition,selectionlength context.current=Self EndMethod Method ClearAfter() Local sublink:TLink Local nextsublink:TLink sublink=link.nextlink() While sublink nextsublink=sublink.nextlink() TUndoState(sublink.value()).kill sublink=nextsublink Wend EndMethod Method Kill() If link.prevlink() context.current=TUndostate(link.prevlink().value()) Else context.current=Null EndIf context=Null RemoveLink link link=Null EndMethod EndType '================================================================= ' '================================================================= '================================================================= 'Menu '================================================================= root:TGadget=WindowMenu(MAINWINDOW) Const MENU_OPEN=1 Const MENU_EXIT=2 Const MENU_NEW=3 Const MENU_SAVE=4 Const MENU_SAVEAS=5 Const MENU_UNDO=6 Const MENU_REDO=7 Const MENU_CUT=8 Const MENU_COPY=9 Const MENU_PASTE=10 Const MENU_DELETE=11 Const MENU_SELECTALL=12 Const MENU_FIND=13 Const MENU_FINDNEXT=14 Const MENU_REPLACE=15 Const MENU_GOTO=16 Const MENU_RUN=17 Const MENU_DEBUG=18 Const MENU_BUILDEXE=19 Const MENU_HELP=20 Const MENU_ABOUT=21 Const MENU_CLOSE=22 menu:TGadget=CreateMenu("File",0,root) CreateMenu("New",MENU_NEW,menu) CreateMenu("",0,menu) CreateMenu("Open...",MENU_OPEN,menu,KEY_O,MODIFIER_COMMAND) CreateMenu("Save",MENU_SAVE,menu,KEY_S,MODIFIER_COMMAND) CreateMenu("Save As...",MENU_SAVEAS,menu) CreateMenu("",0,menu) CreateMenu("",0,menu) CreateMenu("Exit",MENU_EXIT,menu) menu:TGadget=CreateMenu("Edit",0,root) Global GADGET_MENU_UNDO:TGadget=CreateMenu("Undo",MENU_UNDO,menu,KEY_Z,MODIFIER_COMMAND) Global GADGET_MENU_REDO:TGadget=CreateMenu("Redo",MENU_REDO,menu,KEY_Z,MODIFIER_COMMAND|MODIFIER_OPTION) DisableGadget GADGET_MENU_UNDO DisableGadget GADGET_MENU_REDO CreateMenu("",0,menu) CreateMenu("Cut",MENU_CUT,menu,KEY_X,MODIFIER_COMMAND) CreateMenu("Copy",MENU_COPY,menu,KEY_C,MODIFIER_COMMAND) CreateMenu("Paste",MENU_PASTE,menu,KEY_V,MODIFIER_COMMAND) CreateMenu("Delete",MENU_DELETE,menu,KEY_DELETE) CreateMenu("",0,menu) CreateMenu("Select All",MENU_SELECTALL,menu) CreateMenu("",0,menu) CreateMenu("Find...",MENU_FIND,menu) CreateMenu("Find Next",MENU_FINDNEXT,menu) CreateMenu("Replace...",MENU_REPLACE,menu) CreateMenu("Go To...",MENU_GOTO,menu) menu:TGadget=CreateMenu("Compile",0,root) CreateMenu("Run...",MENU_RUN,menu,KEY_F5) CreateMenu("Debug...",MENU_DEBUG,menu,KEY_F6) CreateMenu("Build EXE...",MENU_BUILDEXE,menu,KEY_F7) menu:TGadget=CreateMenu("Help",0,root,KEY_F1) CreateMenu("User Guide...",MENU_HELP,menu) CreateMenu("About",MENU_ABOUT,menu) MAINWINDOW.updatemenu() '================================================================= ' '================================================================= Global undocontext:TUndocontext=CreateUndoContext(TEXTEDITOR) undocontext.createundostate '================================================================= 'About window '================================================================= w=284 h=192 Global ABOUTWINDOW:Tgadget=CreateWindow("About",0,0,w,h,group,WINDOW_TITLEBAR|WINDOW_HIDDEN|WINDOW_DIALOG|WINDOW_CENTER) x=8 y=4 panel:TGadget=CreatePanel(x,y,ABOUTWINDOW.clientwidth()-2*x,ABOUTWINDOW.clientheight()-y-8-23-8,ABOUTWINDOW,PANEL_GROUP) CreateLabel(AppTitle+" "+AppVersion+Chr(13)+Chr(10)+"Leadwerks Corporation 2007"+Chr(13)+Chr(10)+"All Rights Reserved.",0,panel.clientheight()/2-24,panel.clientwidth(),panel.clientheight(),panel,LABEL_CENTER) w=80 h=23 CreateButton("OK",(ABOUTWINDOW.clientwidth()-w)/2,ABOUTWINDOW.clientheight()-h-8,w,h,ABOUTWINDOW) '================================================================= ' '================================================================= UpdateStatusbar() ShowGadget MAINWINDOW ActivateGadget TEXTEDITOR '================================================================= 'Main Loop '================================================================= Repeat WaitEvent() EvaluateEvent(EventID(),EventSource(),EventData()) Forever '================================================================= ' '================================================================= '================================================================= 'Event Handling '================================================================= Function EvaluateEvent:Int(id,source:Object=Null,data:Int=0) Select id Case EVENT_WINDOWCLOSE End Case EVENT_GADGETSELECT Select source Case TEXTEDITOR If undocontext.current If TextAreaText(undocontext.gadget)=undocontext.current.text undocontext.current.updateselection EndIf EndIf UpdateStatusbar() EndSelect Case EVENT_GADGETACTION Select source Case TEXTEDITOR undocontext.createundostate EnableGadget GADGET_MENU_UNDO MAINWINDOW.updatemenu TSourcefile.current.changed=True EndSelect Case EVENT_MENUACTION Select data Case MENU_SELECTALL SelectTextAreaText TEXTEDITOR Case MENU_CUT If TextAreaSelLen(TEXTEDITOR) If Not SetClipboardText(TextAreaSelection(TEXTEDITOR)) Notify "Failed to write text to clipboard." EndIf RemoveTextAreaSelection(TEXTEDITOR) undocontext.createundostate EnableGadget GADGET_MENU_UNDO MAINWINDOW.updatemenu EndIf Case MENU_COPY If TextAreaSelLen(TEXTEDITOR) SetClipboardText TextAreaSelection(TEXTEDITOR) EndIf Case MENU_PASTE text$=ClipboardText() If text<>"" RemoveTextAreaSelection TEXTEDITOR InsertTextAreaText TEXTEDITOR,text undocontext.createundostate EnableGadget GADGET_MENU_UNDO MAINWINDOW.updatemenu EndIf Case MENU_DELETE If TextAreaSelLen(TEXTEDITOR) RemoveTextAreaSelection(TEXTEDITOR) undocontext.createundostate EnableGadget GADGET_MENU_UNDO MAINWINDOW.updatemenu EndIf Case MENU_UNDO undocontext.undo If undocontext.undoavailable() EnableGadget GADGET_MENU_UNDO Else DisableGadget GADGET_MENU_UNDO EndIf If undocontext.redoavailable() EnableGadget GADGET_MENU_REDO Else DisableGadget GADGET_MENU_REDO EndIf MAINWINDOW.updatemenu Case MENU_REDO undocontext.redo If undocontext.undoavailable() EnableGadget GADGET_MENU_UNDO Else DisableGadget GADGET_MENU_UNDO EndIf If undocontext.redoavailable() EnableGadget GADGET_MENU_REDO Else DisableGadget GADGET_MENU_REDO EndIf MAINWINDOW.updatemenu Case MENU_ABOUT ShowGadget ABOUTWINDOW DisableGadget MAINWINDOW Repeat Select WaitEvent() Case EVENT_WINDOWCLOSE Exit Case EVENT_GADGETACTION Exit EndSelect Forever EnableGadget MAINWINDOW HideGadget ABOUTWINDOW Case MENU_NEW If Not EvaluateEvent(EVENT_MENUACTION,Null,MENU_CLOSE) Return False TEXTEDITOR.settext "" undocontext.flush() undocontext.createundostate DisableGadget GADGET_MENU_UNDO DisableGadget GADGET_MENU_REDO MAINWINDOW.updatemenu TSourcefile.current=New TSourcefile TSourcefile.current.gadget=TEXTEDITOR UpdateStatusbar Case MENU_EXIT If Not EvaluateEvent(EVENT_MENUACTION,Null,MENU_CLOSE) Return End Case MENU_CLOSE If TSourceFile.current If TSourceFile.current.changed Select Proceed("Save changes to "+Chr(34)+TSourceFile.current.path+Chr(34)+"?") Case 1'Yes If Not EvaluateEvent(EVENT_MENUACTION,Null,MENU_SAVE) Return False Case -1'Cancel Return False Case 0' No EndSelect EndIf TSourceFile.current.kill() EndIf Return True Case MENU_SAVEAS If TSourcefile.current file$=RequestFile("Save As","Script File (*.script):script;Text Documents (*.txt):txt;All Files:*",True,REQUESTFILEPATH) If file<>"" stream:TStream=WriteFile(file) If stream REQUESTFILEPATH=ExtractDir(file)+"" For n=0 To TextAreaLen(TSourcefile.current.gadget,TEXTAREA_LINES)-1 s$=TextAreaText(TSourcefile.current.gadget,n,1,TEXTAREA_LINES) stream.writeline Left(s,s.length-1) Next stream.close TSourcefile.current.changed=False TSourcefile.current.path=file Return True Else Notify "Failed to write file "+Chr(34)+file+Chr(34)+"." Return False EndIf EndIf EndIf Case MENU_SAVE If TSourcefile.current If TSourcefile.current.path="" Return EvaluateEvent(EVENT_MENUACTION,Null,MENU_SAVEAS) Else stream:TStream=WriteFile(TSourcefile.current.path) If stream For n=0 To TextAreaLen(TSourcefile.current.gadget,TEXTAREA_LINES)-1 s$=TextAreaText(TSourcefile.current.gadget,n,1,TEXTAREA_LINES) stream.writeline Left(s,s.length-1) Next stream.close TSourcefile.current.changed=False Return True Else Notify "Failed to write file "+Chr(34)+file+Chr(34)+"." Return False EndIf EndIf EndIf Case MENU_OPEN If Not EvaluateEvent(EVENT_MENUACTION,Null,MENU_CLOSE) Return False file$=RequestFile("Open","Script File (*.script):script;Text Documents (*.txt):txt;All Files:*",0,REQUESTFILEPATH) If file<>"" stream:TStream=ReadFile(file) If stream REQUESTFILEPATH=ExtractDir(file)+"" LockTextArea TEXTEDITOR SetTextAreaText TEXTEDITOR,"" While Not stream.eof() AddTextAreaText TEXTEDITOR,stream.readline()+Chr(13)+Chr(10) Wend UnlockTextArea TEXTEDITOR SelectTextAreaText TEXTEDITOR,0,0 stream.close() stream=Null undocontext.flush() undocontext.createundostate DisableGadget GADGET_MENU_UNDO DisableGadget GADGET_MENU_REDO MAINWINDOW.updatemenu TSourcefile.current=New TSourcefile TSourcefile.current.path=file TSourcefile.current.gadget=TEXTEDITOR UpdateStatusbar Else Notify "Failed to load file "+Chr(34)+file+Chr(34)+"." EndIf EndIf EndSelect EndSelect EndFunction '================================================================= ' '================================================================= Function ClearAfterLink(link:TLink) Local sublink:TLink Local nextsublink:TLink sublink=link.nextlink() While sublink nextsublink=sublink.nextlink() RemoveLink sublink sublink=nextsublink Wend EndFunction Function RemoveTextAreaSelection(textarea:TGadget) p=TextAreaCursor(textarea) l=TextAreaSelLen(textarea) If l=0 Return firstpart$=TextAreaText(textarea,0,p) lastpart$=TextAreaText(textarea,p+l,TextAreaLen(textarea)-p-l) SetTextAreaText textarea,firstpart+lastpart SelectTextAreaText textarea,p,0 EndFunction Function TextAreaSelection$(textarea:TGadget) Return TextAreaText(textarea,TextAreaCursor(textarea),TextAreaSelLen(textarea)) EndFunction Function InsertTextAreaText(textarea:TGadget,text$,pos=-1) If pos=-1 pos=TextAreaCursor(textarea) firstpart$=TextAreaText(textarea,0,pos) lastpart$=TextAreaText(textarea,pos,TextAreaLen(textarea)-pos) LockTextArea textarea SetTextAreaText textarea,firstpart+text+lastpart UnlockTextArea textarea SelectTextAreaText textarea,pos+Len(text),0 EndFunction Function ClipboardText$() Local htext:Byte Ptr Local text$ If OpenClipboard(0) htext=GetClipboardData(CF_TEXT) text$=String.fromcstring(htext) CloseClipboard() MemFree htext EndIf Return text EndFunction Function SetClipboardText:Int(text$) Local result:Int=False If text="" Return Local htext:Byte Ptr=text.ToCString() Local Memblock:Int=GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, text.length+1) Local DataBuf:Byte Ptr=GlobalLock(Memblock) MemCopy DataBuf, htext, text.length If OpenClipboard(0) EmptyClipboard SetClipboardData CF_TEXT, DataBuf CloseClipboard result=True EndIf MemFree htext GlobalUnlock Memblock GlobalFree Memblock Return result End Function Function UpdateStatusbar() SetStatusText MAINWINDOW,"Line "+TextAreaCursor(TEXTEDITOR,TEXTAREA_LINES) EndFunction
I just wanted to say good job so far..
and in just over two hours?! wow.. :)
and in just over two hours?! wow.. :)
I edited it so everything works around an "UndoContext" type. This way you can have multiple undo systems running for different text areas. I've tested it quite a bit now, and it works really nicely.
@Leadwerks: Can I add your code template to BLIde? Next BLIde version will have code templates functionality. I will put you as the author of the template. If you have any problem with that, let me know it, and I'll remove your template from the BLIde set up.