import glib2, gtk2, gdk2, gtksourceview, dialogs, os, pango, osproc, strutils import pegs, streams import settings, types, cfg, search {.push callConv:cdecl.} const NimrodProjectExt = ".nimprj" var win: types.MainWin win.Tabs = @[] search.win = addr(win) var lastSession: seq[string] = @[] var confParseFail = False # This gets set to true # When there is an error parsing the config # Load the settings try: win.settings = cfg.load(lastSession) except ECFGParse: # TODO: Make the dialog show the exception confParseFail = True win.settings = cfg.defaultSettings() except EIO: win.settings = cfg.defaultSettings() proc getProjectTab(): int = for i in 0..high(win.tabs): if win.tabs[i].filename.endswith(NimrodProjectExt): return i proc saveTab(tabNr: int, startpath: string) = if tabNr < 0: return if win.Tabs[tabNr].saved: return var path = "" if win.Tabs[tabNr].filename == "": path = ChooseFileToSave(win.w, startpath) # dialogs.nim STOCK_OPEN instead of STOCK_SAVE else: path = win.Tabs[tabNr].filename if path != "": var buffer = PTextBuffer(win.Tabs[tabNr].buffer) # Get the text from the TextView var startIter: TTextIter buffer.getStartIter(addr(startIter)) var endIter: TTextIter buffer.getEndIter(addr(endIter)) var text = buffer.getText(addr(startIter), addr(endIter), False) # Save it to a file var f: TFile if open(f, path, fmWrite): f.write(text) f.close() win.tempStuff.lastSaveDir = splitFile(path).dir # Change the tab name and .Tabs.filename etc. win.Tabs[tabNr].filename = path win.Tabs[tabNr].saved = True var name = extractFilename(path) var cTab = win.Tabs[tabNr] cTab.label.setText(name) else: error(win.w, "Unable to write to file") proc saveAllTabs() = for i in 0..high(win.tabs): saveTab(i, os.splitFile(win.tabs[i].filename).dir) # GTK Events # -- w(PWindow) proc destroy(widget: PWidget, data: pgpointer) {.cdecl.} = # gather some settings win.settings.VPanedPos = PPaned(win.sourceViewTabs.getParent()).getPosition() win.settings.winWidth = win.w.allocation.width win.settings.winHeight = win.w.allocation.height # save the settings win.save() # then quit main_quit() proc delete_event(widget: PWidget, event: PEvent, user_data: pgpointer): bool = var quit = True for i in low(win.Tabs)..len(win.Tabs)-1: if not win.Tabs[i].saved: var askSave = dialogNewWithButtons("", win.w, 0, STOCK_SAVE, RESPONSE_ACCEPT, STOCK_CANCEL, RESPONSE_CANCEL, "Close without saving", RESPONSE_REJECT, nil) askSave.setTransientFor(win.w) # TODO: Make this dialog look better var label = labelNew(win.Tabs[i].filename & " is unsaved, would you like to save it ?") PBox(askSave.vbox).pack_start(label, False, False, 0) label.show() var resp = askSave.run() gtk2.destroy(PWidget(askSave)) case resp of RESPONSE_ACCEPT: saveTab(i, os.splitFile(win.tabs[i].filename).dir) quit = True of RESPONSE_CANCEL: quit = False break of RESPONSE_REJECT: quit = True else: quit = False break # If False is returned the window will close return not quit proc windowState_Changed(widget: PWidget, event: PEventWindowState, user_data: pgpointer) = win.settings.winMaximized = (event.newWindowState and WINDOW_STATE_MAXIMIZED) != 0 # -- SourceView(PSourceView) & SourceBuffer proc updateStatusBar(buffer: PTextBuffer){.cdecl.} = # Incase this event gets fired before # bottomBar is initialized if win.bottomBar != nil and not win.tempStuff.stopSBUpdates: var iter: TTextIter win.bottomBar.pop(0) buffer.getIterAtMark(addr(iter), buffer.getInsert()) var row = getLine(addr(iter)) + 1 var col = getLineOffset(addr(iter)) discard win.bottomBar.push(0, "Line: " & $row & " Column: " & $col) proc cursorMoved(buffer: PTextBuffer, location: PTextIter, mark: PTextMark, user_data: pgpointer){.cdecl.} = updateStatusBar(buffer) proc onCloseTab(btn: PButton, user_data: PWidget) = if win.sourceViewTabs.getNPages() > 1: var tab = win.sourceViewTabs.pageNum(user_data) win.sourceViewTabs.removePage(tab) win.Tabs.delete(tab) proc onSwitchTab(notebook: PNotebook, page: PNotebookPage, pageNum: guint, user_data: pgpointer) = if win.Tabs.len()-1 >= pageNum: win.w.setTitle("Aporia IDE - " & win.Tabs[pageNum].filename) proc createTabLabel(name: string, t_child: PWidget): tuple[box: PWidget, label: PLabel] = var box = hboxNew(False, 0) var label = labelNew(name) var closebtn = buttonNew() closeBtn.setLabel(nil) var iconSize = iconSizeFromName("tabIconSize") if iconSize == 0: iconSize = iconSizeRegister("tabIconSize", 10, 10) var image = imageNewFromStock(STOCK_CLOSE, iconSize) discard gSignalConnect(closebtn, "clicked", G_Callback(onCloseTab), t_child) closebtn.setImage(image) gtk2.setRelief(closebtn, RELIEF_NONE) box.packStart(label, True, True, 0) box.packEnd(closebtn, False, False, 0) box.showAll() return (box, label) proc changed(buffer: PTextBuffer, user_data: pgpointer) = # Update the 'Line & Column' #updateStatusBar(buffer) # Change the tabs state to 'unsaved' # and add '*' to the Tab Name var current = win.SourceViewTabs.getCurrentPage() var name = "" if win.Tabs[current].filename == "": win.Tabs[current].saved = False name = "Untitled *" else: win.Tabs[current].saved = False name = extractFilename(win.Tabs[current].filename) & " *" var cTab = win.Tabs[current] cTab.label.setText(name) # Other(Helper) functions proc initSourceView(SourceView: var PWidget, scrollWindow: var PScrolledWindow, buffer: var PSourceBuffer) = # This gets called by addTab # Each tabs creates a new SourceView # SourceScrolledWindow(ScrolledWindow) scrollWindow = scrolledWindowNew(nil, nil) scrollWindow.setPolicy(POLICY_AUTOMATIC, POLICY_AUTOMATIC) scrollWindow.show() # SourceView(gtkSourceView) SourceView = sourceViewNew(buffer) PSourceView(SourceView).setInsertSpacesInsteadOfTabs(True) PSourceView(SourceView).setIndentWidth(win.settings.indentWidth) PSourceView(SourceView).setShowLineNumbers(win.settings.showLineNumbers) PSourceView(SourceView).setHighlightCurrentLine( win.settings.highlightCurrentLine) PSourceView(SourceView).setShowRightMargin(win.settings.rightMargin) PSourceView(SourceView).setAutoIndent(win.settings.autoIndent) var font = font_description_from_string(win.settings.font) SourceView.modifyFont(font) scrollWindow.add(SourceView) SourceView.show() buffer.setHighlightMatchingBrackets( win.settings.highlightMatchingBrackets) # UGLY workaround for yet another compiler bug: discard gsignalConnect(buffer, "mark-set", GCallback(aporia.cursorMoved), nil) discard gsignalConnect(buffer, "changed", GCallback(aporia.changed), nil) # -- Set the syntax highlighter scheme buffer.setScheme(win.scheme) proc addTab(name, filename: string) = ## Adds a tab, if filename is not "" reads the file. And sets ## the tabs SourceViews text to that files contents. assert(win.nimLang != nil) var buffer: PSourceBuffer = sourceBufferNew(win.nimLang) if filename != nil and filename != "": var lang = win.langMan.guessLanguage(filename, nil) if lang != nil: buffer.setLanguage(lang) else: buffer.setHighlightSyntax(False) var nam = name if nam == "": nam = "Untitled" if filename == "": nam.add(" *") elif filename != "" and name == "": # Disable the undo/redo manager. buffer.begin_not_undoable_action() # Load the file. var file: string = readFile(filename) if file != nil: buffer.set_text(file, len(file)) # Enable the undo/redo manager. buffer.end_not_undoable_action() # Get the name.ext of the filename, for the tabs title nam = extractFilename(filename) # Init the sourceview var sourceView: PWidget var scrollWindow: PScrolledWindow initSourceView(sourceView, scrollWindow, buffer) var (TabLabel, labelText) = createTabLabel(nam, scrollWindow) # Add a tab discard win.SourceViewTabs.appendPage(scrollWindow, TabLabel) var nTab: Tab nTab.buffer = buffer nTab.sourceView = sourceView nTab.label = labelText nTab.saved = (filename != "") nTab.filename = filename win.Tabs.add(nTab) PTextView(SourceView).setBuffer(nTab.buffer) # GTK Events Contd. # -- TopMenu & TopBar proc newFile(menuItem: PMenuItem, user_data: pgpointer) = addTab("", "") win.sourceViewTabs.setCurrentPage(win.Tabs.len()-1) proc openFile(menuItem: PMenuItem, user_data: pgpointer) = var startpath = "" var currPage = win.SourceViewTabs.getCurrentPage() if currPage <% win.tabs.len: startpath = os.splitFile(win.tabs[currPage].filename).dir if startpath.len == 0: # Use lastSavePath as the startpath startpath = win.tempStuff.lastSaveDir if startpath.len == 0: startpath = os.getHomeDir() var files = ChooseFilesToOpen(win.w, startpath) if files.len() > 0: for f in items(files): try: addTab("", f) except EIO: error(win.w, "Unable to read from file") # Switch to the newly created tab win.sourceViewTabs.setCurrentPage(win.Tabs.len()-1) proc saveFile_Activate(menuItem: PMenuItem, user_data: pgpointer) = var current = win.SourceViewTabs.getCurrentPage() saveTab(current, os.splitFile(win.tabs[current].filename).dir) proc saveFileAs_Activate(menuItem: PMenuItem, user_data: pgpointer) = var current = win.SourceViewTabs.getCurrentPage() var (filename, saved) = (win.Tabs[current].filename, win.Tabs[current].saved) win.Tabs[current].saved = False win.Tabs[current].filename = "" saveTab(current, os.splitFile(filename).dir) # If the user cancels the save file dialog. Restore the previous filename # and saved state if win.Tabs[current].filename == "": win.Tabs[current].filename = filename win.Tabs[current].saved = saved proc undo(menuItem: PMenuItem, user_data: pgpointer) = var current = win.SourceViewTabs.getCurrentPage() if win.Tabs[current].buffer.canUndo(): win.Tabs[current].buffer.undo() proc redo(menuItem: PMenuItem, user_data: pgpointer) = var current = win.SourceViewTabs.getCurrentPage() if win.Tabs[current].buffer.canRedo(): win.Tabs[current].buffer.redo() proc find_Activate(menuItem: PMenuItem, user_data: pgpointer) = # Get the selected text, and set the findEntry to it. var currentTab = win.SourceViewTabs.getCurrentPage() var insertIter: TTextIter win.Tabs[currentTab].buffer.getIterAtMark(addr(insertIter), win.Tabs[currentTab].buffer.getInsert()) var insertOffset = addr(insertIter).getOffset() var selectIter: TTextIter win.Tabs[currentTab].buffer.getIterAtMark(addr(selectIter), win.Tabs[currentTab].buffer.getSelectionBound()) var selectOffset = addr(selectIter).getOffset() if insertOffset != selectOffset: var text = win.Tabs[currentTab].buffer.getText(addr(insertIter), addr(selectIter), false) win.findEntry.setText(text) win.findBar.show() win.findEntry.grabFocus() win.replaceEntry.hide() win.replaceLabel.hide() win.replaceBtn.hide() win.replaceAllBtn.hide() proc replace_Activate(menuitem: PMenuItem, user_data: pgpointer) = win.findBar.show() win.findEntry.grabFocus() win.replaceEntry.show() win.replaceLabel.show() win.replaceBtn.show() win.replaceAllBtn.show() proc settings_Activate(menuitem: PMenuItem, user_data: pgpointer) = settings.showSettings(win) proc viewBottomPanel_Toggled(menuitem: PCheckMenuItem, user_data: pgpointer) = win.settings.bottomPanelVisible = menuitem.itemGetActive() if win.settings.bottomPanelVisible: win.bottomPanelTabs.show() else: win.bottomPanelTabs.hide() var pegLineError = peg"{[^(]*} '(' {\d+} ', ' \d+ ') Error:' \s* {.*}" pegLineWarning = peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Warning:'/'Hint:') \s* {.*}" pegOtherError = peg"'Error:' \s* {.*}" pegSuccess = peg"'Hint: operation successful'.*" proc addText(textView: PTextView, text: string, colorTag: PTextTag = nil) = if text != nil: var iter: TTextIter textView.getBuffer().getEndIter(addr(iter)) if colorTag == nil: textView.getBuffer().insert(addr(iter), text, len(text)) else: textView.getBuffer().insertWithTags(addr(iter), text, len(text), colorTag, nil) proc createColor(textView: PTextView, name, color: string): PTextTag = var tagTable = textView.getBuffer().getTagTable() result = tagTable.tableLookup(name) if result == nil: result = textView.getBuffer().createTag(name, "foreground", color, nil) when not defined(os.findExe): proc findExe(exe: string): string = ## returns "" if the exe cannot be found result = addFileExt(exe, os.exeExt) if ExistsFile(result): return var path = os.getEnv("PATH") for candidate in split(path, pathSep): var x = candidate / result if ExistsFile(x): return x result = "" proc GetCmd(cmd, filename: string): string = var f = quoteIfContainsWhite(filename) if cmd =~ peg"\s* '$' y'findExe' '(' {[^)]+} ')' {.*}": var exe = quoteIfContainsWhite(findExe(matches[0])) if exe.len == 0: exe = matches[0] result = exe & " " & matches[1] % f else: result = cmd % f proc showBottomPanel() = if not win.settings.bottomPanelVisible: win.bottomPanelTabs.show() win.settings.bottomPanelVisible = true PCheckMenuItem(win.viewBottomPanelMenuItem).itemSetActive(true) # Scroll to the end of the TextView # This is stupid, it works sometimes... it's random var endIter: TTextIter win.outputTextView.getBuffer().getEndIter(addr(endIter)) discard win.outputTextView.scrollToIter( addr(endIter), 0.25, False, 0.0, 0.0) proc compileRun(currentTab: int, shouldRun: bool) = if win.Tabs[currentTab].filename.len == 0: return # Clear the outputTextView win.outputTextView.getBuffer().setText("", 0) var outp = osProc.execProcess(GetCmd(win.settings.nimrodCmd, win.Tabs[currentTab].filename)) # Colors var normalTag = createColor(win.outputTextView, "normalTag", "#3d3d3d") var errorTag = createColor(win.outputTextView, "errorTag", "red") var warningTag = createColor(win.outputTextView, "warningTag", "darkorange") var successTag = createColor(win.outputTextView, "successTag", "darkgreen") for x in outp.splitLines(): if x =~ pegLineError / pegOtherError: win.outputTextView.addText("\n" & x, errorTag) elif x=~ pegSuccess: win.outputTextView.addText("\n" & x, successTag) # Launch the process if shouldRun: var filename = changeFileExt(win.Tabs[currentTab].filename, os.ExeExt) var output = "\n" & osProc.execProcess(filename) win.outputTextView.addText(output) elif x =~ pegLineWarning: win.outputTextView.addText("\n" & x, warningTag) else: win.outputTextView.addText("\n" & x, normalTag) showBottomPanel() proc CompileCurrent_Activate(menuitem: PMenuItem, user_data: pgpointer) = saveFile_Activate(nil, nil) compileRun(win.SourceViewTabs.getCurrentPage(), false) proc CompileRunCurrent_Activate(menuitem: PMenuItem, user_data: pgpointer) = saveFile_Activate(nil, nil) compileRun(win.SourceViewTabs.getCurrentPage(), true) proc CompileProject_Activate(menuitem: PMenuItem, user_data: pgpointer) = saveAllTabs() compileRun(getProjectTab(), false) proc CompileRunProject_Activate(menuitem: PMenuItem, user_data: pgpointer) = saveAllTabs() compileRun(getProjectTab(), true) proc RunCustomCommand(cmd: string) = saveFile_Activate(nil, nil) var currentTab = win.SourceViewTabs.getCurrentPage() if win.Tabs[currentTab].filename.len == 0 or cmd.len == 0: return # Clear the outputTextView win.outputTextView.getBuffer().setText("", 0) var outp = osProc.execProcess(GetCmd(cmd, win.Tabs[currentTab].filename)) var normalTag = createColor(win.outputTextView, "normalTag", "#3d3d3d") for x in outp.splitLines(): win.outputTextView.addText("\n" & x, normalTag) showBottomPanel() proc RunCustomCommand1(menuitem: PMenuItem, user_data: pgpointer) = RunCustomCommand(win.settings.customCmd1) proc RunCustomCommand2(menuitem: PMenuItem, user_data: pgpointer) = RunCustomCommand(win.settings.customCmd2) proc RunCustomCommand3(menuitem: PMenuItem, user_data: pgpointer) = RunCustomCommand(win.settings.customCmd3) # -- FindBar proc nextBtn_Clicked(button: PButton, user_data: pgpointer) = findText(True) proc prevBtn_Clicked(button: PButton, user_data: pgpointer) = findText(False) proc replaceBtn_Clicked(button: PButton, user_data: pgpointer) = var currentTab = win.SourceViewTabs.getCurrentPage() var start, theEnd: TTextIter if not win.Tabs[currentTab].buffer.getSelectionBounds( addr(start), addr(theEnd)): # If no text is selected, try finding a match. findText(True) if not win.Tabs[currentTab].buffer.getSelectionBounds( addr(start), addr(theEnd)): # No match return # Remove the text win.Tabs[currentTab].buffer.delete(addr(start), addr(theEnd)) # Insert the replacement var text = getText(win.replaceEntry) win.Tabs[currentTab].buffer.insert(addr(start), text, len(text)) proc replaceAllBtn_Clicked(button: PButton, user_data: pgpointer) = var find = getText(win.findEntry) var replace = getText(win.replaceEntry) discard replaceAll(find, replace) proc closeBtn_Clicked(button: PButton, user_data: pgpointer) = win.findBar.hide() proc caseSens_Changed(radiomenuitem: PRadioMenuitem, user_data: pgpointer) = win.settings.search = "casesens" proc caseInSens_Changed(radiomenuitem: PRadioMenuitem, user_data: pgpointer) = win.settings.search = "caseinsens" proc style_Changed(radiomenuitem: PRadioMenuitem, user_data: pgpointer) = win.settings.search = "style" proc regex_Changed(radiomenuitem: PRadioMenuitem, user_data: pgpointer) = win.settings.search = "regex" proc peg_Changed(radiomenuitem: PRadioMenuitem, user_data: pgpointer) = win.settings.search = "peg" proc extraBtn_Clicked(button: PButton, user_data: pgpointer) = var extraMenu = menuNew() var group: PGSList var caseSensMenuItem = radio_menu_item_new(group, "Case sensitive") extraMenu.append(caseSensMenuItem) discard signal_connect(caseSensMenuItem, "toggled", SIGNAL_FUNC(caseSens_Changed), nil) caseSensMenuItem.show() group = caseSensMenuItem.ItemGetGroup() var caseInSensMenuItem = radio_menu_item_new(group, "Case insensitive") extraMenu.append(caseInSensMenuItem) discard signal_connect(caseInSensMenuItem, "toggled", SIGNAL_FUNC(caseInSens_Changed), nil) caseInSensMenuItem.show() group = caseInSensMenuItem.ItemGetGroup() var styleMenuItem = radio_menu_item_new(group, "Style insensitive") extraMenu.append(styleMenuItem) discard signal_connect(styleMenuItem, "toggled", SIGNAL_FUNC(style_Changed), nil) styleMenuItem.show() group = styleMenuItem.ItemGetGroup() var regexMenuItem = radio_menu_item_new(group, "Regex") extraMenu.append(regexMenuItem) discard signal_connect(regexMenuItem, "toggled", SIGNAL_FUNC(regex_Changed), nil) regexMenuItem.show() group = regexMenuItem.ItemGetGroup() var pegMenuItem = radio_menu_item_new(group, "Pegs") extraMenu.append(pegMenuItem) discard signal_connect(pegMenuItem, "toggled", SIGNAL_FUNC(peg_Changed), nil) pegMenuItem.show() # Make the correct radio button active case win.settings.search of "casesens": PCheckMenuItem(caseSensMenuItem).ItemSetActive(True) of "caseinsens": PCheckMenuItem(caseInSensMenuItem).ItemSetActive(True) of "style": PCheckMenuItem(styleMenuItem).ItemSetActive(True) of "regex": PCheckMenuItem(regexMenuItem).ItemSetActive(True) of "peg": PCheckMenuItem(pegMenuItem).ItemSetActive(True) extraMenu.popup(nil, nil, nil, nil, 0, get_current_event_time()) # GUI Initialization proc createAccelMenuItem(toolsMenu: PMenu, accGroup: PAccelGroup, label: string, acc: gint, action: proc (i: PMenuItem, p: pgpointer)) = var result = menu_item_new(label) result.addAccelerator("activate", accGroup, acc, 0, ACCEL_VISIBLE) ToolsMenu.append(result) show(result) discard signal_connect(result, "activate", SIGNAL_FUNC(action), nil) proc createSeparator(menu: PMenu) = var sep = separator_menu_item_new() menu.append(sep) sep.show() proc initTopMenu(MainBox: PBox) = # Create a accelerator group, used for shortcuts # like CTRL + S in SaveMenuItem var accGroup = accel_group_new() add_accel_group(win.w, accGroup) # TopMenu(MenuBar) var TopMenu = menuBarNew() # FileMenu var FileMenu = menuNew() var NewMenuItem = menu_item_new("New") # New FileMenu.append(NewMenuItem) show(NewMenuItem) discard signal_connect(NewMenuItem, "activate", SIGNAL_FUNC(newFile), nil) createSeparator(FileMenu) var OpenMenuItem = menu_item_new("Open...") # Open... # CTRL + O OpenMenuItem.add_accelerator("activate", accGroup, KEY_o, CONTROL_MASK, ACCEL_VISIBLE) FileMenu.append(OpenMenuItem) show(OpenMenuItem) discard signal_connect(OpenMenuItem, "activate", SIGNAL_FUNC(aporia.openFile), nil) var SaveMenuItem = menu_item_new("Save") # Save # CTRL + S SaveMenuItem.add_accelerator("activate", accGroup, KEY_s, CONTROL_MASK, ACCEL_VISIBLE) FileMenu.append(SaveMenuItem) show(SaveMenuItem) discard signal_connect(SaveMenuItem, "activate", SIGNAL_FUNC(saveFile_activate), nil) var SaveAsMenuItem = menu_item_new("Save As...") # Save as... SaveAsMenuItem.add_accelerator("activate", accGroup, KEY_s, CONTROL_MASK or gdk2.SHIFT_MASK, ACCEL_VISIBLE) FileMenu.append(SaveAsMenuItem) show(SaveAsMenuItem) discard signal_connect(SaveAsMenuItem, "activate", SIGNAL_FUNC(saveFileAs_Activate), nil) var FileMenuItem = menuItemNewWithMnemonic("_File") FileMenuItem.setSubMenu(FileMenu) FileMenuItem.show() TopMenu.append(FileMenuItem) # Edit menu var EditMenu = menuNew() var UndoMenuItem = menu_item_new("Undo") # Undo EditMenu.append(UndoMenuItem) show(UndoMenuItem) discard signal_connect(UndoMenuItem, "activate", SIGNAL_FUNC(aporia.undo), nil) var RedoMenuItem = menu_item_new("Redo") # Undo EditMenu.append(RedoMenuItem) show(RedoMenuItem) discard signal_connect(RedoMenuItem, "activate", SIGNAL_FUNC(aporia.redo), nil) createSeparator(EditMenu) var FindMenuItem = menu_item_new("Find") # Find FindMenuItem.add_accelerator("activate", accGroup, KEY_f, CONTROL_MASK, ACCEL_VISIBLE) EditMenu.append(FindMenuItem) show(FindMenuItem) discard signal_connect(FindMenuItem, "activate", SIGNAL_FUNC(aporia.find_Activate), nil) var ReplaceMenuItem = menu_item_new("Replace") # Replace ReplaceMenuItem.add_accelerator("activate", accGroup, KEY_h, CONTROL_MASK, ACCEL_VISIBLE) EditMenu.append(ReplaceMenuItem) show(ReplaceMenuItem) discard signal_connect(ReplaceMenuItem, "activate", SIGNAL_FUNC(aporia.replace_Activate), nil) createSeparator(EditMenu) var SettingsMenuItem = menu_item_new("Settings...") # Settings EditMenu.append(SettingsMenuItem) show(SettingsMenuItem) discard signal_connect(SettingsMenuItem, "activate", SIGNAL_FUNC(aporia.Settings_Activate), nil) var EditMenuItem = menuItemNewWithMnemonic("_Edit") EditMenuItem.setSubMenu(EditMenu) EditMenuItem.show() TopMenu.append(EditMenuItem) # View menu var ViewMenu = menuNew() win.viewBottomPanelMenuItem = check_menu_item_new("Bottom Panel") PCheckMenuItem(win.viewBottomPanelMenuItem).itemSetActive( win.settings.bottomPanelVisible) win.viewBottomPanelMenuItem.add_accelerator("activate", accGroup, KEY_f9, CONTROL_MASK, ACCEL_VISIBLE) ViewMenu.append(win.viewBottomPanelMenuItem) show(win.viewBottomPanelMenuItem) discard signal_connect(win.viewBottomPanelMenuItem, "toggled", SIGNAL_FUNC(aporia.viewBottomPanel_Toggled), nil) var ViewMenuItem = menuItemNewWithMnemonic("_View") ViewMenuItem.setSubMenu(ViewMenu) ViewMenuItem.show() TopMenu.append(ViewMenuItem) # Tools menu var ToolsMenu = menuNew() createAccelMenuItem(ToolsMenu, accGroup, "Compile current file", KEY_F4, aporia.CompileCurrent_Activate) createAccelMenuItem(ToolsMenu, accGroup, "Compile & run current file", KEY_F5, aporia.CompileRunCurrent_Activate) createSeparator(ToolsMenu) createAccelMenuItem(ToolsMenu, accGroup, "Compile project", KEY_F8, aporia.CompileProject_Activate) createAccelMenuItem(ToolsMenu, accGroup, "Compile & run project", KEY_F9, aporia.CompileRunProject_Activate) createSeparator(ToolsMenu) createAccelMenuItem(ToolsMenu, accGroup, "Run custom command 1", KEY_F1, aporia.RunCustomCommand1) createAccelMenuItem(ToolsMenu, accGroup, "Run custom command 2", KEY_F2, aporia.RunCustomCommand2) createAccelMenuItem(ToolsMenu, accGroup, "Run custom command 3", KEY_F3, aporia.RunCustomCommand3) var ToolsMenuItem = menuItemNewWithMnemonic("_Tools") ToolsMenuItem.setSubMenu(ToolsMenu) ToolsMenuItem.show() TopMenu.append(ToolsMenuItem) # Help menu MainBox.packStart(TopMenu, False, False, 0) TopMenu.show() proc initToolBar(MainBox: PBox) = # TopBar(ToolBar) var TopBar = toolbarNew() TopBar.setStyle(TOOLBAR_ICONS) var NewFileItem = TopBar.insertStock(STOCK_NEW, "New File", "New File", SIGNAL_FUNC(aporia.newFile), nil, 0) TopBar.appendSpace() var OpenItem = TopBar.insertStock(STOCK_OPEN, "Open", "Open", SIGNAL_FUNC(aporia.openFile), nil, -1) var SaveItem = TopBar.insertStock(STOCK_SAVE, "Save", "Save", SIGNAL_FUNC(saveFile_Activate), nil, -1) TopBar.appendSpace() var UndoItem = TopBar.insertStock(STOCK_UNDO, "Undo", "Undo", SIGNAL_FUNC(aporia.undo), nil, -1) var RedoItem = TopBar.insertStock(STOCK_REDO, "Redo", "Redo", SIGNAL_FUNC(aporia.redo), nil, -1) MainBox.packStart(TopBar, False, False, 0) TopBar.show() proc initSourceViewTabs() = win.SourceViewTabs = notebookNew() #win.sourceViewTabs.dragDestSet(DEST_DEFAULT_DROP, nil, 0, ACTION_MOVE) discard win.SourceViewTabs.signalConnect( "switch-page", SIGNAL_FUNC(onSwitchTab), nil) #discard win.SourceViewTabs.signalConnect( # "drag-drop", SIGNAL_FUNC(svTabs_DragDrop), nil) #discard win.SourceViewTabs.signalConnect( # "drag-data-received", SIGNAL_FUNC(svTabs_DragDataRecv), nil) #discard win.SourceViewTabs.signalConnect( # "drag-motion", SIGNAL_FUNC(svTabs_DragMotion), nil) win.SourceViewTabs.set_scrollable(True) win.SourceViewTabs.show() if lastSession.len != 0: for i in 0 .. len(lastSession)-1: var splitUp = lastSession[i].split('|') var (filename, offset) = (splitUp[0], splitUp[1]) addTab("", filename) var iter: TTextIter win.Tabs[i].buffer.getIterAtOffset(addr(iter), offset.parseInt()) win.Tabs[i].buffer.moveMarkByName("insert", addr(iter)) win.Tabs[i].buffer.moveMarkByName("selection_bound", addr(iter)) # TODO: Fix this..... :( discard PTextView(win.Tabs[i].sourceView). scrollToIter(addr(iter), 0.25, true, 0.0, 0.0) else: addTab("", "") # This doesn't work :\ win.Tabs[0].sourceView.grabFocus() proc initBottomTabs() = win.bottomPanelTabs = notebookNew() if win.settings.bottomPanelVisible: win.bottomPanelTabs.show() # output tab var tabLabel = labelNew("Output") var outputTab = vboxNew(False, 0) discard win.bottomPanelTabs.appendPage(outputTab, tabLabel) # Compiler tabs, gtktextview var outputScrolledWindow = scrolledwindowNew(nil, nil) outputScrolledWindow.setPolicy(POLICY_AUTOMATIC, POLICY_AUTOMATIC) outputTab.packStart(outputScrolledWindow, true, true, 0) outputScrolledWindow.show() win.outputTextView = textviewNew() outputScrolledWindow.add(win.outputTextView) win.outputTextView.show() outputTab.show() proc initTAndBP(MainBox: PBox) = # This init's the HPaned, which splits the sourceViewTabs # and the BottomPanelTabs initSourceViewTabs() initBottomTabs() var TAndBPVPaned = vpanedNew() tandbpVPaned.pack1(win.sourceViewTabs, resize=True, shrink=False) tandbpVPaned.pack2(win.bottomPanelTabs, resize=False, shrink=False) MainBox.packStart(TAndBPVPaned, True, True, 0) tandbpVPaned.setPosition(win.settings.VPanedPos) TAndBPVPaned.show() proc initFindBar(MainBox: PBox) = # Create a fixed container win.findBar = HBoxNew(False, 0) win.findBar.setSpacing(4) # Add a Label 'Find' var findLabel = labelNew("Find:") win.findBar.packStart(findLabel, False, False, 0) findLabel.show() # Add a (find) text entry win.findEntry = entryNew() win.findBar.packStart(win.findEntry, False, False, 0) discard win.findEntry.signalConnect("activate", SIGNAL_FUNC( aporia.nextBtn_Clicked), nil) win.findEntry.show() var rq: TRequisition win.findEntry.sizeRequest(addr(rq)) # Make the (find) text entry longer win.findEntry.set_size_request(190, rq.height) # Add a Label 'Replace' # - This Is only shown, when the 'Search & Replace'(CTRL + H) is shown win.replaceLabel = labelNew("Replace:") win.findBar.packStart(win.replaceLabel, False, False, 0) #replaceLabel.show() # Add a (replace) text entry # - This Is only shown, when the 'Search & Replace'(CTRL + H) is shown win.replaceEntry = entryNew() win.findBar.packStart(win.replaceEntry, False, False, 0) #win.replaceEntry.show() var rq1: TRequisition win.replaceEntry.sizeRequest(addr(rq1)) # Make the (replace) text entry longer win.replaceEntry.set_size_request(100, rq1.height) # Find next button var nextBtn = buttonNew("Next") win.findBar.packStart(nextBtn, false, false, 0) discard nextBtn.signalConnect("clicked", SIGNAL_FUNC(aporia.nextBtn_Clicked), nil) nextBtn.show() var nxtBtnRq: TRequisition nextBtn.sizeRequest(addr(nxtBtnRq)) # Find previous button var prevBtn = buttonNew("Previous") win.findBar.packStart(prevBtn, false, false, 0) discard prevBtn.signalConnect("clicked", SIGNAL_FUNC(aporia.prevBtn_Clicked), nil) prevBtn.show() # Replace button # - This Is only shown, when the 'Search & Replace'(CTRL + H) is shown win.replaceBtn = buttonNew("Replace") win.findBar.packStart(win.replaceBtn, false, false, 0) discard win.replaceBtn.signalConnect("clicked", SIGNAL_FUNC(aporia.replaceBtn_Clicked), nil) #replaceBtn.show() # Replace all button # - this Is only shown, when the 'Search & Replace'(CTRL + H) is shown win.replaceAllBtn = buttonNew("Replace All") win.findBar.packStart(win.replaceAllBtn, false, false, 0) discard win.replaceAllBtn.signalConnect("clicked", SIGNAL_FUNC(aporia.replaceAllBtn_Clicked), nil) #replaceAllBtn.show() # Right side ... # Close button - With a close stock image var closeBtn = buttonNew() var closeImage = imageNewFromStock(STOCK_CLOSE, ICON_SIZE_SMALL_TOOLBAR) var closeBox = hboxNew(False, 0) closeBtn.add(closeBox) closeBox.show() closeBox.add(closeImage) closeImage.show() discard closeBtn.signalConnect("clicked", SIGNAL_FUNC(aporia.closeBtn_Clicked), nil) win.findBar.packEnd(closeBtn, False, False, 2) closeBtn.show() # Extra button - When clicked shows a menu with options like 'Use regex' var extraBtn = buttonNew() var extraImage = imageNewFromStock(STOCK_PROPERTIES, ICON_SIZE_SMALL_TOOLBAR) var extraBox = hboxNew(False, 0) extraBtn.add(extraBox) extraBox.show() extraBox.add(extraImage) extraImage.show() discard extraBtn.signalConnect("clicked", SIGNAL_FUNC(aporia.extraBtn_Clicked), nil) win.findBar.packEnd(extraBtn, False, False, 0) extraBtn.show() MainBox.packStart(win.findBar, False, False, 0) win.findBar.show() proc initStatusBar(MainBox: PBox) = win.bottomBar = statusbarNew() MainBox.packStart(win.bottomBar, False, False, 0) win.bottomBar.show() discard win.bottomBar.push(0, "Line: 0 Column: 0") proc initControls() = # Load up the language style win.langMan = languageManagerGetDefault() var langpaths: array[0..1, cstring] = [cstring(os.getApplicationDir() / langSpecs), nil] win.langMan.setSearchPath(addr(langpaths)) var nimLang = win.langMan.getLanguage("nimrod") win.nimLang = nimLang # Load the scheme var schemeMan = schemeManagerGetDefault() var schemepaths: array[0..1, cstring] = [cstring(os.getApplicationDir() / styles), nil] schemeMan.setSearchPath(addr(schemepaths)) win.scheme = schemeMan.getScheme(win.settings.colorSchemeID) # Window win.w = windowNew(gtk2.WINDOW_TOPLEVEL) win.w.setDefaultSize(win.settings.winWidth, win.settings.winHeight) win.w.setTitle("Aporia IDE") if win.settings.winMaximized: win.w.maximize() win.w.show() # The window has to be shown before # setting the position of the VPaned so that # it gets set correctly, when the window is maximized. discard win.w.signalConnect("destroy", SIGNAL_FUNC(aporia.destroy), nil) discard win.w.signalConnect("delete_event", SIGNAL_FUNC(aporia.delete_event), nil) discard win.w.signalConnect("window-state-event", SIGNAL_FUNC(aporia.windowState_Changed), nil) # MainBox (vbox) var MainBox = vboxNew(False, 0) win.w.add(MainBox) initTopMenu(MainBox) initToolBar(MainBox) initTAndBP(MainBox) initFindBar(MainBox) initStatusBar(MainBox) MainBox.show() if confParseFail: dialogs.warning(win.w, "Error parsing config file, using default settings.") nimrod_init() initControls() main()