(* Copyright 2021 Anton Krotov This file is part of CEdit. CEdit 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 3 of the License, or (at your option) any later version. CEdit 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 CEdit. If not, see . *) MODULE CEdit; IMPORT OpenDlg, K := KolibriOS, U := Utils, Lines, Menu, List, G := Graph, T := Text, E := Encodings, CB := Clipboard, Languages, ChangeLog, Scroll, CheckBox, RW, Ini, box_lib, Icons, Tabs, Timer; CONST header = "CEdit (08-sep-2021)"; ShellFilter = ""; EditFilter = "SH|ASM|TXT|INC|OB07|C|CPP|H|PAS|PP|LUA|INI|JSON"; fontWidth = K.fontWidth; fontHeight = K.fontHeight; scrollWidth = 22; btnClose = 1; btnNew = 20; btnOpen = 21; btnSave = 22; btnSearch = 23; btnUndo = 24; btnRedo = 25; btnUpper = 26; btnLower = 27; btnBuild = 28; btnRun = 29; btnYes = 40; btnNo = 41; btnFindNext = 60; btnReplace = 61; btnReplaceAll = 62; btnGoto = 63; btnCloseFind = 64; btnHideFind = 65; btnFile = 70; btnEdit = 71; btnMenuSearch = 72; btnEncoding = 73; btnEOL = 74; btnView = 75; btnSyntax = 76; btnProgram = 77; btnTools = 78; MainMenuHeight = fontHeight + 7; btnHeight = 25; btnWidth = 75; btnTop = MainMenuHeight + 3; toolBtnSize = 24; toolbarDelim = 7; iconPad = (toolBtnSize - Icons.SIZE) DIV 2; TOP = btnTop + toolBtnSize + 10 + Tabs.tabHeight; RIGHT = scrollWidth - 2; BOTTOM = scrollWidth + 18; minWinWidth = 635; minWinHeight = 550; SEARCH_PADDING = 10; searchLeft = 0; EditBox_Width = 180; EDITBOX_MAXCHARS = 500; menuFileX = searchLeft; menuEditX = menuFileX + 4*fontWidth + 2 + 7; menuSearchX = menuEditX + 4*fontWidth + 2 + 7; menuEncodingX = menuSearchX + 6*fontWidth + 2 + 7; menuEOLX = menuEncodingX + 8*fontWidth + 2 + 7; menuViewX = menuEOLX + 3*fontWidth + 2 + 7; menuSyntaxX = menuViewX + 4*fontWidth + 2 + 7; menuProgramX = menuSyntaxX + 6*fontWidth + 2 + 7; menuToolsX = menuProgramX + 7*fontWidth + 2 + 7; menuCut = 1; menuCopy = 2; menuPaste = 3; menuDelete = 4; menuSelectAll = 5; menuUndo = 6; menuRedo = 7; menuCurLine = 100; menuIndent = 110; menuCase = 120; menuNew = 10; menuOpen = 11; menuSave = 12; menuSaveAs = 13; menuSaveAll = 14; menuFolder = 15; menuClose = 16; menuExit = 17; menuNumbers = 20; menuFontSize = 21; menuColors = 1000; menuMaxColors = menuColors + Ini.MAX_SECTIONS - 1; menuNone = 30; menuC = 31; menuFasm = 32; menuIni = 33; menuJSON = 34; menuLua = 35; menuOberon = 36; menuPascal = 37; menuBuild = 50; menuBuildScript = 51; menuRun = 52; menuRunScript = 53; menuDebug = 54; menuDebugScript = 55; menuUTF8BOM = 60; menuUTF8 = 61; menuCP866 = 62; menuWin1251 = 63; menuPipet = 70; menuBoard = 71; menuSysFunc = 72; menuFind = 80; menuFindNext = 81; menuFindPrev = 82; menuGoto = 83; menuBookmark = 130; menuMoveUp = 101; menuMoveDown = 102; menuDuplicate = 103; menuRemove = 104; menuIncInd = 111; menuDecInd = 112; menuUpper = 121; menuLower = 122; menuToggleBookmark = 131; menuNextBookmark = 132; menuPrevBookmark = 133; menuLF = 140; menuCRLF = 141; menuCR = 142; maxTexts = 32; scrollDelay = 40; VAR canvas: G.tCanvas; font, font1, font2: G.tFont; tabs: Tabs.tTabs; text: T.tText; texts: ARRAY maxTexts OF T.tText; textsCount, curText: INTEGER; winWidth, winHeight: INTEGER; AppPath, runScript, buildScript, debugScript: RW.tFileName; OD: OpenDlg.Dialog; confirm, notFound, menuFindClicked, search, searchOpened, modified: BOOLEAN; switch, closing: BOOLEAN; leftButton: BOOLEAN; hScroll, vScroll: Scroll.tScroll; LEFT: INTEGER; FindEdit, ReplaceEdit, GotoEdit: box_lib.edit_box; CS, WH, BKW: CheckBox.tCheckBox; new_searchText, searchText, replaceText, gotoText: T.tString; cs, whole: BOOLEAN; replaced: INTEGER; mainTID, delay: INTEGER; context, menuFile, menuEdit, menuSearch, menuEncoding, menuEOL, menuView, menuSyntax, menuProgram, menuTools, subCurLine, subIndent, subCase, subBookmark: Menu.tMenu; menuActive: BOOLEAN; icons: INTEGER; grayIcons: INTEGER; IPC: ARRAY 64 OF INTEGER; PROCEDURE WritePos (y: INTEGER); VAR s1, s2: ARRAY 32 OF WCHAR; line, col: INTEGER; BEGIN T.getPos(text, col, line); U.int2str(line, s1); U.int2str(col, s2); U.append(s1, ": "); U.append(s1, s2); K.DrawText(LEFT, y, K.textColor, s1) END WritePos; PROCEDURE EditBox_Focus (edit: box_lib.edit_box): BOOLEAN; VAR res: BOOLEAN; BEGIN res := FALSE; IF edit # NIL THEN res := 1 IN BITS(edit.flags) END RETURN res END EditBox_Focus; PROCEDURE resetTimer; BEGIN IF EditBox_Focus(FindEdit) OR EditBox_Focus(ReplaceEdit) OR EditBox_Focus(GotoEdit) THEN T.hideCursor; Timer.kill ELSE T.showCursor; Timer.create(mainTID) END END resetTimer; PROCEDURE EditBox_SetFocus (edit: box_lib.edit_box; value: BOOLEAN); BEGIN IF value THEN edit.flags := ORD(BITS(edit.flags) + {1}) ELSE edit.flags := ORD(BITS(edit.flags) - {1}) END; IF search & searchOpened THEN box_lib.edit_box_draw(edit) END END EditBox_SetFocus; PROCEDURE SetFocus (edit: box_lib.edit_box; value: BOOLEAN); BEGIN EditBox_SetFocus(FindEdit, FALSE); EditBox_SetFocus(ReplaceEdit, FALSE); EditBox_SetFocus(GotoEdit, FALSE); EditBox_SetFocus(edit, value); resetTimer END SetFocus; PROCEDURE Rect (left, top, right, bottom, color: INTEGER); BEGIN K.DrawLine(left, top, right, top, color); K.DrawLine(left, bottom, right, bottom, color); K.DrawLine(left, top, left, bottom, color); K.DrawLine(right, top, right, bottom, color); END Rect; PROCEDURE Message (s: ARRAY OF WCHAR); CONST minWidth = 30; height = 40; borderColor = 808080H; VAR top, left, right, bottom, x, y, width: INTEGER; BEGIN Timer.kill; width := minWidth + LENGTH(s)*fontWidth; left := (canvas.width - width) DIV 2 + LEFT; top := (canvas.height - height) DIV 2 + TOP; bottom := top + height - 1; right := left + width - 1; x := minWidth DIV 2 + left; y := (height - fontHeight) DIV 2 + top; K.DrawRect(left, top, width, height, K.winColor); Rect(left, top, right, bottom, borderColor); K.DrawText(x, y, K.textColor, s); END Message; PROCEDURE NotFound; BEGIN IF notFound THEN Message("not found"); IF menuFindClicked THEN menuFindClicked := FALSE ELSE notFound := FALSE END; SetFocus(FindEdit, TRUE) END END NotFound; PROCEDURE Replaced; VAR s, s1: ARRAY 32 OF WCHAR; BEGIN IF replaced # 0 THEN s := "replaced: "; U.int2str(replaced, s1); U.append(s, s1); Message(s); replaced := 0; SetFocus(FindEdit, TRUE) END END Replaced; PROCEDURE drawIcon (icons, idx, x: INTEGER); BEGIN Icons.draw(icons, idx, x + iconPad, btnTop + iconPad) END drawIcon; PROCEDURE toolbarIcons; VAR x, color, ico: INTEGER; BEGIN x := searchLeft + (toolBtnSize + 5)*2; IF text.modified THEN ico := icons ELSE ico := grayIcons END; drawIcon(ico, 5, x); IF text.edition # NIL THEN x := searchLeft + (toolBtnSize + 5)*4 + toolbarDelim*2; IF ChangeLog.isFirstGuard(text.edition) THEN ico := grayIcons ELSE ico := icons END; drawIcon(ico, 37, x); x := searchLeft + (toolBtnSize + 5)*5 + toolbarDelim*2; IF ChangeLog.isLastGuard(text.edition) THEN ico := grayIcons ELSE ico := icons END; drawIcon(ico, 36, x) END; IF T.selected(text) THEN color := K.caseColor ELSE color := K.disCaseColor END; x := searchLeft + (toolBtnSize + 5)*6 + toolbarDelim*3; K.DrawRect(x, btnTop, toolBtnSize, toolBtnSize, K.toolbarColor); K.DrawText69(x + (toolBtnSize - 12) DIV 2, btnTop + (toolBtnSize - 9) DIV 2 + 2, color, "AB"); INC(x, toolBtnSize + 5); K.DrawRect(x, btnTop, toolBtnSize, toolBtnSize, K.toolbarColor); K.DrawText69(x + (toolBtnSize - 12) DIV 2, btnTop + (toolBtnSize - 9) DIV 2 + 2, color, "ab"); x := searchLeft + (toolBtnSize + 5)*8 + toolbarDelim*4; IF buildScript # "" THEN ico := icons ELSE ico := grayIcons END; drawIcon(ico, 54, x); INC(x, toolBtnSize + 5); IF runScript # "" THEN ico := icons ELSE ico := grayIcons END; drawIcon(ico, 53, x) END toolbarIcons; PROCEDURE WriteModified (x, y: INTEGER); BEGIN modified := text.modified; K.DrawRect(x, TOP + canvas.height + scrollWidth, 8*fontWidth, BOTTOM - scrollWidth + 1, K.winColor); IF modified THEN K.DrawText866(x, y, K.textColor, "modified") END END WriteModified; PROCEDURE DrawState (text: T.tText; width, height: INTEGER); VAR y, w, x: INTEGER; BEGIN y := (btnHeight - fontHeight) DIV 2 + btnTop; K.DrawRect(width - 32*fontWidth, y, 32*fontWidth, fontHeight, K.winColor); w := LENGTH(E.names[text.enc])*fontWidth; x := width - w; K.DrawText(x, y, K.textColor, E.names[text.enc]); w := LENGTH(RW.eolNames[text.eol])*fontWidth; DEC(x, w + 10); K.DrawText(x, y, K.textColor, RW.eolNames[text.eol]); y := height - (BOTTOM - scrollWidth) + (BOTTOM - scrollWidth - 16) DIV 2; K.DrawRect(LEFT + 16*fontWidth, TOP + canvas.height + scrollWidth, width - LEFT - 24*fontWidth, BOTTOM - scrollWidth + 1, K.winColor); K.DrawText866(LEFT + 16*fontWidth, y, K.textColor, text.fileName); WriteModified(width - 8*fontWidth, y) END DrawState; PROCEDURE DrawScroll (VAR scroll: Scroll.tScroll; left, top, value, maxVal: INTEGER); BEGIN scroll.maxVal := maxVal; scroll.left := left; scroll.top := top; Scroll.setValue(scroll, value); Scroll.paint(scroll) END DrawScroll; PROCEDURE repaint; VAR width, height, scrollX, scrollY, y: INTEGER; BEGIN IF text # NIL THEN IF confirm THEN K.DeleteButton(btnYes); K.DeleteButton(btnNo); confirm := FALSE; resetTimer; closing := FALSE END; IF ~search OR (searchText = "") THEN T.wordSel(text) END; K.ClientSize(width, height); IF switch THEN DrawState(text, width, height); Tabs.draw(tabs); IF search & T.search(text, searchText, cs, whole) THEN END; switch := FALSE END; T.draw(text); y := height - (BOTTOM - scrollWidth) + (BOTTOM - scrollWidth - 16) DIV 2; K.DrawRect(LEFT, TOP + canvas.height + scrollWidth, 16*fontWidth, BOTTOM - scrollWidth + 1, K.winColor); WritePos(y); IF modified # text.modified THEN WriteModified(width - 8*fontWidth, y) END; T.getScroll(text, scrollX, scrollY); DrawScroll(vScroll, LEFT + canvas.width, TOP - 1, scrollY, text.count - 1); DrawScroll(hScroll, LEFT, TOP + canvas.height, scrollX, text.maxLength); IF search & searchOpened THEN CheckBox.paint(BKW); CheckBox.paint(CS); CheckBox.paint(WH); END; G.DrawCanvas(canvas, LEFT, TOP); NotFound; Replaced; toolbarIcons END END repaint; PROCEDURE resize; VAR cliWidth, cliHeight: INTEGER; BEGIN K.WinSize(winWidth, winHeight); IF winWidth < minWinWidth THEN winWidth := minWinWidth END; IF winHeight < minWinHeight THEN winHeight := minWinHeight END; K.SetWinSize(winWidth, winHeight); K.WinSize(winWidth, winHeight); K.ClientSize(cliWidth, cliHeight); G.destroy(canvas); canvas := G.CreateCanvas(cliWidth - (LEFT + RIGHT + 2), cliHeight - (TOP + BOTTOM + 1)); Tabs.setArea(tabs, LEFT, TOP - Tabs.tabHeight, cliWidth - (LEFT + RIGHT + 2), Tabs.tabHeight); G.SetFont(canvas, font); T.setCanvas(canvas); T.resize(canvas.width, canvas.height); Scroll.resize(vScroll, vScroll.width, canvas.height + 2); Scroll.resize(hScroll, canvas.width + 1, hScroll.height); END resize; PROCEDURE SearchPanel (left, top: INTEGER); VAR y, right, bottom, color: INTEGER; BEGIN DEC(top, Tabs.tabHeight); right := left + EditBox_Width + SEARCH_PADDING*2; bottom := top + 395 + btnHeight + SEARCH_PADDING; color := K.borderColor; Rect(left, top, right, bottom, color); K.CreateButton(btnCloseFind, right - 20, top, 20, 20, 0EF999FH, ""); K.DrawLine(right - 14, top + 5, right - 5, top + 14, 0FFFFFFH); K.DrawLine(right - 15, top + 5, right - 5, top + 15, 0FFFFFFH); K.DrawLine(right - 15, top + 6, right - 6, top + 15, 0FFFFFFH); K.DrawLine(right - 15, top + 14, right - 6, top + 5, 0FFFFFFH); K.DrawLine(right - 15, top + 15, right - 5, top + 5, 0FFFFFFH); K.DrawLine(right - 14, top + 15, right - 5, top + 6, 0FFFFFFH); K.CreateButton(btnHideFind, right - 40, top, 20, 20, K.btnColor, ""); K.DrawLine(right - 34, top + 14, right - 26, top + 14, K.btnTextColor); K.DrawLine(right - 34, top + 15, right - 26, top + 15, K.btnTextColor); INC(top, 15); INC(left, SEARCH_PADDING); K.DrawText866(left, top, K.textColor, "find"); K.DrawText866(left, top + 55, K.textColor, "replace with"); K.DrawText866(left, top + 330, K.textColor, "go to line"); BKW.top := top + 110; BKW.left := left; CS.top := top + 140; CS.left := left; WH.top := top + 170; WH.left := left; FindEdit.top := top + 20; ReplaceEdit.top := top + 75; GotoEdit.top := top + 350; FindEdit.left := left; ReplaceEdit.left := left; GotoEdit.left := left; box_lib.edit_box_draw(FindEdit); box_lib.edit_box_draw(ReplaceEdit); box_lib.edit_box_draw(GotoEdit); y := top + 200; K.CreateButton(btnFindNext, left, y, btnWidth, btnHeight, K.btnColor, "next"); INC(y, btnHeight + 10); K.CreateButton(btnReplace, left, y, btnWidth, btnHeight, K.btnColor, "replace"); INC(y, btnHeight + 10); K.CreateButton(btnReplaceAll, left, y, btnWidth + 5*fontWidth - 2, btnHeight, K.btnColor, "replace all"); K.CreateButton(btnGoto, left, top + 380, btnWidth, btnHeight, K.btnColor, "go"); END SearchPanel; PROCEDURE draw_window; VAR width, height, x: INTEGER; PROCEDURE drawToolbarBtn (id, x: INTEGER); BEGIN K.DrawRect(x, btnTop, toolBtnSize, toolBtnSize, K.toolbarColor); K.DrawLine(x, btnTop + toolBtnSize, x + toolBtnSize, btnTop + toolBtnSize, K.shadowColor); K.DrawLine(x + toolBtnSize, btnTop, x + toolBtnSize, btnTop + toolBtnSize, K.shadowColor); K.CreateButton(id + ORD({30}), x, btnTop, toolBtnSize, toolBtnSize, K.btnColor, ""); END drawToolbarBtn; PROCEDURE drawMainMenu (menu: Menu.tMenu; x: INTEGER; btn: INTEGER; caption: ARRAY OF WCHAR); VAR menuColor, textColor, n: INTEGER; BEGIN IF menu.tid # 0 THEN menuColor := K.textColor; textColor := K.winColor ELSE menuColor := K.winColor; textColor := K.textColor END; n := LENGTH(caption); K.DrawRect(x, 0, n*fontWidth + 2, MainMenuHeight, menuColor); K.CreateButton(btn + ORD({30}), x, 0, n*fontWidth + 2, MainMenuHeight, K.btnColor, ""); K.DrawText(x + 1, (MainMenuHeight - fontHeight) DIV 2 + 1, textColor, caption) END drawMainMenu; BEGIN K.BeginDraw; K.CreateWindow(30 + K.GetTickCount() MOD 128, 30 + K.GetTickCount() MOD 128, winWidth, winHeight, K.winColor, 73H, 0, 0, header); IF (text # NIL) & ~K.RolledUp() THEN IF confirm THEN resetTimer END; confirm := FALSE; K.ClientSize(width, height); K.DrawRect(0, 0, width, TOP, K.winColor); K.DrawRect(0, 0, LEFT, height, K.winColor); K.DrawRect(LEFT + canvas.width + 1, TOP + canvas.height, scrollWidth - 1, scrollWidth, K.winColor); drawMainMenu(menuFile, menuFileX, btnFile, "file"); drawMainMenu(menuEdit, menuEditX, btnEdit, "edit"); drawMainMenu(menuSearch, menuSearchX, btnMenuSearch, "search"); drawMainMenu(menuEncoding, menuEncodingX, btnEncoding, "encoding"); drawMainMenu(menuEOL, menuEOLX, btnEOL, "eol"); drawMainMenu(menuView, menuViewX, btnView, "view"); drawMainMenu(menuSyntax, menuSyntaxX, btnSyntax, "syntax"); drawMainMenu(menuProgram, menuProgramX, btnProgram, "program"); drawMainMenu(menuTools, menuToolsX, btnTools, "tools"); x := searchLeft; drawToolbarBtn(btnNew, x); drawIcon(icons, 2, x); INC(x, toolBtnSize + 5); drawToolbarBtn(btnOpen, x); drawIcon(icons, 0, x); INC(x, toolBtnSize + 5); drawToolbarBtn(btnSave, x); INC(x, toolBtnSize + 5 + toolbarDelim); drawToolbarBtn(btnSearch, x); drawIcon(icons, 49, x); INC(x, toolBtnSize + 5 + toolbarDelim); drawToolbarBtn(btnUndo, x); INC(x, toolBtnSize + 5); drawToolbarBtn(btnRedo, x); INC(x, toolBtnSize + 5 + toolbarDelim); drawToolbarBtn(btnUpper, x); INC(x, toolBtnSize + 5); drawToolbarBtn(btnLower, x); INC(x, toolBtnSize + 5 + toolbarDelim); drawToolbarBtn(btnBuild, x); INC(x, toolBtnSize + 5); drawToolbarBtn(btnRun, x); INC(x, toolBtnSize + 5); toolbarIcons; DrawState(text, width, height); IF search & searchOpened THEN SearchPanel(searchLeft, TOP) END; Tabs.draw(tabs); repaint END; K.EndDraw END draw_window; PROCEDURE mouse (VAR x, y: INTEGER); VAR mouseX, mouseY, cliX, cliY, winX, winY: INTEGER; BEGIN K.MousePos(mouseX, mouseY); K.WinPos(winX, winY); K.ClientPos(cliX, cliY); x := mouseX - winX - cliX - LEFT; y := mouseY - winY - cliY - TOP; END mouse; PROCEDURE getKBState (VAR shift, ctrl: BOOLEAN); VAR kbState: SET; BEGIN kbState := K.GetControlKeys(); shift := {0, 1} * kbState # {}; ctrl := {2, 3} * kbState # {}; END getKBState; PROCEDURE stopTimer; BEGIN T.hideCursor; Timer.kill; repaint END stopTimer; PROCEDURE OpenFile (VAR FileName: RW.tFileName; filter: ARRAY OF CHAR); BEGIN stopTimer; OpenDlg.SetFilter(OD, filter); OpenDlg.Show(OD, 500, 400); WHILE OD.status = 2 DO K.Pause(30) END; IF OD.status = 1 THEN COPY(OD.FilePath, FileName) ELSE FileName := "" END; resetTimer END OpenFile; PROCEDURE error (s: RW.tFileName); BEGIN K.Run("/rd/1/@notify", s) END error; PROCEDURE saveError (name: RW.tFileName); VAR s: RW.tFileName; BEGIN s := "'cedit: error saving file "; U.append8(s, name); U.append8(s, "' -E"); error(s) END saveError; PROCEDURE saveAs (text: T.tText); VAR fileName, name: RW.tFileName; ext: ARRAY 8 OF CHAR; BEGIN OD._type := OpenDlg.tsave; U.getFileName(text.fileName, OD.FileName, U.SLASH); IF OD.FileName = "" THEN OD.FileName := "NewFile."; CASE text.lang OF |Languages.langNone: ext := "txt" |Languages.langC: ext := "c" |Languages.langFasm: ext := "asm" |Languages.langIni: ext := "ini" |Languages.langJSON: ext := "json" |Languages.langLua: ext := "lua" |Languages.langOberon: ext := "ob07" |Languages.langPascal: ext := "pas" END; U.append8(OD.FileName, ext) END; OpenFile(fileName, EditFilter); IF fileName # "" THEN IF T.save(text, fileName) THEN T.setName(text, fileName); U.getFileName(fileName, name, U.SLASH); Tabs.rename(tabs, curText, name) ELSE saveError(fileName) END END END saveAs; PROCEDURE getIdx (text: T.tText): INTEGER; VAR i: INTEGER; BEGIN i := 0; WHILE texts[i] # text DO INC(i) END RETURN i END getIdx; PROCEDURE Switch (txt: T.tText); BEGIN Tabs.switch(tabs, curText); text := txt; T.switch(txt); switch := TRUE END Switch; PROCEDURE save (text: T.tText); BEGIN IF text.modified THEN IF text.fileName # "" THEN IF ~T.save(text, text.fileName) THEN saveError(text.fileName) END ELSE curText := getIdx(text); Switch(text); saveAs(text) END END END save; PROCEDURE saveAll; VAR i: INTEGER; BEGIN i := textsCount - 1; WHILE i >= 0 DO IF texts[i].modified THEN save(texts[i]) END; DEC(i) END; END saveAll; PROCEDURE insert (pos: INTEGER; txt: T.tText); VAR i: INTEGER; name: RW.tFileName; BEGIN FOR i := textsCount - 1 TO pos BY -1 DO texts[i + 1] := texts[i] END; texts[pos] := txt; INC(textsCount); curText := pos; IF txt.fileName = "" THEN name := "new" ELSE U.getFileName(txt.fileName, name, U.SLASH) END; Tabs.add(tabs, name); Switch(txt) END insert; PROCEDURE Confirm; CONST width = btnWidth*2 + 30; height = btnHeight*2 + 20; lineColor = 808080H; VAR left, top, right, bottom: INTEGER; BEGIN stopTimer; draw_window; confirm := TRUE; left := (canvas.width - width) DIV 2 + LEFT; top := (canvas.height - height) DIV 2 + TOP; right := left + width - 1; bottom := top + height - 1; K.DrawRect(left, top, width, height, K.winColor); Rect(left, top, right, bottom, lineColor); K.DrawText866(left + (width - 10*fontWidth) DIV 2, top + 10, K.textColor, "save file?"); K.CreateButton(btnYes, left + 10, top + 35, btnWidth, btnHeight, K.btnColor, "yes"); K.CreateButton(btnNo, left + 20 + btnWidth, top + 35, btnWidth, btnHeight, K.btnColor, "no"); END Confirm; PROCEDURE closeFile (conf: BOOLEAN; n: INTEGER); VAR i: INTEGER; BEGIN IF texts[n].modified & conf THEN Confirm ELSE Tabs.delete(tabs, n); FOR i := n + 1 TO textsCount - 1 DO texts[i - 1] := texts[i] END; DEC(textsCount); IF (curText = textsCount) OR (n < curText) THEN DEC(curText) END; IF curText >= 0 THEN Switch(texts[curText]) ELSE K.Exit END; draw_window END END closeFile; PROCEDURE NewFile; VAR nov: T.tText; BEGIN IF textsCount < maxTexts THEN nov := T.New(); T.SetPos(nov, 0, 0); insert(textsCount, nov) ELSE error("'cedit: too many files' -E") END END NewFile; PROCEDURE getFileNum (fileName: RW.tFileName): INTEGER; VAR i: INTEGER; PROCEDURE nameEq (name1, name2: RW.tFileName): BOOLEAN; VAR n1, n2: RW.tFileName; BEGIN n1 := name1; n2 := name2; U.upcase(n1); U.upcase(n2) RETURN n1 = n2 END nameEq; BEGIN i := 0; WHILE (i < textsCount) & ~nameEq(texts[i].fileName, fileName) DO INC(i) END; IF i = textsCount THEN i := -1 END RETURN i END getFileNum; PROCEDURE SwitchTab (n: INTEGER); BEGIN curText := n; Tabs.switch(tabs, n); Switch(texts[n]); resetTimer; draw_window END SwitchTab; PROCEDURE open; VAR fileName: RW.tFileName; nov: T.tText; err, n: INTEGER; BEGIN IF textsCount < maxTexts THEN OD._type := OpenDlg.topen; OpenFile(fileName, EditFilter); IF fileName # "" THEN n := getFileNum(fileName); IF n = -1 THEN nov := T.open(fileName, err); IF nov = NIL THEN error("'cedit: error opening file' -E") ELSE insert(textsCount, nov); T.SetPos(nov, 0, 0) END ELSE SwitchTab(n) END END ELSE error("'cedit: too many files' -E") END END open; PROCEDURE createEdit (left, top: INTEGER): box_lib.edit_box; VAR edit, EditBox0: box_lib.edit_box; BEGIN NEW(EditBox0); EditBox0.text := K.malloc(EDITBOX_MAXCHARS + 2); ASSERT(EditBox0.text # 0); edit := box_lib.kolibri_new_edit_box(left, top, EditBox_Width, EDITBOX_MAXCHARS, EditBox0); edit.flags := 4002H; edit.text_color := 30000000H; EditBox_SetFocus(edit, FALSE) RETURN edit END createEdit; PROCEDURE createSearchForm; BEGIN FindEdit := createEdit(searchLeft, TOP + 20); ReplaceEdit := createEdit(searchLeft, TOP + 20 + 55); GotoEdit := createEdit(searchLeft, TOP + 20 + 330); GotoEdit.flags := ORD(BITS(GotoEdit.flags) + BITS(8000H)); BKW := CheckBox.create("backward"); CS := CheckBox.create("match case"); WH := CheckBox.create("whole word"); END createSearchForm; PROCEDURE EditBox_GetValue (edit: box_lib.edit_box; VAR s: ARRAY OF WCHAR); VAR str: ARRAY EDITBOX_MAXCHARS + 1 OF CHAR; i: INTEGER; BEGIN box_lib.edit_box_get_value(edit, str); i := 0; WHILE str[i] # 0X DO s[i] := WCHR(E.cp866[ORD(str[i])]); INC(i) END; s[i] := 0X END EditBox_GetValue; PROCEDURE Search; BEGIN search := ~search; LEFT := searchLeft; IF search THEN searchOpened := TRUE; INC(LEFT, EditBox_Width + SEARCH_PADDING*2 + 5); IF T.search(text, searchText, cs, whole) THEN END ELSE IF T.search(text, "", FALSE, FALSE) THEN END END; SetFocus(FindEdit, search); resize; draw_window END Search; PROCEDURE click (x, y: INTEGER): INTEGER; VAR scrollX, scrollY: INTEGER; shift, ctrl: BOOLEAN; BEGIN getKBState(shift, ctrl); IF ~hScroll.mouse THEN Scroll.MouseDown(hScroll, x + LEFT, y + TOP); T.getScroll(text, scrollX, scrollY); T.scroll(text, hScroll.value - scrollX, 0); repaint END; IF ~vScroll.mouse THEN Scroll.MouseDown(vScroll, x + LEFT, y + TOP); T.getScroll(text, scrollX, scrollY); T.scroll(text, 0, vScroll.value - scrollY); repaint END; IF search & searchOpened THEN CheckBox.MouseDown(BKW, x + LEFT, y + TOP); CheckBox.MouseDown(CS, x + LEFT, y + TOP); CheckBox.MouseDown(WH, x + LEFT, y + TOP); END; IF (0 <= x) & (x < canvas.width) & (0 <= y) & (y < canvas.height) THEN leftButton := TRUE; SetFocus(FindEdit, FALSE); IF ~shift THEN T.resetSelect(text) END; T.mouse(text, x, y); repaint END RETURN K.GetTickCount() END click; PROCEDURE LeftButtonUp; BEGIN leftButton := FALSE; Scroll.MouseUp(hScroll); Scroll.MouseUp(vScroll); CheckBox.MouseUp(BKW); CheckBox.MouseUp(CS); CheckBox.MouseUp(WH); END LeftButtonUp; PROCEDURE Close; VAR cont: BOOLEAN; BEGIN closing := TRUE; cont := TRUE; WHILE (textsCount > 0) & cont DO IF text.modified THEN Confirm; cont := FALSE ELSE closeFile(FALSE, curText); repaint END END END Close; PROCEDURE CloseMenu; BEGIN Menu.close(menuFile); Menu.close(menuEdit); Menu.close(menuSearch); Menu.close(menuEncoding); Menu.close(menuEOL); Menu.close(menuView); Menu.close(menuSyntax); Menu.close(menuProgram); Menu.close(menuTools); Menu.close(subCurLine); Menu.close(subIndent); Menu.close(subCase); Menu.close(subBookmark); Menu.close(context); END CloseMenu; PROCEDURE MenuItemClick (menu: Menu.tMenu; id: INTEGER); BEGIN K.SendIPC(mainTID, id) END MenuItemClick; PROCEDURE goto; VAR gotoVal: INTEGER; BEGIN EditBox_GetValue(GotoEdit, gotoText); IF U.str2int(gotoText, gotoVal) & T.goto(text, gotoVal) THEN SetFocus(GotoEdit, FALSE) END END goto; PROCEDURE Script (script: ARRAY OF CHAR); BEGIN IF script # "" THEN K.Run("/rd/1/@open", script) END END Script; PROCEDURE ShowSearchPanel; BEGIN IF ~search THEN Search ELSIF ~searchOpened THEN search := FALSE; Search END END ShowSearchPanel; PROCEDURE CanvasToScreen (VAR x, y: INTEGER); VAR cliX, cliY, winX, winY: INTEGER; BEGIN K.WinPos(winX, winY); K.ClientPos(cliX, cliY); x := x + winX + cliX + LEFT; y := y + winY + cliY + TOP; END CanvasToScreen; PROCEDURE ShowMenu (menu: Menu.tMenu); VAR winX, winY, cliX, cliY, x, y, i: INTEGER; selected, enabled: BOOLEAN; BEGIN IF menu = context THEN mouse(x, y); IF ~((0 <= x) & (x < canvas.width) & (0 <= y) & (y < canvas.height)) THEN menu := NIL END ELSE K.WinPos(winX, winY); K.ClientPos(cliX, cliY); x := winX + cliX; y := MainMenuHeight + winY + cliY END; selected := T.selected(text); IF menu = menuFile THEN Menu.setEnabled(menu, menuSave, text.modified); Menu.setEnabled(menu, menuFolder, text.fileName # ""); i := 0; WHILE (i < textsCount) & ~texts[i].modified DO INC(i) END; Menu.setEnabled(menu, menuSaveAll, i < textsCount); INC(x, menuFileX) ELSIF (menu = menuEdit) OR (menu = context) THEN Menu.setEnabled(menu, menuUndo, ~ChangeLog.isFirstGuard(text.edition)); Menu.setEnabled(menu, menuRedo, ~ChangeLog.isLastGuard(text.edition)); Menu.setEnabled(menu, menuCut, selected); Menu.setEnabled(menu, menuCopy, selected); Menu.setEnabled(menu, menuDelete, selected); Menu.setEnabled(menu, menuPaste, CB.available()); IF menu = menuEdit THEN INC(x, menuEditX) ELSE IF y + menu.height >= canvas.height THEN DEC(y, menu.height) END; IF x + menu.width >= canvas.width THEN DEC(x, menu.width) END; CanvasToScreen(x, y) END ELSIF menu = menuEncoding THEN Menu.option(menu, menuUTF8BOM, text.enc = E.UTF8BOM); Menu.option(menu, menuUTF8, text.enc = E.UTF8); Menu.option(menu, menuCP866, text.enc = E.CP866); Menu.option(menu, menuWin1251, text.enc = E.W1251); INC(x, menuEncodingX) ELSIF menu = menuEOL THEN Menu.option(menu, menuCRLF, text.eol = RW.EOL_CRLF); Menu.option(menu, menuLF, text.eol = RW.EOL_LF); Menu.option(menu, menuCR, text.eol = RW.EOL_CR); INC(x, menuEOLX) ELSIF menu = menuView THEN Menu.check(menu, menuNumbers, text.numbers); Menu.check(menu, menuFontSize, font = font2); FOR i := 0 TO Ini.sections.count - 1 DO Menu.option(menu, menuColors + i, Ini.curSectionNum = i) END; INC(x, menuViewX) ELSIF menu = menuSyntax THEN Menu.option(menu, menuNone, text.lang = Languages.langNone); Menu.option(menu, menuC, text.lang = Languages.langC); Menu.option(menu, menuFasm, text.lang = Languages.langFasm); Menu.option(menu, menuIni, text.lang = Languages.langIni); Menu.option(menu, menuJSON, text.lang = Languages.langJSON); Menu.option(menu, menuLua, text.lang = Languages.langLua); Menu.option(menu, menuOberon, text.lang = Languages.langOberon); Menu.option(menu, menuPascal, text.lang = Languages.langPascal); INC(x, menuSyntaxX) ELSIF menu = menuProgram THEN Menu.setEnabled(menu, menuBuild, buildScript # ""); Menu.setEnabled(menu, menuDebug, debugScript # ""); Menu.setEnabled(menu, menuRun, runScript # ""); INC(x, menuProgramX) ELSIF menu = menuTools THEN INC(x, menuToolsX) ELSIF menu = menuSearch THEN INC(x, menuSearchX) END; enabled := search & (searchText # ""); Menu.setEnabled(menuSearch, menuFindNext, enabled); Menu.setEnabled(menuSearch, menuFindPrev, enabled); Menu.setEnabled(subIndent, menuIncInd, selected); Menu.setEnabled(subIndent, menuDecInd, selected); Menu.setEnabled(subCase, menuUpper, selected); Menu.setEnabled(subCase, menuLower, selected); IF menu # NIL THEN Timer.kill; IF Menu.opened(menu) THEN Menu.close(menu) END; Menu.open(menu, x, y); menuActive := TRUE END END ShowMenu; PROCEDURE receiveIPC; VAR scrollIPC: BOOLEAN; BEGIN scrollIPC := FALSE; IF IPC[0] = Timer.ID THEN IF IPC[4] = Timer.n THEN T.toggleCursor; repaint END; IPC[2] := 0 ELSIF IPC[0] = mainTID THEN IF IPC[2] = Scroll.ScrollIPC THEN Scroll.change(hScroll); IF hScroll.Dec THEN T.scroll(text, -1, 0) ELSIF hScroll.Inc THEN T.scroll(text, 1, 0) END; Scroll.change(vScroll); IF vScroll.Dec THEN T.scroll(text, 0, -1) ELSIF vScroll.Inc THEN T.scroll(text, 0, 1) END; IF menuActive THEN draw_window; menuActive := FALSE ELSE repaint END; IF (0 IN K.MouseState()) THEN WHILE (0 IN K.MouseState()) & (delay > 0) DO K.Pause(1); DEC(delay) END; IF delay = 0 THEN IPC[0] := 0; IPC[1] := 0; scrollIPC := TRUE; Scroll.SendIPC; delay := 2 ELSE delay := scrollDelay END ELSE delay := scrollDelay END END; IPC[2] := 0 ELSIF ~Menu.isSender(IPC[0]) THEN IPC[2] := 0 END; CASE IPC[2] OF |0: |menuCut: T.key(text, ORD("X"), FALSE, TRUE) |menuCopy: T.key(text, ORD("C"), FALSE, TRUE) |menuPaste: T.key(text, ORD("V"), FALSE, TRUE) |menuDelete: T.key(text, 46, FALSE, FALSE) |menuSelectAll: T.key(text, ORD("A"), FALSE, TRUE) |menuNew: NewFile |menuOpen: open |menuSave: save(text); repaint |menuSaveAs: saveAs(text); repaint |menuSaveAll: saveAll; repaint |menuClose: closeFile(TRUE, curText) |menuFolder: K.Run("/rd/1/File Managers/Eolite", text.fileName) |menuExit: Close |menuUndo: T.undo(text); repaint |menuRedo: T.redo(text); repaint |menuFind: ShowSearchPanel; SetFocus(FindEdit, TRUE) |menuFindNext: notFound := ~T.findNext(text, BKW.value); menuFindClicked := TRUE |menuFindPrev: notFound := ~T.findNext(text, ~BKW.value); menuFindClicked := TRUE |menuGoto: ShowSearchPanel; SetFocus(GotoEdit, TRUE) |menuToggleBookmark: T.toggleLabel(text) |menuNextBookmark: T.gotoLabel(text, TRUE) |menuPrevBookmark: T.gotoLabel(text, FALSE) |menuNumbers: T.toggleNumbers(text) |menuFontSize: IF font = font1 THEN font := font2 ELSE font := font1 END; resize |menuNone: T.setLang(text, Languages.langNone) |menuC: T.setLang(text, Languages.langC) |menuFasm: T.setLang(text, Languages.langFasm) |menuIni: T.setLang(text, Languages.langIni) |menuJSON: T.setLang(text, Languages.langJSON) |menuLua: T.setLang(text, Languages.langLua) |menuOberon: T.setLang(text, Languages.langOberon) |menuPascal: T.setLang(text, Languages.langPascal) |menuBuild: Script(buildScript) |menuBuildScript: OpenFile(buildScript, ShellFilter) |menuRun: Script(runScript) |menuRunScript: OpenFile(runScript, ShellFilter) |menuDebug: Script(debugScript) |menuDebugScript: OpenFile(debugScript, ShellFilter) |menuUTF8BOM: text.enc := E.UTF8BOM |menuUTF8: text.enc := E.UTF8 |menuCP866: text.enc := E.CP866 |menuWin1251: text.enc := E.W1251 |menuLF: text.eol := RW.EOL_LF |menuCRLF: text.eol := RW.EOL_CRLF |menuCR: text.eol := RW.EOL_CR |menuPipet: K.Run("/rd/1/develop/pipet", "") |menuBoard: K.Run("/rd/1/develop/board", "") |menuSysFunc: K.Run("/rd/1/docpack", "f") |menuColors..menuMaxColors: Ini.selectSection(IPC[2] - menuColors) |menuMoveUp: T.upLine(text) |menuMoveDown: T.downLine(text) |menuDuplicate: T.dupLine(text) |menuRemove: T.delLine(text) |menuIncInd: T.Indent(text, TRUE) |menuDecInd: T.Indent(text, FALSE) |menuUpper: T.chCase(text, TRUE) |menuLower: T.chCase(text, FALSE) END; IF ~scrollIPC THEN IPC[0] := 0; IPC[1] := 0 END END receiveIPC; PROCEDURE MenuKeyDown (menu: Menu.tMenu; key: INTEGER): BOOLEAN; VAR menuItem: INTEGER; shift, ctrl: BOOLEAN; BEGIN menuItem := -1; getKBState(shift, ctrl); IF ctrl THEN CASE key DIV 65536 OF |17: menuItem := menuClose |21: menuItem := menuRedo |30: menuItem := menuSelectAll |33: menuItem := menuFind |34: menuItem := menuGoto |44: menuItem := menuUndo |45: menuItem := menuCut |46: menuItem := menuCopy |47: menuItem := menuPaste |24: menuItem := menuOpen |31: menuItem := menuSave |49: menuItem := menuNew |67: menuItem := menuBuild ELSE END ELSE IF key DIV 65536 = 83 THEN menuItem := menuDelete ELSIF key DIV 65536 = 67 THEN menuItem := menuRun END END; IF menuItem # -1 THEN IF Menu.isEnabled(menu, menuItem) THEN MenuItemClick(menu, menuItem) ELSE menuItem := -1 END END RETURN menuItem # -1 END MenuKeyDown; PROCEDURE CreateContextMenu (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuUndo, "undo ctrl-Z"); Menu.AddMenuItem(menu, menuRedo, "redo ctrl-Y"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuCut, "cut ctrl-X"); Menu.AddMenuItem(menu, menuCopy, "copy ctrl-C"); Menu.AddMenuItem(menu, menuPaste, "paste ctrl-V"); Menu.AddMenuItem(menu, menuDelete, "delete"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuSelectAll, "select all ctrl-A"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateContextMenu; PROCEDURE CreateMenuFile (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuNew, "new ctrl-N"); Menu.AddMenuItem(menu, menuOpen, "open ctrl-O"); Menu.AddMenuItem(menu, menuSave, "save ctrl-S"); Menu.AddMenuItem(menu, menuSaveAs, "save as"); Menu.AddMenuItem(menu, menuSaveAll, "save all"); Menu.AddMenuItem(menu, menuFolder, "folder"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuClose, "close ctrl-W"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuExit, "exit"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuFile; PROCEDURE CreateMenuEdit (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuUndo, "undo ctrl-Z"); Menu.AddMenuItem(menu, menuRedo, "redo ctrl-Y"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuCut, "cut ctrl-X"); Menu.AddMenuItem(menu, menuCopy, "copy ctrl-C"); Menu.AddMenuItem(menu, menuPaste, "paste ctrl-V"); Menu.AddMenuItem(menu, menuDelete, "delete"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuSelectAll, "select all ctrl-A"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuCurLine, "current line"); Menu.child(menu, subCurLine); Menu.AddMenuItem(menu, menuIndent, "indent"); Menu.child(menu, subIndent); Menu.AddMenuItem(menu, menuCase, "case"); Menu.child(menu, subCase); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuEdit; PROCEDURE CreateMenuSearch (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuFind, "search ctrl-F"); Menu.AddMenuItem(menu, menuFindNext, "find next F3"); Menu.AddMenuItem(menu, menuFindPrev, "find previous shift-F3"); Menu.AddMenuItem(menu, menuGoto, "go to line ctrl-G"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuBookmark, "bookmark"); Menu.child(menu, subBookmark); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuSearch; PROCEDURE CreateMenuEncoding (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuUTF8BOM, E.names[E.UTF8BOM]); Menu.AddMenuItem(menu, menuUTF8, E.names[E.UTF8]); Menu.AddMenuItem(menu, menuCP866, E.names[E.CP866]); Menu.AddMenuItem(menu, menuWin1251, E.names[E.W1251]); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuEncoding; PROCEDURE CreateMenuEOL (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuCRLF, RW.eolNames[RW.EOL_CRLF]); Menu.AddMenuItem(menu, menuLF, RW.eolNames[RW.EOL_LF]); Menu.AddMenuItem(menu, menuCR, RW.eolNames[RW.EOL_CR]); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuEOL; PROCEDURE CreateMenuView (): Menu.tMenu; VAR menu: List.tList; colors: Ini.tSection; idx: INTEGER; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuNumbers, "line numbers"); Menu.AddMenuItem(menu, menuFontSize, "x2"); Menu.delimiter(menu); colors := Ini.sections.first(Ini.tSection); idx := menuColors; WHILE colors # NIL DO Menu.AddMenuItem(menu, idx, colors.name); INC(idx); colors := colors.next(Ini.tSection) END; RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuView; PROCEDURE CreateMenuSyntax (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuC, "C"); Menu.AddMenuItem(menu, menuFasm, "Fasm"); Menu.AddMenuItem(menu, menuIni, "Ini"); Menu.AddMenuItem(menu, menuJSON, "JSON"); Menu.AddMenuItem(menu, menuLua, "Lua"); Menu.AddMenuItem(menu, menuOberon, "Oberon"); Menu.AddMenuItem(menu, menuPascal, "Pascal"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuNone, "none"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuSyntax; PROCEDURE CreateMenuProgram (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuBuild, "build ctrl-F9"); Menu.AddMenuItem(menu, menuBuildScript, "script"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuRun, "run F9"); Menu.AddMenuItem(menu, menuRunScript, "script"); Menu.delimiter(menu); Menu.AddMenuItem(menu, menuDebug, "debug"); Menu.AddMenuItem(menu, menuDebugScript, "script"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuProgram; PROCEDURE CreateMenuTools (): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuPipet, "pipet"); Menu.AddMenuItem(menu, menuBoard, "board"); Menu.AddMenuItem(menu, menuSysFunc, "system functions"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuTools; PROCEDURE CreateMenuCurLine(): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuMoveUp, "move up ctrl-Up"); Menu.AddMenuItem(menu, menuMoveDown, "move down ctrl-Down"); Menu.AddMenuItem(menu, menuDuplicate, "duplicate ctrl-D"); Menu.AddMenuItem(menu, menuRemove, "remove ctrl-Del"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuCurLine; PROCEDURE CreateMenuIndent(): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuIncInd, "increase Tab"); Menu.AddMenuItem(menu, menuDecInd, "decrease shift-Bksp"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuIndent; PROCEDURE CreateMenuCase(): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuUpper, "UPPER ctrl-U"); Menu.AddMenuItem(menu, menuLower, "lower ctrl-L"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuCase; PROCEDURE CreateMenuBookmark(): Menu.tMenu; VAR menu: List.tList; BEGIN menu := List.create(NIL); Menu.AddMenuItem(menu, menuToggleBookmark, "toggle ctrl-F2"); Menu.AddMenuItem(menu, menuNextBookmark, "next F2"); Menu.AddMenuItem(menu, menuPrevBookmark, "previous shift-F2"); RETURN Menu.create(menu, MenuItemClick, MenuKeyDown) END CreateMenuBookmark; PROCEDURE KeyDown (key: INTEGER); VAR keyCode: INTEGER; shift, ctrl: BOOLEAN; BEGIN keyCode := key DIV 65536; getKBState(shift, ctrl); IF confirm THEN IF keyCode = 28 THEN (* Enter *) save(text); IF ~text.modified THEN closeFile(FALSE, curText) END END; key := -1 ELSE IF keyCode = 61 THEN (* F3 *) key := -1; IF search & (searchText # "") THEN IF shift THEN notFound := ~T.findNext(text, ~BKW.value) ELSE notFound := ~T.findNext(text, BKW.value) END END ELSIF keyCode = 60 THEN (* F2 *) key := -1; IF ctrl THEN T.toggleLabel(text) ELSE T.gotoLabel(text, ~shift) END ELSIF keyCode = 67 THEN (* F9 *) key := -1; IF ctrl THEN Script(buildScript) ELSE Script(runScript) END ELSIF keyCode = 1 THEN (* Esc *) key := -1; IF search THEN Search END ELSIF (keyCode = 55) & (key DIV 256 MOD 256 = 52) THEN (* PrtScn *) key := -1 ELSIF (keyCode = 14) & shift THEN (* shift+Backspace *) key := -1; T.input(text, -8) ELSIF (keyCode = 15) & ctrl THEN (* ctrl+Tab *) key := -1; SwitchTab((curText + 1) MOD textsCount) ELSIF (keyCode = 33) & ctrl THEN key := -1; ShowSearchPanel; SetFocus(FindEdit, TRUE) ELSIF (keyCode = 34) & ctrl THEN key := -1; ShowSearchPanel; SetFocus(GotoEdit, TRUE) ELSE IF EditBox_Focus(FindEdit) THEN box_lib.edit_box_key(FindEdit, key); EditBox_GetValue(FindEdit, new_searchText); IF new_searchText # searchText THEN searchText := new_searchText; notFound := ~T.search(text, searchText, cs, whole) END ELSIF EditBox_Focus(ReplaceEdit) THEN box_lib.edit_box_key(ReplaceEdit, key); EditBox_GetValue(ReplaceEdit, replaceText) ELSIF EditBox_Focus(GotoEdit) THEN IF (key DIV 256) MOD 256 = 13 THEN goto ELSE box_lib.edit_box_key(GotoEdit, key) END ELSE CASE keyCode OF |73: key := 33 |81: key := 34 |71: key := 36 |79: key := 35 |72: key := 38 |80: key := 40 |75: key := 37 |77: key := 39 |82, 91, 219, 92, 220: key := -1 (* insert, windows *) |93: ShowMenu(context); key := -1 |83: key := 46 |59, 62..66, 68, 87, 88: key := -1 (* F1, F4..F8, F10, F11, F12 *) ELSE IF ctrl THEN CASE keyCode OF |17: closeFile(TRUE, curText); key := -2 |21: T.redo(text); key := -1 |22: key := ORD("U") |24: key := -1; open |30: key := ORD("A") |31: key := -1; save(text) |32: key := ORD("D") |38: key := ORD("L") |44: T.undo(text); key := -1 |45: key := ORD("X") |46: key := ORD("C") |47: key := ORD("V") |49: key := -1; NewFile ELSE key := -1 END ELSE T.input(text, E.cp866[key DIV 256 MOD 256]); key := -1 END END; IF key >= 0 THEN T.key(text, key, shift, ctrl) END END END END; IF key # -2 THEN repaint END END KeyDown; PROCEDURE BtnClick; VAR btn: INTEGER; middle, exit: BOOLEAN; BEGIN btn := K.ButtonCode(middle); IF (Tabs.btnID <= btn) & (btn <= Tabs.btnID + maxTexts - 1) THEN DEC(btn, Tabs.btnID); IF middle THEN IF texts[btn].modified THEN SwitchTab(btn) END; closeFile(TRUE, btn) ELSE SwitchTab(btn) END; btn := 0 ELSE IF middle THEN btn := 0 END END; CASE btn OF |Tabs.btnID - 1: Tabs.scroll(tabs, -1); switch := TRUE; repaint |Tabs.btnID - 2: Tabs.scroll(tabs, +1); switch := TRUE; repaint |0: |btnFile: ShowMenu(menuFile) |btnEdit: ShowMenu(menuEdit) |btnMenuSearch: ShowMenu(menuSearch) |btnEncoding: ShowMenu(menuEncoding) |btnEOL: ShowMenu(menuEOL) |btnView: ShowMenu(menuView) |btnSyntax: ShowMenu(menuSyntax) |btnProgram: ShowMenu(menuProgram) |btnTools: ShowMenu(menuTools) |btnNo: exit := closing; closeFile(FALSE, curText); repaint; IF exit THEN Close END |btnYes: exit := closing; save(text); IF ~text.modified THEN closeFile(FALSE, curText) END; repaint; IF exit THEN Close END |btnClose: Close |btnNew: NewFile; repaint |btnOpen: open |btnSave: save(text); repaint |btnSearch: ShowSearchPanel |btnCloseFind: Search |btnHideFind: SetFocus(FindEdit, FALSE); searchOpened := FALSE; LEFT := searchLeft; resize; draw_window |btnUndo: T.undo(text); repaint |btnRedo: T.redo(text); repaint |btnUpper: T.chCase(text, TRUE); repaint |btnLower: T.chCase(text, FALSE); repaint |btnBuild: Script(buildScript) |btnRun: Script(runScript) |btnFindNext: IF searchText # "" THEN notFound := ~T.findNext(text, BKW.value); repaint END |btnReplace: T.replace(text, replaceText, LENGTH(searchText)); repaint |btnReplaceAll: notFound := ~T.search(text, searchText, cs, whole); IF ~notFound THEN replaced := T.replaceAll(text, replaceText, LENGTH(searchText)); END; repaint |btnGoto: goto; repaint END END BtnClick; PROCEDURE MouseEvent (VAR resized: BOOLEAN; VAR firstClickX, firstClickY, time: INTEGER); CONST DELAY = 10; VAR msState: SET; scroll, x, y, scrollX, scrollY: INTEGER; PROCEDURE EditBox (eb: box_lib.edit_box); VAR focus: BOOLEAN; BEGIN focus := EditBox_Focus(eb); box_lib.edit_box_mouse(eb); IF focus # EditBox_Focus(eb) THEN SetFocus(eb, TRUE); repaint END END EditBox; BEGIN CloseMenu; IF ~resized THEN msState := K.MouseState(); IF ~(0 IN msState) OR (16 IN msState) THEN LeftButtonUp END; scroll := K.Scroll(); IF scroll # 0 THEN T.scroll(text, 0, scroll*3); repaint END; IF leftButton THEN IF K.GetTickCount() - time >= DELAY THEN mouse(x, y); T.mouse(text, x, y); repaint END END; IF Scroll.isActive(hScroll) THEN mouse(x, y); Scroll.MouseMove(hScroll, x + LEFT, y + TOP); T.getScroll(text, scrollX, scrollY); T.scroll(text, hScroll.value - scrollX, 0); repaint END; IF Scroll.isActive(vScroll) THEN mouse(x, y); Scroll.MouseMove(vScroll, x + LEFT, y + TOP); T.getScroll(text, scrollX, scrollY); T.scroll(text, 0, vScroll.value - scrollY); repaint END; IF (8 IN msState) & ~(24 IN msState) THEN mouse(firstClickX, firstClickY); time := click(firstClickX, firstClickY) END; IF 9 IN msState THEN ShowMenu(context) END; IF 24 IN msState THEN mouse(x, y); IF ~hScroll.mouse THEN Scroll.MouseDown(hScroll, x + LEFT, y + TOP) END; IF ~vScroll.mouse THEN Scroll.MouseDown(vScroll, x + LEFT, y + TOP) END; IF search & searchOpened THEN CheckBox.MouseDown(BKW, x + LEFT, y + TOP); CheckBox.MouseDown(CS, x + LEFT, y + TOP); CheckBox.MouseDown(WH, x + LEFT, y + TOP); END; IF (ABS(x - firstClickX) < 5) & (ABS(y - firstClickY) < 5) THEN IF (0 <= x) & (x < canvas.width) & (0 <= y) & (y < canvas.height) THEN leftButton := FALSE; T.selectWord(text); repaint END ELSE firstClickX := x; firstClickY := y; time := click(firstClickX, firstClickY) END END END; IF search & searchOpened THEN EditBox(FindEdit); EditBox(ReplaceEdit); EditBox(GotoEdit); IF CS.value # cs THEN cs := ~cs; notFound := ~T.search(text, searchText, cs, whole); repaint END; IF WH.value # whole THEN whole := ~whole; notFound := ~T.search(text, searchText, cs, whole); repaint END END; resized := FALSE END MouseEvent; PROCEDURE Redraw (VAR resized: BOOLEAN; VAR width, height, cliWidth, cliHeight: INTEGER); VAR i: INTEGER; BEGIN K.GetSystemColors; FOR i := 0 TO 1 DO IF ~K.RolledUp() THEN K.ClientSize(width, height); IF (width # cliWidth) OR (height # cliHeight) THEN cliWidth := width; cliHeight := height; resize; resized := TRUE END; K.SetEventsMask({0, 1, 2, 5, 6, 31}) ELSE K.SetEventsMask({0, 30, 31}) END; draw_window END END Redraw; PROCEDURE main; VAR err: INTEGER; fileName, filePath: RW.tFileName; width, height, cliWidth, cliHeight: INTEGER; resized: BOOLEAN; firstClickX, firstClickY, time: INTEGER; BEGIN delay := scrollDelay; K.GetSystemColors; Icons.get(icons, grayIcons); modified := FALSE; switch := FALSE; closing := FALSE; textsCount := 0; curText := 0; mainTID := K.ThreadID(); K.SetIPC(IPC); U.ptr2str(K.GetName(), AppPath); Ini.load(AppPath); LeftButtonUp; resized := FALSE; K.ScreenSize(winWidth, winHeight); winWidth := (winWidth*80) DIV 100 - (128 + 30); winHeight := winHeight - (128 + 30); winWidth := MAX(winWidth, minWinWidth); winHeight := MAX(winHeight, minWinHeight); cliWidth := winWidth; cliHeight := winHeight; LEFT := searchLeft; canvas := G.CreateCanvas(winWidth - (LEFT + RIGHT + 11), winHeight - (TOP + BOTTOM + 5) - K.SkinHeight()); tabs := Tabs.create(); Tabs.setArea(tabs, LEFT, TOP - Tabs.tabHeight, canvas.width, Tabs.tabHeight); font1 := G.CreateFont(1, "", {}); font2 := G.CreateFont(2, "", {}); font := font1; G.SetFont(canvas, font); T.init(resetTimer); T.setCanvas(canvas); U.ptr2str(K.GetCommandLine(), fileName); context := CreateContextMenu(); menuFile := CreateMenuFile(); subCurLine := CreateMenuCurLine(); subIndent := CreateMenuIndent(); subCase := CreateMenuCase(); menuEdit := CreateMenuEdit(); subCurLine.parent := menuEdit; subIndent.parent := menuEdit; subCase.parent := menuEdit; subBookmark := CreateMenuBookmark(); menuSearch := CreateMenuSearch(); subBookmark.parent := menuSearch; menuEncoding := CreateMenuEncoding(); menuEOL := CreateMenuEOL(); menuView := CreateMenuView(); menuSyntax := CreateMenuSyntax(); menuProgram := CreateMenuProgram(); menuTools := CreateMenuTools(); Ini.getSettings(buildScript, runScript, debugScript); IF fileName = "" THEN text := T.New(); filePath := "/rd/1" ELSE text := T.open(fileName, err); IF text = NIL THEN error("'cedit: error opening file' -E"); K.Exit ELSE U.getPath(fileName, filePath) END END; OD := OpenDlg.Create(draw_window, OpenDlg.topen, filePath, ""); insert(0, text); Scroll.create(FALSE, canvas.width + 1, scrollWidth, scrollWidth, scrollWidth, hScroll); Scroll.create(TRUE, scrollWidth, canvas.height + 1, scrollWidth, scrollWidth, vScroll); T.resize(canvas.width, canvas.height); T.SetPos(text, 0, 0); confirm := FALSE; notFound := FALSE; menuFindClicked := FALSE; menuActive := FALSE; search := FALSE; searchOpened := FALSE; createSearchForm; new_searchText := ""; searchText := ""; cs := FALSE; whole := FALSE; replaced := 0; K.SetEventsMask({0, 1, 2, 5, 6, 31}); Menu.init(resetTimer); draw_window; Timer.create(mainTID); WHILE TRUE DO CASE K.WaitForEvent() OF |1: IF Menu.redraw THEN Redraw(resized, width, height, cliWidth, cliHeight) ELSE Menu.Redraw; K.CreateWindow(30 + K.GetTickCount() MOD 128, 30 + K.GetTickCount() MOD 128, winWidth, winHeight, K.winColor, 73H, 0, 0, header); repaint END |2: KeyDown(K.GetKey()) |3: BtnClick |6: MouseEvent(resized, firstClickX, firstClickY, time) |7: receiveIPC END END END main; BEGIN main END CEdit.