def draw_line_hexagon(self, position, line_width, line_color, paint_enabled=[True,True,True,True,True,True], shadow=False): qpainter = self.painter if line_width == 0: return pen = data.QPen(data.Qt.SolidLine) pen.setCapStyle(data.Qt.RoundCap) pen.setJoinStyle(data.Qt.RoundJoin) pen.setWidth(line_width) pen.setColor(line_color) qpainter.setPen(pen) hex_points = list( HexBuilder.generate_hexagon_points(self.edge_length, position) ) x_correction = self.edge_length / 2 y_correction = self.edge_length / (2 * math.tan(math.radians(30))) hex_points = [(x-x_correction, y-y_correction) for x, y in hex_points] hex_lines = [] for i in range(len(hex_points)): if paint_enabled[i] == False: continue n = i + 1 if n > (len(hex_points)-1): n = 0 hex_lines.append( data.QLine( data.QPoint(*hex_points[i]), data.QPoint(*hex_points[n]) ) ) if hex_lines: if shadow == True: shadow_0_color = data.QColor(line_color) shadow_0_color.setAlpha(64) shadow_1_color = data.QColor(line_color) shadow_1_color.setAlpha(128) pen.setWidth(line_width*2.0) pen.setColor(shadow_0_color) qpainter.setPen(pen) qpainter.drawLines(*hex_lines) pen.setWidth(line_width*1.5) pen.setColor(shadow_1_color) qpainter.setPen(pen) qpainter.drawLines(*hex_lines) pen.setWidth(line_width) pen.setColor(line_color) qpainter.setPen(pen) qpainter.drawLines(*hex_lines) else: qpainter.drawLines(*hex_lines)
def draw_full_hexagon_with_shadow(self, position, fill_color, line_width, line_color): qpainter = self.painter self.draw_filled_hexagon(position, fill_color) shadow_0_color = data.QColor(line_color) shadow_0_color.setAlpha(64) shadow_1_color = data.QColor(line_color) shadow_1_color.setAlpha(128) self.draw_line_hexagon(position, line_width * 2.0, shadow_0_color) self.draw_line_hexagon(position, line_width * 1.5, shadow_1_color) self.draw_line_hexagon(position, line_width, line_color)
def set_theme(self, theme): for style in self.styles: # Papers self.setPaper(data.QColor(theme.Paper.AWK.Default), self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.AWK, style))
def draw_filled_hexagon(self, position, fill_color, number=None): qpainter = self.painter pen = data.QPen(data.Qt.SolidLine) pen.setColor(fill_color) brush = data.QBrush(data.Qt.SolidPattern) brush.setColor(fill_color) qpainter.setBrush(brush) qpainter.setPen(pen) hex_points = list( HexBuilder.generate_hexagon_points(self.edge_length, position)) x_correction = self.edge_length / 2 y_correction = self.edge_length / (2 * math.tan(math.radians(30))) hex_points = [(x - x_correction, y - y_correction) for x, y in hex_points] hex_qpoints = [data.QPoint(*x) for x in hex_points] qpainter.drawPolygon(*hex_qpoints) if (self.SHOW_FIELD_NUMBERS == True) and (number != None): font = data.QFont('Courier', 8) font.setBold(True) qpainter.setFont(font) pen = data.QPen(data.Qt.SolidLine) pen.setColor(data.QColor(0, 0, 0)) qpainter.setPen(pen) font_metric = data.QFontMetrics(font) x = position[0] - font_metric.width(str(number)) / 2 y = position[1] + font_metric.height() / 4 qpainter.drawText(data.QPoint(x, y), str(number))
def set_theme(self, theme): for style in self.styles.keys(): # Papers self.setPaper(data.QColor(theme.Paper.Nim.Default), self.styles[style]) # Fonts set_font(self, style, getattr(theme.Font.Nim, style))
def set_theme(self, theme): for style in self.styles: # Papers paper = data.QColor(getattr(theme.Paper.Python, style)) self.setPaper(paper, self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.Python, style))
def set_font(lexer, style_name, style_options): font, color, size, bold = style_options lexer.setColor(data.QColor(color), lexer.styles[style_name]) weight = data.QFont.Normal if bold == 1 or bold == True: weight = data.QFont.Bold elif bold == 2: weight = data.QFont.Black lexer.setFont(data.QFont(font, size, weight=weight), lexer.styles[style_name])
def init_editor(self, editor): """Initialize all of the PlainEditor settings for difference displaying""" editor.setLexer(None) editor.setUtf8(True) editor.setIndentationsUseTabs(False) editor.setFont(self.DEFAULT_FONT) editor.setBraceMatching(data.QsciScintilla.SloppyBraceMatch) editor.setMatchedBraceBackgroundColor(data.QColor(255, 153, 0)) editor.setAcceptDrops(False) editor.setEolMode(settings.Editor.end_of_line_mode) editor.setReadOnly(True) editor.savable = data.CanSave.NO
def __init__(self, painter, first_position, edge_length, scale=1.0, fill_color=data.QColor(255,255,255), line_width=1, line_color=data.QColor(255,255,255),): self.set_first_position(first_position) self.painter = painter self.scale = scale self.edge_length = scale * edge_length self.horizontal_step, self.vertical_step, self.steps = GridGenerator.init_steps( self.edge_length, self.scale ) self.fill_color = fill_color self.line_width = line_width self.line_color = line_color self.stored_lines = []
def set_font(lexer, style_name, style_options): font, color, size, bold = style_options try: style_index = lexer.styles[style_name]["index"] except: style_index = lexer.styles[style_name] lexer.setColor( data.QColor(color), style_index ) weight = data.QFont.Normal if bold == 1 or bold == True: weight = data.QFont.Bold elif bold == 2: weight = data.QFont.Black lexer.setFont( data.QFont(font, size, weight=weight), style_index )
def create_base_image(): hex_image = data.QImage( functions.create_size(width, height), data.QImage.Format_ARGB32_Premultiplied) hex_image.fill(data.Qt.transparent) qpainter = data.QPainter(hex_image) qpainter.setRenderHints(data.QPainter.Antialiasing | data.QPainter.TextAntialiasing | data.QPainter.SmoothPixmapTransform) hb = components.HexBuilder( qpainter, (width / 2, height / 2), self.DEFAULT_SIZE, self.scale_factor, fill_color=data.theme.Settings_Hex_Background, line_width=2, line_color=data.QColor(64, 64, 64), ) hb.create_grid(False) qpainter.end() return data.QPixmap.fromImage(hex_image)
def draw(self, opacity): image = data.QImage(self.pixmap.size(), data.QImage.Format_ARGB32_Premultiplied) image.fill(data.Qt.transparent) painter = data.QPainter(image) painter.setOpacity(opacity) painter.drawPixmap(0, 0, self.pixmap) if opacity < 0.5: painter.setPen(data.theme.Font.Default) else: painter.setPen(data.QColor(255, 255, 255)) painter.setFont( data.QFont('Segoe UI', int(16 * self.scale), data.QFont.Bold)) painter.setOpacity(1.0) painter.drawText(self.pixmap.rect(), data.Qt.AlignCenter, self.text) painter.end() # Display the manipulated image self.setPixmap(data.QPixmap.fromImage(image)) # Set the button mask, which sets the button area to the shape of # the button image instead of a rectangle self.setMask(self.pixmap.mask())
def create_color_image(color): hex_image = data.QImage( data.QSize(width, height), data.QImage.Format_ARGB32_Premultiplied ) hex_image.fill(data.Qt.transparent) qpainter = data.QPainter(hex_image) qpainter.setRenderHints( data.QPainter.Antialiasing | data.QPainter.TextAntialiasing | data.QPainter.SmoothPixmapTransform ) hb = components.HexBuilder( qpainter, (width/2, height/2), self.DEFAULT_SIZE, self.scale_factor, fill_color=color, line_width=0, line_color=data.QColor(0,0,0), ) hb.create_grid(False) qpainter.end() return data.QPixmap.fromImage(hex_image)
class TextDiffer(data.QWidget): """A widget that holds two PlainEditors for displaying text difference""" #Class variables _parent = None main_form = None name = "" savable = data.CanSave.NO current_icon = None icon_manipulator = None focused_editor = None text_1 = None text_2 = None text_1_name = None text_2_name = None #Class constants DEFAULT_FONT = data.QFont(data.current_font_name, data.current_font_size) MARGIN_STYLE = data.QsciScintilla.STYLE_LINENUMBER INDICATOR_UNIQUE_1 = 1 Indicator_Unique_1_Color = data.QColor(0x72, 0x9f, 0xcf, 80) INDICATOR_UNIQUE_2 = 2 Indicator_Unique_2_Color = data.QColor(0xad, 0x7f, 0xa8, 80) INDICATOR_SIMILAR = 3 Indicator_Similar_Color = data.QColor(0x8a, 0xe2, 0x34, 80) GET_X_OFFSET = data.QsciScintillaBase.SCI_GETXOFFSET SET_X_OFFSET = data.QsciScintillaBase.SCI_SETXOFFSET UPDATE_H_SCROLL = data.QsciScintillaBase.SC_UPDATE_H_SCROLL UPDATE_V_SCROLL = data.QsciScintillaBase.SC_UPDATE_V_SCROLL #Diff icons icon_unique_1 = None icon_unique_2 = None icon_similar = None #Marker references marker_unique_1 = None marker_unique_2 = None marker_unique_symbol_1 = None marker_unique_symbol_2 = None marker_similar_1 = None marker_similar_2 = None marker_similar_symbol_1 = None marker_similar_symbol_2 = None #Child widgets splitter = None editor_1 = None editor_2 = None layout = None def clean_up(self): self.editor_1.mousePressEvent = None self.editor_1.wheelEvent = None self.editor_2.mousePressEvent = None self.editor_2.wheelEvent = None self.editor_1.actual_parent = None self.editor_2.actual_parent = None self.editor_1.clean_up() self.editor_2.clean_up() self.editor_1 = None self.editor_2 = None self.focused_editor = None self.splitter.setParent(None) self.splitter = None self.layout = None self._parent = None self.main_form = None self.icon_manipulator = None # Clean up self self.setParent(None) self.deleteLater() """ The actual clean up will occur when the next garbage collection cycle is executed, probably because of the nested functions and the focus decorator. """ def __init__(self, parent, main_form, text_1=None, text_2=None, text_1_name="", text_2_name=""): """Initialization""" # Initialize the superclass super().__init__(parent) # Initialize components self.icon_manipulator = components.IconManipulator(self, parent) # Initialize colors according to theme self.Indicator_Unique_1_Color = data.theme.TextDifferColors.Indicator_Unique_1_Color self.Indicator_Unique_2_Color = data.theme.TextDifferColors.Indicator_Unique_2_Color self.Indicator_Similar_Color = data.theme.TextDifferColors.Indicator_Similar_Color # Store the reference to the parent self._parent = parent # Store the reference to the main form self.main_form = main_form # Set the differ icon self.current_icon = functions.create_icon( 'tango_icons/compare-text.png') #Set the name of the differ widget if text_1_name != None and text_2_name != None: self.name = "Text difference: {:s} / {:s}".format( text_1_name, text_2_name) self.text_1_name = text_1_name self.text_2_name = text_2_name else: self.name = "Text difference" self.text_1_name = "TEXT 1" self.text_2_name = "TEXT 2" # Initialize diff icons self.icon_unique_1 = functions.create_icon( "tango_icons/diff-unique-1.png") self.icon_unique_2 = functions.create_icon( "tango_icons/diff-unique-2.png") self.icon_similar = functions.create_icon( "tango_icons/diff-similar.png") # Create the horizontal splitter and two editor widgets self.splitter = data.QSplitter(data.Qt.Horizontal, self) self.editor_1 = CustomEditor(self, main_form) self.init_editor(self.editor_1) self.editor_2 = CustomEditor(self, main_form) self.init_editor(self.editor_2) self.editor_1.choose_lexer("text") self.editor_2.choose_lexer("text") self.splitter.addWidget(self.editor_1) self.splitter.addWidget(self.editor_2) self.layout = data.QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.splitter) # Set the layout self.setLayout(self.layout) # Connect the necessary signals self.editor_1.SCN_UPDATEUI.connect(self._scn_updateui_1) self.editor_2.SCN_UPDATEUI.connect(self._scn_updateui_2) self.editor_1.cursorPositionChanged.connect(self._cursor_change_1) self.editor_2.cursorPositionChanged.connect(self._cursor_change_2) # Overwrite the CustomEditor parent widgets to point to the TextDiffers' PARENT self.editor_1._parent = self._parent self.editor_2._parent = self._parent # Add a new attribute to the CustomEditor that will hold the TextDiffer reference self.editor_1.actual_parent = self self.editor_2.actual_parent = self # Set the embedded flag self.editor_1.embedded = True self.editor_2.embedded = True # Add decorators to each editors mouse clicks and mouse wheel scrolls def focus_decorator(function_to_decorate, focused_editor): def decorated_function(*args, **kwargs): self.focused_editor = focused_editor function_to_decorate(*args, **kwargs) return decorated_function self.editor_1.mousePressEvent = focus_decorator( self.editor_1.mousePressEvent, self.editor_1) self.editor_1.wheelEvent = focus_decorator(self.editor_1.wheelEvent, self.editor_1) self.editor_2.mousePressEvent = focus_decorator( self.editor_2.mousePressEvent, self.editor_2) self.editor_2.wheelEvent = focus_decorator(self.editor_2.wheelEvent, self.editor_2) # Add corner buttons self.add_corner_buttons() # Focus the first editor on initialization self.focused_editor = self.editor_1 self.focused_editor.setFocus() # Initialize markers self.init_markers() # Set the theme self.set_theme(data.theme) # Set editor functions that have to be propagated from the TextDiffer # to the child editor self._init_editor_functions() # Check the text validity if text_1 == None or text_2 == None: #One of the texts is unspecified return # Create the diff self.compare(text_1, text_2) def _scn_updateui_1(self, sc_update): """Function connected to the SCN_UPDATEUI signal for scroll detection""" if self.focused_editor == self.editor_1: #Scroll the opposite editor if sc_update == self.UPDATE_H_SCROLL: current_x_offset = self.editor_1.SendScintilla( self.GET_X_OFFSET) self.editor_2.SendScintilla(self.SET_X_OFFSET, current_x_offset) elif sc_update == self.UPDATE_V_SCROLL: current_top_line = self.editor_1.firstVisibleLine() self.editor_2.setFirstVisibleLine(current_top_line) def _scn_updateui_2(self, sc_update): """Function connected to the SCN_UPDATEUI signal for scroll detection""" if self.focused_editor == self.editor_2: #Scroll the opposite editor if sc_update == self.UPDATE_H_SCROLL: current_x_offset = self.editor_2.SendScintilla( self.GET_X_OFFSET) self.editor_1.SendScintilla(self.SET_X_OFFSET, current_x_offset) elif sc_update == self.UPDATE_V_SCROLL: current_top_line = self.editor_2.firstVisibleLine() self.editor_1.setFirstVisibleLine(current_top_line) def _cursor_change_1(self, line, index): """ Function connected to the cursorPositionChanged signal for cursor position change detection """ if self.focused_editor == self.editor_1: #Update the cursor position on the opposite editor cursor_line, cursor_index = self.editor_1.getCursorPosition() #Check if the opposite editor line is long enough if self.editor_2.lineLength(cursor_line) > cursor_index: self.editor_2.setCursorPosition(cursor_line, cursor_index) else: self.editor_2.setCursorPosition(cursor_line, 0) #Update the first visible line, so that the views in both differs match current_top_line = self.editor_1.firstVisibleLine() self.editor_2.setFirstVisibleLine(current_top_line) def _cursor_change_2(self, line, index): """ Function connected to the cursorPositionChanged signal for cursor position change detection """ if self.focused_editor == self.editor_2: #Update the cursor position on the opposite editor cursor_line, cursor_index = self.editor_2.getCursorPosition() #Check if the opposite editor line is long enough if self.editor_1.lineLength(cursor_line) > cursor_index: self.editor_1.setCursorPosition(cursor_line, cursor_index) else: self.editor_1.setCursorPosition(cursor_line, 0) #Update the first visible line, so that the views in both differs match current_top_line = self.editor_2.firstVisibleLine() self.editor_1.setFirstVisibleLine(current_top_line) def _update_margins(self): """Update the text margin width""" self.editor_1.setMarginWidth(0, "0" * len(str(self.editor_1.lines()))) self.editor_2.setMarginWidth(0, "0" * len(str(self.editor_2.lines()))) def _signal_editor_cursor_change(self, cursor_line=None, cursor_column=None): """Signal that fires when cursor position changes in one of the editors""" self.main_form.display.update_cursor_position(cursor_line, cursor_column) def _init_editor_functions(self): """ Initialize the editor functions that are called on the TextDiffer widget, but need to be executed on one of the editors """ #Find text function propagated to the focused editor def enabled_function(*args, **kwargs): #Get the function function = getattr(self.focused_editor, args[0]) #Call the function˘, leaving out the "function name" argument function(*args[1:], **kwargs) #Unimplemented functions def uniplemented_function(*args, **kwargs): self.main_form.display.repl_display_message( "Function '{:s}' is not implemented by the TextDiffer!".format( args[0]), message_type=data.MessageType.ERROR) all_editor_functions = inspect.getmembers(CustomEditor, predicate=inspect.isfunction) skip_functions = [ "set_theme", "clean_up", ] enabled_functions = [ "find_text", ] disabled_functions = [ "__init__", "__setattr__", "_filter_keypress", "_filter_keyrelease", "_init_special_functions", "_set_indicator", "find_text", "keyPressEvent", "keyReleaseEvent", "mousePressEvent", "setFocus", "wheelEvent", ] #Check methods for function in all_editor_functions: if function[0] in skip_functions: #Use the TextDiffer implementation of this function continue if function[0] in enabled_functions: #Find text is enabled setattr(self, function[0], functools.partial(enabled_function, function[0])) elif function[0] in disabled_functions: #Disabled functions should be skipped, they are probably already #implemented by the TextDiffer continue else: #Unimplemented functions should display an error message setattr(self, function[0], functools.partial(uniplemented_function, function[0])) def mousePressEvent(self, event): """Overloaded mouse click event""" #Execute the superclass mouse click event super().mousePressEvent(event) #Set focus to the clicked editor self.setFocus() #Set the last focused widget to the parent basic widget self.main_form.last_focused_widget = self._parent data.print_log("Stored \"{:s}\" as last focused widget".format( self._parent.name)) #Hide the function wheel if it is shown self.main_form.view.hide_all_overlay_widgets() # Reset the click&drag context menu action components.ActionFilter.clear_action() def setFocus(self): """Overridden focus event""" #Execute the superclass focus function super().setFocus() #Check indication self.main_form.view.indication_check() #Focus the last focused editor self.focused_editor.setFocus() def init_margin(self, editor, marker_unique, marker_unique_symbol, marker_similar, marker_similar_symbol): """Initialize margin for coloring lines showing diff symbols""" editor.setMarginWidth(0, "0") #Setting the margin width to 0 makes the marker colour the entire line #to the marker background color editor.setMarginWidth(1, "00") editor.setMarginWidth(2, 0) editor.setMarginType(0, data.QsciScintilla.TextMargin) editor.setMarginType(1, data.QsciScintilla.SymbolMargin) editor.setMarginType(2, data.QsciScintilla.SymbolMargin) #I DON'T KNOW THE ENTIRE LOGIC BEHIND MARKERS AND MARGINS! If you set #something wrong in the margin mask, the markers on a different margin don't appear! #http://www.scintilla.org/ScintillaDoc.html#SCI_SETMARGINMASKN editor.setMarginMarkerMask(1, ~data.QsciScintillaBase.SC_MASK_FOLDERS) editor.setMarginMarkerMask(2, 0x0) def init_markers(self): """Initialize all markers for showing diff symbols""" #Set the images image_scale_size = functions.create_size(16, 16) image_unique_1 = functions.create_pixmap( 'tango_icons/diff-unique-1.png') image_unique_2 = functions.create_pixmap( 'tango_icons/diff-unique-2.png') image_similar = functions.create_pixmap('tango_icons/diff-similar.png') #Scale the images to a smaller size image_unique_1 = image_unique_1.scaled(image_scale_size) image_unique_2 = image_unique_2.scaled(image_scale_size) image_similar = image_similar.scaled(image_scale_size) #Markers for editor 1 self.marker_unique_1 = self.editor_1.markerDefine( data.QsciScintillaBase.SC_MARK_BACKGROUND, 0) self.marker_unique_symbol_1 = self.editor_1.markerDefine( image_unique_1, 1) self.marker_similar_1 = self.editor_1.markerDefine( data.QsciScintillaBase.SC_MARK_BACKGROUND, 2) self.marker_similar_symbol_1 = self.editor_1.markerDefine( image_similar, 3) #Set background colors only for the background markers self.editor_1.setMarkerBackgroundColor(self.Indicator_Unique_1_Color, self.marker_unique_1) self.editor_1.setMarkerBackgroundColor(self.Indicator_Similar_Color, self.marker_similar_1) #Margins for editor 1 self.init_margin(self.editor_1, self.marker_unique_1, self.marker_unique_symbol_1, self.marker_similar_1, self.marker_similar_symbol_1) #Markers for editor 2 self.marker_unique_2 = self.editor_2.markerDefine( data.QsciScintillaBase.SC_MARK_BACKGROUND, 0) self.marker_unique_symbol_2 = self.editor_2.markerDefine( image_unique_2, 1) self.marker_similar_2 = self.editor_2.markerDefine( data.QsciScintillaBase.SC_MARK_BACKGROUND, 2) self.marker_similar_symbol_2 = self.editor_2.markerDefine( image_similar, 3) #Set background colors only for the background markers self.editor_2.setMarkerBackgroundColor(self.Indicator_Unique_2_Color, self.marker_unique_2) self.editor_2.setMarkerBackgroundColor(self.Indicator_Similar_Color, self.marker_similar_2) #Margins for editor 2 self.init_margin(self.editor_2, self.marker_unique_2, self.marker_unique_symbol_2, self.marker_similar_2, self.marker_similar_symbol_2) def init_indicator(self, editor, indicator, color): """Set the indicator settings""" editor.indicatorDefine(data.QsciScintillaBase.INDIC_ROUNDBOX, indicator) editor.setIndicatorForegroundColor(color, indicator) editor.SendScintilla(data.QsciScintillaBase.SCI_SETINDICATORCURRENT, indicator) def init_editor(self, editor): """Initialize all of the PlainEditor settings for difference displaying""" editor.setLexer(None) editor.setUtf8(True) editor.setIndentationsUseTabs(False) editor.setFont(self.DEFAULT_FONT) editor.setBraceMatching(data.QsciScintilla.SloppyBraceMatch) editor.setMatchedBraceBackgroundColor(data.QColor(255, 153, 0)) editor.setAcceptDrops(False) editor.setEolMode(settings.Editor.end_of_line_mode) editor.setReadOnly(True) editor.savable = data.CanSave.NO def set_margin_text(self, editor, line, text): """Set the editor's margin text at the selected line""" editor.setMarginText(line, text, self.MARGIN_STYLE) def set_line_indicator(self, editor, line, indicator_index): """Set the editor's selected line color""" #Set the indicator if indicator_index == self.INDICATOR_UNIQUE_1: self.init_indicator(editor, self.INDICATOR_UNIQUE_1, self.Indicator_Unique_1_Color) elif indicator_index == self.INDICATOR_UNIQUE_2: self.init_indicator(editor, self.INDICATOR_UNIQUE_2, self.Indicator_Unique_2_Color) elif indicator_index == self.INDICATOR_SIMILAR: self.init_indicator(editor, self.INDICATOR_SIMILAR, self.Indicator_Similar_Color) #Color the line background scintilla_command = data.QsciScintillaBase.SCI_INDICATORFILLRANGE start = editor.positionFromLineIndex(line, 0) length = editor.lineLength(line) editor.SendScintilla(scintilla_command, start, length) def compare(self, text_1, text_2): """ Compare two text strings and display the difference !! This function uses Python's difflib which is not 100% accurate !! """ #Store the original text self.text_1 = text_1 self.text_2 = text_2 text_1_list = text_1.split("\n") text_2_list = text_2.split("\n") #Create the difference differer = difflib.Differ() list_sum = list(differer.compare(text_1_list, text_2_list)) #Assemble the two lists of strings that will be displayed in each editor list_1 = [] line_counter_1 = 1 line_numbering_1 = [] line_styling_1 = [] list_2 = [] line_counter_2 = 1 line_numbering_2 = [] line_styling_2 = [] #Flow control flags skip_next = False store_next = False for i, line in enumerate(list_sum): if store_next == True: store_next = False list_2.append(line[2:]) line_numbering_2.append(str(line_counter_2)) line_counter_2 += 1 line_styling_2.append(self.INDICATOR_SIMILAR) elif skip_next == False: if line.startswith(" "): #The line is the same in both texts list_1.append(line[2:]) line_numbering_1.append(str(line_counter_1)) line_counter_1 += 1 line_styling_1.append(None) list_2.append(line[2:]) line_numbering_2.append(str(line_counter_2)) line_counter_2 += 1 line_styling_2.append(None) elif line.startswith("- "): #The line is unique to text 1 list_1.append(line[2:]) line_numbering_1.append(str(line_counter_1)) line_counter_1 += 1 line_styling_1.append(self.INDICATOR_UNIQUE_1) list_2.append("") line_numbering_2.append("") line_styling_2.append(None) elif line.startswith("+ "): #The line is unique to text 2 list_1.append("") line_numbering_1.append("") line_styling_1.append(None) list_2.append(line[2:]) line_numbering_2.append(str(line_counter_2)) line_counter_2 += 1 line_styling_2.append(self.INDICATOR_UNIQUE_2) elif line.startswith("? "): #The line is similar if (list_sum[i - 1].startswith("- ") and len(list_sum) > (i + 1) and list_sum[i + 1].startswith("+ ") and len(list_sum) > (i + 2) and list_sum[i + 2].startswith("? ")): """ Line order: - ... ? ... + ... ? ... """ #Lines have only a few character difference, skip the #first '?' and handle the next '?' as a "'- '/'+ '/'? '" sequence pass elif list_sum[i - 1].startswith("- "): #Line in text 1 has something added """ Line order: - ... ? ... + ... """ line_styling_1[len(line_numbering_1) - 1] = self.INDICATOR_SIMILAR list_2.pop() line_numbering_2.pop() line_styling_2.pop() store_next = True elif list_sum[i - 1].startswith("+ "): #Line in text 2 has something added """ Line order: - ... + ... ? ... """ list_1.pop() line_numbering_1.pop() line_styling_1.pop() line_styling_1[len(line_numbering_1) - 1] = self.INDICATOR_SIMILAR pop_index_2 = (len(line_numbering_2) - 1) - 1 list_2.pop(pop_index_2) line_numbering_2.pop(pop_index_2) line_styling_2.pop() line_styling_2.pop() line_styling_2.append(self.INDICATOR_SIMILAR) else: skip_next = False #Display the results self.editor_1.setText("\n".join(list_1)) self.editor_2.setText("\n".join(list_2)) #Set margins and style for both editors for i, line in enumerate(line_numbering_1): self.set_margin_text(self.editor_1, i, line) line_styling = line_styling_1[i] if line_styling != None: if line_styling == self.INDICATOR_SIMILAR: self.editor_1.markerAdd(i, self.marker_similar_1) self.editor_1.markerAdd(i, self.marker_similar_symbol_1) else: self.editor_1.markerAdd(i, self.marker_unique_1) self.editor_1.markerAdd(i, self.marker_unique_symbol_1) for i, line in enumerate(line_numbering_2): self.set_margin_text(self.editor_2, i, line) line_styling = line_styling_2[i] if line_styling != None: if line_styling == self.INDICATOR_SIMILAR: self.editor_2.markerAdd(i, self.marker_similar_2) self.editor_2.markerAdd(i, self.marker_similar_symbol_2) else: self.editor_2.markerAdd(i, self.marker_unique_2) self.editor_2.markerAdd(i, self.marker_unique_symbol_2) #Check if there were any differences if (any(line_styling_1) == False and any(line_styling_2) == False): self.main_form.display.repl_display_message( "No differences between texts.", message_type=data.MessageType.SUCCESS) else: #Count the number of differences difference_counter_1 = 0 #Similar line count is the same in both editor line stylings similarity_counter = 0 for diff in line_styling_1: if diff != None: if diff == self.INDICATOR_SIMILAR: similarity_counter += 1 else: difference_counter_1 += 1 difference_counter_2 = 0 for diff in line_styling_2: if diff != None: if diff == self.INDICATOR_SIMILAR: #Skip the similar line, which were already counter above continue else: difference_counter_2 += 1 #Display the differences/similarities messages self.main_form.display.repl_display_message( "{:d} differences found in '{:s}'!".format( difference_counter_1, self.text_1_name), message_type=data.MessageType.DIFF_UNIQUE_1) self.main_form.display.repl_display_message( "{:d} differences found in '{:s}'!".format( difference_counter_2, self.text_2_name), message_type=data.MessageType.DIFF_UNIQUE_2) self.main_form.display.repl_display_message( "{:d} similarities found between documents!".format( similarity_counter, self.text_2_name), message_type=data.MessageType.DIFF_SIMILAR) self._update_margins() def find_next_unique_1(self): """Find and scroll to the first unique 1 difference""" self.focused_editor = self.editor_1 cursor_line, cursor_index = self.editor_1.getCursorPosition() next_unique_diff_line = self.editor_1.markerFindNext( cursor_line + 1, 0b0011) #Correct the line numbering to the 1..line_count display next_unique_diff_line += 1 self.editor_1.goto_line(next_unique_diff_line, skip_repl_focus=False) self.editor_2.goto_line(next_unique_diff_line, skip_repl_focus=False) #Check if we are back at the start of the document if next_unique_diff_line == 0: self.main_form.display.repl_display_message( "Scrolled back to the start of the document!", message_type=data.MessageType.DIFF_UNIQUE_1) self.main_form.display.write_to_statusbar( "Scrolled back to the start of the document!") def find_next_unique_2(self): """Find and scroll to the first unique 2 difference""" self.focused_editor = self.editor_2 cursor_line, cursor_index = self.editor_2.getCursorPosition() next_unique_diff_line = self.editor_2.markerFindNext( cursor_line + 1, 0b0011) #Correct the line numbering to the 1..line_count display next_unique_diff_line += 1 self.editor_1.goto_line(next_unique_diff_line, skip_repl_focus=False) self.editor_2.goto_line(next_unique_diff_line, skip_repl_focus=False) #Check if we are back at the start of the document if next_unique_diff_line == 0: self.main_form.display.repl_display_message( "Scrolled back to the start of the document!", message_type=data.MessageType.DIFF_UNIQUE_2) self.main_form.display.write_to_statusbar( "Scrolled back to the start of the document!") def find_next_similar(self): """Find and scroll to the first similar line""" self.focused_editor = self.editor_1 cursor_line, cursor_index = self.editor_1.getCursorPosition() next_unique_diff_line = self.editor_1.markerFindNext( cursor_line + 1, 0b1100) #Correct the line numbering to the 1..line_count display next_unique_diff_line += 1 self.editor_1.goto_line(next_unique_diff_line, skip_repl_focus=False) self.editor_2.goto_line(next_unique_diff_line, skip_repl_focus=False) #Check if we are back at the start of the document if next_unique_diff_line == 0: self.main_form.display.repl_display_message( "Scrolled back to the start of the document!", message_type=data.MessageType.DIFF_SIMILAR) self.main_form.display.write_to_statusbar( "Scrolled back to the start of the document!") def add_corner_buttons(self): # Unique 1 button self.icon_manipulator.add_corner_button( functions.create_icon("tango_icons/diff-unique-1.png"), "Scroll to next unique line\nin document: '{:s}'".format( self.text_1_name), self.find_next_unique_1) # Unique 2 button self.icon_manipulator.add_corner_button( functions.create_icon("tango_icons/diff-unique-2.png"), "Scroll to next unique line\nin document: '{:s}'".format( self.text_2_name), self.find_next_unique_2) # Similar button self.icon_manipulator.add_corner_button( functions.create_icon("tango_icons/diff-similar.png"), "Scroll to next similar line\nin both documents", self.find_next_similar) def set_theme(self, theme): def set_editor_theme(editor): if theme == themes.Air: editor.resetFoldMarginColors() elif theme == themes.Earth: editor.setFoldMarginColors(theme.FoldMargin.ForeGround, theme.FoldMargin.BackGround) editor.setMarginsForegroundColor(theme.LineMargin.ForeGround) editor.setMarginsBackgroundColor(theme.LineMargin.BackGround) editor.SendScintilla(data.QsciScintillaBase.SCI_STYLESETBACK, data.QsciScintillaBase.STYLE_DEFAULT, theme.Paper.Default) editor.SendScintilla(data.QsciScintillaBase.SCI_STYLESETBACK, data.QsciScintillaBase.STYLE_LINENUMBER, theme.LineMargin.BackGround) editor.SendScintilla(data.QsciScintillaBase.SCI_SETCARETFORE, theme.Cursor) editor.choose_lexer("text") set_editor_theme(self.editor_1) set_editor_theme(self.editor_2)
def __init__(self, parent, main_form, repl_master): #Initialize superclass, from which the current class is inherited, THIS MUST BE DONE SO THAT THE SUPERCLASS EXECUTES ITS __init__ !!!!!! super().__init__(parent) # Set default font self.setFont(data.get_current_font()) #Save the reference to the parent(main window) self._parent = parent self.main_form = main_form #Save the reference to the REPL object self.repl_master = repl_master #Hide the horizontal and show the vertical scrollbar self.SendScintilla(data.QsciScintillaBase.SCI_SETVSCROLLBAR, True) self.SendScintilla(data.QsciScintillaBase.SCI_SETHSCROLLBAR, False) #Hide the margin self.setMarginWidth(1, 0) #Autoindentation enabled when using "Enter" to indent to the same level as the previous line self.setAutoIndent(True) #Tabs are spaces by default self.setIndentationsUseTabs(False) #Set tab space indentation width self.setTabWidth(settings.Editor.tab_width) #Set encoding format to UTF-8 (Unicode) self.setUtf8(True) #Set brace matching self.setBraceMatching(data.QsciScintilla.SloppyBraceMatch) self.setMatchedBraceBackgroundColor(data.QColor(255, 153, 0)) #Tabs are spaces by default self.setIndentationsUseTabs(False) #Set backspace to delete by tab widths self.setBackspaceUnindents(True) #Disable drops self.setAcceptDrops(False) #Set line endings to be Unix style ("\n") self.setEolMode(settings.Editor.end_of_line_mode) #Set the initial zoom factor self.zoomTo(settings.Editor.zoom_factor) """ Functionality copied from the CustomEditor to copy some of the neede editing functionality like commenting, ... """ # Add the attributes needed to implement the line nist self.line_list = components.LineList(self, self.text()) # Add the needed functions assigned from the CustomEditor self.set_theme = functools.partial(CustomEditor.set_theme, self) self.set_line = functools.partial(CustomEditor.set_line, self) self.set_lines = functools.partial(CustomEditor.set_lines, self) self.toggle_comment_uncomment = functools.partial(CustomEditor.toggle_comment_uncomment, self) self.comment_line = functools.partial(CustomEditor.comment_line, self) self.comment_lines = functools.partial(CustomEditor.comment_lines, self) self.uncomment_line = functools.partial(CustomEditor.uncomment_line, self) self.uncomment_lines = functools.partial(CustomEditor.uncomment_lines, self) self.prepend_to_line = functools.partial(CustomEditor.prepend_to_line, self) self.prepend_to_lines = functools.partial(CustomEditor.prepend_to_lines, self) self.replace_line = functools.partial(CustomEditor.replace_line, self) self.get_line = functools.partial(CustomEditor.get_line, self) self.check_line_numbering = functools.partial(CustomEditor.check_line_numbering, self) self.text_to_list = functools.partial(CustomEditor.text_to_list, self) self.list_to_text = functools.partial(CustomEditor.list_to_text, self) # Add the function and connect the signal to update the line/column positions self.cursorPositionChanged.connect(self._signal_editor_cursor_change) #Set the lexer to python self.set_lexer() #Set the initial autocompletions self.update_autocompletions() #Setup the LineList object that will hold the custom editor text as a list of lines self.line_list = components.LineList(self, self.text()) self.textChanged.connect(self.text_changed)
class Nim(data.QsciLexerCustom): """ Custom lexer for the Nim programming language """ styles = { "Default" : 0, "Comment" : 1, "BasicKeyword" : 2, "TopKeyword" : 3, "String" : 4, "LongString" : 5, "Number" : 6, "Pragma" : 7, "Operator" : 8, "Unsafe" : 9, "Type" : 10, "DocumentationComment" : 11, "Definition" : 12, "Class" : 13, "KeywordOperator" : 14, "CharLiteral" : 15, "CaseOf" : 16, "UserKeyword" : 17, "MultilineComment" : 18, "MultilineDocumentation" : 19 } #Class variables default_color = data.QColor(data.theme.Font.Nim.Default[1]) default_paper = data.QColor(data.theme.Paper.Nim.Default) default_font = data.QFont(data.current_font_name, data.current_font_size) #Basic keywords and built-in procedures and templates basic_keyword_list = [ "as", "atomic", "bind", "sizeof", "break", "case", "continue", "converter", "discard", "distinct", "do", "echo", "elif", "else", "end", "except", "finally", "for", "from", "defined", "if", "interface", "iterator", "macro", "method", "mixin", "of", "out", "proc", "func", "raise", "ref", "result", "return", "template", "try", "inc", "dec", "new", "quit", "while", "with", "without", "yield", "true", "false", "assert", "min", "max", "newseq", "len", "pred", "succ", "contains", "cmp", "add", "del","deepcopy", "shallowcopy", "abs", "clamp", "isnil", "open", "reopen", "close","readall", "readfile", "writefile", "endoffile", "readline", "writeline", ] #Custom keyword created with templates/macros user_keyword_list = [ "class", "namespace", "property", ] #Keywords that define a proc-like definition def_keyword_list = ["proc", "method", "func", "template", "macro", "converter", "iterator"] #Keywords that can define blocks top_keyword_list = [ "block", "const", "export", "import", "include", "let", "static", "type", "using", "var", "when", ] #Keywords that might be unsafe/dangerous unsafe_keyword_list = [ "asm", "addr", "cast", "ptr", "pointer", "alloc", "alloc0", "allocshared0", "dealloc", "realloc", "nil", "gc_ref", "gc_unref", "copymem", "zeromem", "equalmem", "movemem", "gc_disable", "gc_enable", ] #Built-in types type_keyword_list = [ "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float", "float32", "float64", "bool", "char", "string", "cstring", "pointer", "ordinal", "ptr", "ref", "expr", "stmt", "typedesc", "void", "auto", "any", "untyped", "typed", "somesignedint", "someunsignedint", "someinteger", "someordinal", "somereal", "somenumber", "range", "array", "openarray", "varargs", "seq", "set", "slice", "shared", "guarded", "byte", "natural", "positive", "rootobj", "rootref", "rooteffect", "timeeffect", "ioeffect", "readioeffect", "writeioeffect", "execioeffect", "exception", "systemerror", "ioerror", "oserror", "libraryerror", "resourceexhaustederror", "arithmeticerror", "divbyzeroerror", "overflowerror", "accessviolationerror", "assertionerror", "valueerror", "keyerror", "outofmemerror", "indexerror", "fielderror", "rangeerror", "stackoverflowerror", "reraiseerror", "objectassignmenterror", "objectconversionerror", "floatingpointerror", "floatinvalidoperror", "floatdivbyzeroerror", "floatoverflowerror", "floatunderflowerror", "floatinexacterror", "deadthreaderror", "tresult", "endianness", "taintedstring", "libhandle", "procaddr", "byteaddress", "biggestint", "biggestfloat", "clong", "culong", "cchar", "cschar", "cshort", "cint", "csize", "clonglong", "cfloat", "cdouble", "clongdouble", "cuchar", "cushort", "cuint", "culonglong", "cstringarray", "pfloat32", "pfloat64", "pint64", "pint32", "gc_strategy", "pframe", "tframe", "file", "filemode", "filehandle", "thinstance", "aligntype", "refcount", "object", "tuple", "enum", ] #Sign operators operator_list = [ "=", "+", "-", "*", "/", "<", ">", "@", "$", ".", "~", "&", "%", "|", "!", "?", "^", ".", ":", "\"", ] #Keyword operators keyword_operator_list = [ "and", "or", "not", "xor", "shl", "shr", "div", "mod", "in", "notin", "is", "isnot", ] splitter = re.compile(r"(\{\.|\.\}|\#|\'|\"\"\"|\n|\s+|\w+|\W)") #Characters that autoindent one level on pressing Return/Enter autoindent_characters = [":", "="] def __init__(self, parent=None): """Overridden initialization""" #Initialize superclass super().__init__() #Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) #Reset autoindentation style self.setAutoIndentStyle(0) #Set the theme self.set_theme(data.theme) def language(self): return "Nim" def description(self, style): if style < len(self.styles): description = "Custom lexer for the Nim programming languages" else: description = "" return description def defaultStyle(self): return self.styles["Default"] def braceStyle(self): return self.styles["Default"] def defaultFont(self, style): return data.QFont(data.current_font_name, data.current_font_size) def set_theme(self, theme): for style in self.styles.keys(): # Papers self.setPaper( data.QColor(theme.Paper.Nim.Default), self.styles[style] ) # Fonts set_font(self, style, getattr(theme.Font.Nim, style)) def styleText(self, start, end): """ Overloaded method for styling text. NOTE: Very slow if done in Python! Using the Cython version is better. The fastest would probably be adding the lexer directly into the QScintilla source. Maybe never :-) """ #Style in pure Python, VERY SLOW! editor = self.editor() if editor is None: return #Initialize the styling self.startStyling(start) #Scintilla works with bytes, so we have to adjust the start and end boundaries text = bytearray(editor.text().lower(), "utf-8")[start:end].decode("utf-8") #Loop optimizations setStyling = self.setStyling basic_kw_list = self.basic_keyword_list user_kw_list = self.user_keyword_list def_kw_list = self.def_keyword_list top_kw_list = self.top_keyword_list unsafe_kw_list = self.unsafe_keyword_list operator_list = self.operator_list keyword_operator_list = self.keyword_operator_list type_kw_list = self.type_keyword_list DEF = self.styles["Default"] B_KWD = self.styles["BasicKeyword"] T_KWD = self.styles["TopKeyword"] COM = self.styles["Comment"] STR = self.styles["String"] L_STR = self.styles["LongString"] NUM = self.styles["Number"] MAC = self.styles["Pragma"] OPE = self.styles["Operator"] UNS = self.styles["Unsafe"] TYP = self.styles["Type"] D_COM = self.styles["DocumentationComment"] DEFIN = self.styles["Definition"] CLS = self.styles["Class"] KOP = self.styles["KeywordOperator"] CHAR = self.styles["CharLiteral"] OF = self.styles["CaseOf"] U_KWD = self.styles["UserKeyword"] M_COM = self.styles["MultilineComment"] M_DOC = self.styles["MultilineDocumentation"] #Initialize various states and split the text into tokens commenting = False doc_commenting = False multi_doc_commenting= False new_commenting = False stringing = False long_stringing = False char_literal = False pragmaing = False case_of = False cls_descrition = False tokens = [(token, len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text)] #Check if there is a style(comment, string, ...) stretching on from the previous line if start != 0: previous_style = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1) if previous_style == L_STR: long_stringing = True elif previous_style == MAC: pragmaing = True elif previous_style == M_COM: new_commenting = True elif previous_style == M_DOC: multi_doc_commenting = True #Style the tokens accordingly for i, token in enumerate(tokens): # print(str(token) + " " + str(i)) if commenting == True: #Continuation of comment setStyling(token[1], COM) #Check if comment ends if "\n" in token[0]: commenting = False elif doc_commenting == True: #Continuation of comment setStyling(token[1], D_COM) #Check if comment ends if "\n" in token[0]: doc_commenting = False elif new_commenting == True: #Continuation of comment setStyling(token[1], M_COM) #Check if comment ends if "#" in token[0] and "]" in tokens[i-1][0]: new_commenting = False elif multi_doc_commenting == True: #Continuation of comment setStyling(token[1], M_DOC) #Check if comment ends if "#" in token[0] and "#" in tokens[i-1][0] and "]" in tokens[i-2][0]: multi_doc_commenting = False elif stringing == True: #Continuation of a string setStyling(token[1], STR) #Check if string ends if token[0] == "\"" and (tokens[i-1][0] != "\\") or "\n" in token[0]: stringing = False elif long_stringing == True: #Continuation of a string setStyling(token[1], L_STR) #Check if string ends if token[0] == "\"\"\"": long_stringing = False elif char_literal == True: #Check if string ends if ("\n" in token[0] or " " in token[0] or "(" in token[0] or ")" in token[0] or "," in token[0] or token[0] in operator_list): #Do not color the separator setStyling(token[1], DEF) char_literal = False elif token[0] == "'": #Continuation of a character setStyling(token[1], CHAR) char_literal = False else: setStyling(token[1], CHAR) elif pragmaing == True: #Continuation of a string setStyling(token[1], MAC) #Check if string ends if token[0] == ".}": pragmaing = False elif case_of == True: #'Case of' parameter if token[0] == ":" or "\n" in token[0]: setStyling(token[1], DEF) case_of = False else: setStyling(token[1], OF) elif cls_descrition == True: #Class/namespace description if token[0] == ":" or "\n" in token[0]: setStyling(token[1], DEF) cls_descrition = False else: setStyling(token[1], CLS) elif token[0] == "\"\"\"": #Start of a multi line (long) string setStyling(token[1], L_STR) long_stringing = True elif token[0] == "{.": #Start of a multi line (long) string setStyling(token[1], MAC) pragmaing = True elif token[0] == "\"": #Start of a string setStyling(token[1], STR) stringing = True elif token[0] == "'": #Start of a string setStyling(token[1], CHAR) char_literal = True elif token[0] in basic_kw_list: #Basic keyword setStyling(token[1], B_KWD) try: if ((token[0] == "of" and "\n" in tokens[i-2][0]) or ((token[0] == "of" and "\n" in tokens[i-1][0]))): #Start of a CASE case_of = True except IndexError: case_of = False elif token[0] in user_kw_list: #User keyword setStyling(token[1], U_KWD) elif token[0] in top_kw_list: #Top keyword setStyling(token[1], T_KWD) elif token[0] in unsafe_kw_list: #Unsafe/danger keyword setStyling(token[1], UNS) elif token[0] in operator_list: #Operator setStyling(token[1], OPE) elif token[0] in keyword_operator_list: #Operator setStyling(token[1], KOP) elif token[0] in type_kw_list: #Operator setStyling(token[1], TYP) elif token[0] == "#": #Start of a comment or documentation comment if len(tokens) > i+2 and tokens[i+1][0] == "#" and tokens[i+2][0] == "[": setStyling(token[1], M_DOC) multi_doc_commenting = True elif len(tokens) > i+1 and tokens[i+1][0] == "#": setStyling(token[1], D_COM) doc_commenting = True elif len(tokens) > i+1 and tokens[i+1][0] == "[": setStyling(token[1], M_COM) new_commenting = True else: setStyling(token[1], COM) commenting = True elif (i > 1) and (("\n" in tokens[i-2][0]) or (" " in tokens[i-2][0])) and (tokens[i-1][0] == "of"): #Case of statement case_of = True setStyling(token[1], OF) elif functions.is_number(token[0][0]): #Number #Check only the first character, because Nim has those weird constants e.g.: 12u8, ...) setStyling(token[1], NUM) elif ((i > 1) and (tokens[i-2][0] in user_kw_list) and token[0][0].isalpha()): #Class-like definition setStyling(token[1], CLS) cls_descrition = True elif (((i > 1) and (tokens[i-2][0] in def_kw_list and tokens[i-1][0] != "(") and token[0][0].isalpha()) or ((i > 2) and (tokens[i-3][0] in def_kw_list and tokens[i-1][0] == '`') and token[0][0].isalpha())): #Proc-like definition setStyling(token[1], DEFIN) else: setStyling(token[1], DEF)
def __init__(self, name, picture, scale_factor=1.0, function=None, key_combination=None, starting_position=None, end_position=None, parent=None): super().__init__(parent) self.name = name self.scale_factor = scale_factor self.key_combination = key_combination self.animating = False self.starting_position = starting_position self.end_position = end_position self.disable() self.properties = {} # Set default font self.setFont(data.get_current_font()) # Button image self.button_image = data.QPixmap( os.path.join(data.resources_directory, picture)) adjusted_size = self.DEFAULT_SIZE * self.scale_factor self.button_image = self.button_image.scaled( functions.create_size( math.ceil(adjusted_size), math.ceil(adjusted_size), ), transformMode=data.Qt.SmoothTransformation) width, height = components.HexBuilder.get_single_hex_size( adjusted_size, 2) def create_base_image(): hex_image = data.QImage( functions.create_size(width, height), data.QImage.Format_ARGB32_Premultiplied) hex_image.fill(data.Qt.transparent) qpainter = data.QPainter(hex_image) qpainter.setRenderHints(data.QPainter.Antialiasing | data.QPainter.TextAntialiasing | data.QPainter.SmoothPixmapTransform) hb = components.HexBuilder( qpainter, (width / 2, height / 2), self.DEFAULT_SIZE, self.scale_factor, fill_color=data.theme.Settings_Hex_Background, line_width=2, line_color=data.QColor(64, 64, 64), ) hb.create_grid(False) qpainter.end() return data.QPixmap.fromImage(hex_image) self.hex_image = create_base_image() self.hex_image = self.hex_image.scaled( functions.create_size( math.ceil(self.hex_image.size().width() * self.scale_factor), math.ceil(self.hex_image.size().height() * self.scale_factor), ), transformMode=data.Qt.SmoothTransformation) # Green hex background def create_color_image(color): hex_image = data.QImage( functions.create_size(width, height), data.QImage.Format_ARGB32_Premultiplied) hex_image.fill(data.Qt.transparent) qpainter = data.QPainter(hex_image) qpainter.setRenderHints(data.QPainter.Antialiasing | data.QPainter.TextAntialiasing | data.QPainter.SmoothPixmapTransform) hb = components.HexBuilder( qpainter, (width / 2, height / 2), self.DEFAULT_SIZE, self.scale_factor, fill_color=color, line_width=0, line_color=data.QColor(0, 0, 0), ) hb.create_grid(False) qpainter.end() return data.QPixmap.fromImage(hex_image) self.hex_image_green = create_color_image(data.QColor( 138, 226, 52)) self.hex_image_green = self.hex_image_green.scaled( functions.create_size( math.ceil(self.hex_image_green.size().width() * self.scale_factor) - 1, math.ceil(self.hex_image_green.size().height() * self.scale_factor) - 1, ), transformMode=data.Qt.SmoothTransformation) # Red hex background self.hex_image_red = create_color_image(data.QColor(239, 41, 41)) self.hex_image_red = self.hex_image_red.scaled( functions.create_size( math.ceil(self.hex_image_red.size().width() * self.scale_factor) - 1, math.ceil(self.hex_image_red.size().height() * self.scale_factor) - 1, ), transformMode=data.Qt.SmoothTransformation) scaled_size = functions.create_size( self.hex_image.size().width(), self.hex_image.size().height(), ) image = data.QImage( scaled_size, data.QImage.Format_ARGB32_Premultiplied, ) image.fill(data.Qt.transparent) button_painter = data.QPainter(image) button_painter.setCompositionMode( data.QPainter.CompositionMode_SourceOver) button_painter.setOpacity(1.0) # Adjust inner button positioning according to the scale x = (self.hex_image.width() - self.button_image.width()) / 2 y = (self.hex_image.height() - self.button_image.height()) / 2 button_painter.drawPixmap(0, 0, self.hex_image) button_painter.drawPixmap(x, y, self.button_image) button_painter.end() # Set properites self.setParent(parent) self.setPixmap(data.QPixmap.fromImage(image)) self.setGeometry(0, 0, int(image.width() * self.scale_factor), int(image.height() * self.scale_factor)) self.setMask(self.hex_image.mask()) self.setScaledContents(True) # Set the non-enlarged dimensions self.original_size = (self.geometry().width(), self.geometry().height()) # Set the initial color state self.current_color = "default"
class RouterOS(data.QsciLexerCustom): """ Custom lexer for the RouterOS syntax for MikroTik routers (WinBox) """ styles = { "Default": 0, "Operator": 1, "Comment": 2, "Keyword1": 3, "Keyword2": 4, "Keyword3": 5, } #Class variables default_color = data.QColor(data.theme.Font.RouterOS.Default[1]) default_paper = data.QColor(data.theme.Paper.RouterOS.Default) default_font = data.QFont('Courier', 10) #All keywords, operators, ... operator_list = [ '!', '$', '(', ')', ',', ':', '[', ']', '{', '|', '}', "=" ] comment_list = ['#'] keyword1_list = [ 'ac-name', 'accept', 'accessible-via-web', 'account-local-traffic', 'accounting', 'action', 'active-flow-timeout', 'active-mode', 'add-default-route', 'address-list', 'address-pool', 'address', 'addresses-per-mac', 'admin-mac', 'advertise-dns', 'advertise-mac-address', 'ageing-time', 'allocate-udp-ports-from', 'allow-disable-external-interface', 'allow-guests', 'allow-remote-requests', 'allow', 'allowed-number', 'always-from-cache', 'area-id', 'area', 'arp', 'as', 'audio-max', 'audio-min', 'audio-monitor', 'auth-algorithms', 'auth-method', 'auth', 'authenticate', 'authentication-password', 'authentication-protocol', 'authentication-types', 'authentication', 'authoritative', 'auto-mac', 'auto-negotiation', 'auto-send-supout', 'automatic-supout', 'autonomous', 'backup-allowed', 'baud-rate', 'bidirectional-timeout', 'blank-interval', 'bootp-support', 'bridge-mode', 'bridge', 'broadcast-addresses', 'broadcast', 'bsd-syslog', 'cable-settings', 'cache-administrator', 'cache-entries', 'cache-hit-dscp', 'cache-max-ttl', 'cache-on-disk', 'cache-size', 'certificate', 'chain', 'change-tcp-mss', 'channel-time', 'channel', 'check-interval', 'cipher', 'client-to-client-reflection', 'comment', 'connection-bytes', 'connection-idle-timeout', 'connection-mark', 'connection-state', 'contact', 'contrast', 'cpu', 'data-bits', 'default-ap-tx-limit', 'default-authentication', 'default-client-tx-limit', 'default-forwarding', 'default-group', 'default-profile', 'default-route-distance', 'default', 'dh-group', 'dhcp-option', 'dial-on-demand', 'directory', 'disable-running-check', 'disabled', 'disk-file-count', 'disk-file-name', 'disk-lines-per-file', 'disk-stop-on-full', 'display-time', 'distance', 'distribute-default', 'distribute-for-default-route', 'dns-name', 'dns-server', 'domain', 'dpd-interval', 'dpd-maximum-failures', 'dst-address-list', 'dst-address', 'dst-delta', 'dst-end', 'dst-port', 'dst-start', 'dynamic-label-range', 'e', 'eap-methods', 'enabled', 'enc-algorithm', 'enc-algorithms', 'encryption-password', 'encryption-protocol', 'engine-id', 'exchange-mode', 'exclude-groups', 'file-limit', 'file-name', 'filter-ip-address', 'filter-ip-protocol', 'filter-mac-address', 'filter-mac-protocol', 'filter-mac', 'filter-port', 'filter-stream', 'flow-control', 'forward-delay', 'frame-size', 'frames-per-second', 'from', 'full-duplex', 'garbage-timer', 'gateway-class', 'gateway-keepalive', 'gateway-selection', 'gateway', 'generate-policy', 'generic-timeout', 'group-ciphers', 'group-key-update', 'hash-algorithm', 'hide-ssid', 'hop-limit', 'hotspot-address', 'html-directory', 'http-cookie-lifetime', 'http-proxy', 'i', 'icmp-timeout', 'idle-timeout', 'ignore-as-path-len', 'in-filter', 'in-interface', 'inactive-flow-timeout', 'instance', 'interface', 'interfaces', 'interim-update', 'interval', 'ipsec-protocols', 'jump-target', 'keep-max-sms', 'keepalive-timeout', 'kind', 'l2mtu', 'latency-distribution-scale', 'lease-time', 'level', 'lifebytes', 'lifetime', 'line-count', 'list', 'local-address', 'location', 'log-prefix', 'login-by', 'login', 'loop-detect', 'lsr-id', 'mac-address', 'managed-address-configuration', 'management-protection-key', 'management-protection', 'manycast', 'max-cache-size', 'max-client-connections', 'max-connections', 'max-fresh-time', 'max-message-age', 'max-mru', 'max-mtu', 'max-server-connections', 'max-sessions', 'max-station-count', 'max-udp-packet-size', 'memory-limit', 'memory-lines', 'memory-scroll', 'memory-stop-on-full', 'metric-bgp', 'metric-connected', 'metric-default', 'metric-ospf', 'metric-other-ospf', 'metric-rip', 'metric-static', 'min-rx', 'mode', 'mpls-mtu', 'mq-pfifo-limit', 'mrru', 'mtu', 'multi-cpu', 'multicast', 'multiple-channels', 'multiplier', 'my-id-user-fqdn', 'name', 'nat-traversal', 'netmask', 'network', 'new-connection-mark', 'new-packet-mark', 'new-routing-mark', 'no-ping-delay', 'note', 'ntp-server', 'on-backup', 'on-master', 'only-headers', 'only-one', 'origination-interval', 'other-configuration', 'out-filter', 'out-interface', 'page-refresh', 'parent-proxy-port', 'parent-proxy', 'parent', 'parity', 'passthrough', 'password', 'path-vector-limit', 'paypal-accept-pending', 'paypal-allowed', 'paypal-secure-response', 'permissions', 'pfifo-limit', 'pfs-group', 'policy', 'port', 'ports', 'preemption-mode', 'preferred-gateway', 'preferred-lifetime', 'prefix', 'primary-ntp', 'primary-server', 'priority', 'profile', 'propagate-ttl', 'proposal-check', 'proposal', 'proprietary-extensions', 'protocol-mode', 'protocol', 'query-interval', 'query-response-interval', 'queue', 'quick-leave', 'ra-delay', 'ra-interval', 'ra-lifetime', 'radius-eap-accounting', 'radius-mac-accounting', 'radius-mac-authentication', 'radius-mac-caching', 'radius-mac-format', 'radius-mac-mode', 'ranges', 'rate-limit', 'reachable-time', 'read-access', 'read-only', 'receive-all', 'receive-enabled', 'receive-errors', 'red-avg-packet', 'red-burst', 'red-limit', 'red-max-threshold', 'red-min-threshold', 'redistribute-bgp', 'redistribute-connected', 'redistribute-ospf', 'redistribute-other-bgp', 'redistribute-other-ospf', 'redistribute-rip', 'redistribute-static', 'remember', 'remote-address', 'remote-ipv6-prefix-pool', 'remote-port', 'remote', 'require-client-certificate', 'retransmit-interval', 'router-id', 'routing-mark', 'routing-table', 'sa-dst-address', 'sa-src-address', 'scope', 'secondary-ntp', 'secondary-server', 'secret', 'security-profile', 'security', 'send-initial-contact', 'serialize-connections', 'servers', 'service-name', 'set-system-time', 'sfq-allot', 'sfq-perturb', 'shared-users', 'show-at-login', 'show-dummy-rule', 'signup-allowed', 'sip-direct-media', 'skin', 'smtp-server', 'source', 'speed', 'split-user-domain', 'src-address-list', 'src-address', 'src-port', 'ssid-all', 'ssid', 'state-after-reboot', 'static-algo-0', 'static-algo-1', 'static-algo-2', 'static-algo-3', 'static-key-0', 'static-key-1', 'static-key-2', 'static-key-3', 'static-sta-private-algo', 'static-sta-private-key', 'static-transmit-key', 'status-autorefresh', 'stop-bits', 'store-every', 'store-leases-disk', 'streaming-enabled', 'streaming-max-rate', 'streaming-server', 'supplicant-identity', 'switch-to-spt-bytes', 'switch-to-spt-interval', 'switch-to-spt', 'syslog-facility', 'syslog-severity', 'target-scope', 'target', 'tcp-close-timeout', 'tcp-close-wait-timeout', 'tcp-established-timeout', 'tcp-fin-wait-timeout', 'tcp-last-ack-timeout', 'tcp-syn-received-timeout', 'tcp-syn-sent-timeout', 'tcp-syncookie', 'tcp-time-wait-timeout', 'term', 'test-id', 'threshold', 'time-zone-name', 'time-zone', 'timeout-timer', 'timeout', 'tls-certificate', 'tls-mode', 'to-addresses', 'topics', 'transmit-hold-count', 'transparent-proxy', 'transport-address', 'trap-generators', 'trap-target', 'trap-version', 'ttl', 'tunnel', 'type', 'udp-stream-timeout', 'udp-timeout', 'unicast-ciphers', 'update-stats-interval', 'update-timer', 'use-compression', 'use-encryption', 'use-explicit-null', 'use-ip-firewall-for-pppoe', 'use-ip-firewall-for-vlan', 'use-ip-firewall', 'use-ipv6', 'use-mpls', 'use-peer-dns', 'use-peer-ntp', 'use-radius', 'use-service-tag', 'use-vj-compression', 'user', 'v3-protocol', 'valid-lifetime', 'vcno', 'verify-client-certificate', 'version', 'vlan-id', 'vrid', 'watch-address', 'watchdog-timer', 'wds-cost-range', 'wds-default-bridge', 'wds-default-cost', 'wds-ignore-ssid', 'wds-mode', 'wins-server', 'wmm-support', 'wpa-pre-shared-key', 'wpa2-pre-shared-key', 'write-access', 'burst-limit', 'burst-threshold', 'burst-time', 'limit-at', 'priority', 'max-limit', 'tree', 'packet-mark', 'value', 'option', 'target-addresses', 'queue', 'encryption-password', 'always-broadcast', 'connect-to', 'adaptive-noise-immunity', 'compression', 'band', 'country', 'frequency', 'hw-retries', 'rate-selection', 'scan-list' ] keyword2_list = [ 'set', 'add', 'delay', 'do', 'error', 'execute', 'find', 'for', 'foreach', 'global', 'if', 'len', 'local', 'nothing', 'parse', 'pick', 'put', 'resolve', 'set', 'time', 'toarray', 'tobool', 'toid', 'toip', 'toip6', 'tonum', 'tostr', 'totime', 'typeof', 'while', 'beep', 'export', 'import', 'led', 'password', 'ping', 'quit', 'redo', 'setup', 'undo', 'print', 'detail', 'file', 'log', 'info', 'get', 'warning', 'critical' ] keyword3_list = [ '/', 'aaa', 'accounting', 'address', 'address-list', 'align', 'area', 'bandwidth-server', 'bfd', 'bgp', 'bridge', 'client', 'clock', 'community', 'config', 'connection', 'console', 'customer', 'default', 'dhcp-client', 'dhcp-server', 'discovery', 'dns', 'e-mail', 'ethernet', 'filter', 'firewall', 'firmware', 'gps', 'graphing', 'group', 'hardware', 'health', 'hotspot', 'identity', 'igmp-proxy', 'incoming', 'instance', 'interface0', 'ip', 'ipsec', 'ipv6', 'irq', 'l2tp-server', 'lcd', 'ldp', 'logging', 'mac-server', 'mac-winbox', 'mangle', 'manual', 'mirror', 'mme', 'mpls', 'nat', 'nd', 'neighbor', 'network', 'note', 'ntp', 'ospf', 'ospf-v3', 'ovpn-server', 'page', 'peer', 'pim', 'ping', 'policy', 'pool', 'port', 'ppp', 'pppoe-client', 'pptp-server', 'prefix', 'profile', 'proposal', 'proxy', 'queue', 'radius', 'resource', 'rip', 'ripng', 'route', 'routing', 'screen', 'script', 'security-profiles', 'server', 'service', 'service-port', 'settings', 'shares', 'smb', 'sms', 'sniffer', 'snmp', 'snooper', 'socks', 'sstp-server', 'system', 'tool', 'tracking', 'traffic-flow', 'traffic-generator', 'type', 'upgrade', 'upnp', 'user', 'user-manager', 'users', 'vlan', 'vrrp', 'watchdog', 'web-access', 'wireless', 'pptp', 'pppoe', 'lan', 'wan', 'layer7-protocol', 'eth-', 'wlan-', 'bridge-' ] splitter = re.compile(r"(\{\.|\.\}|\#|\'|\"\"\"|\n|\s+|\w+|\W)") #Characters that autoindent one level on pressing Return/Enter autoindent_characters = [":", "="] def __init__(self, parent=None): """Overridden initialization""" #Initialize superclass super().__init__() #Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) #Reset autoindentation style self.setAutoIndentStyle(0) #Set the theme self.set_theme(data.theme) def language(self): return "RouterOS" def description(self, style): if style < len(self.styles): description = "Custom lexer for the RouterOS syntax by MikroTik" else: description = "" return description def set_theme(self, theme): for style in self.styles: # Papers self.setPaper(data.QColor(theme.Paper.RouterOS.Default), self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.RouterOS, style)) def styleText(self, start, end): """ Overloaded method for styling text. NOTE: Very slow if done in Python! Using the Cython version is better. The fastest would probably be adding the lexer directly into the QScintilla source. Maybe never :-) """ #Style in pure Python, VERY SLOW! editor = self.editor() if editor is None: return #Initialize the styling self.startStyling(start) #Scintilla works with bytes, so we have to adjust the start and end boundaries text = bytearray(editor.text().lower(), "utf-8")[start:end].decode("utf-8") #Loop optimizations setStyling = self.setStyling operator_list = self.operator_list comment_list = self.comment_list keyword1_list = self.keyword1_list keyword2_list = self.keyword2_list keyword3_list = self.keyword3_list DEFAULT = self.styles["Default"] OPERATOR = self.styles["Operator"] COMMENT = self.styles["Comment"] KEYWORD1 = self.styles["Keyword1"] KEYWORD2 = self.styles["Keyword2"] KEYWORD3 = self.styles["Keyword3"] #Initialize various states and split the text into tokens commenting = False tokens = [(token, len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text)] #Style the tokens accordingly for i, token in enumerate(tokens): if commenting == True: #Continuation of comment setStyling(token[1], COMMENT) #Check if comment ends if "\n" in token[0]: commenting = False elif token[0] in operator_list: setStyling(token[1], OPERATOR) elif token[0] in comment_list: setStyling(token[1], COMMENT) commenting = True elif token[0] in keyword1_list: setStyling(token[1], KEYWORD1) elif token[0] in keyword2_list: setStyling(token[1], KEYWORD2) elif token[0] in keyword3_list: setStyling(token[1], KEYWORD3) else: setStyling(token[1], DEFAULT)
class CiCode(data.QsciLexerCustom): """ Custom lexer for the Citect CiCode programming language """ class Sequence: def __init__(self, start, stop_sequences, stop_characters, style, add_to_style): self.start = start self.stop_sequences = stop_sequences self.stop_characters = stop_characters self.style = style self.add_to_style = add_to_style styles = { "Default" : 0, "Comment" : 1, "MultilineComment" : 2, "Keyword" : 3, "BuiltInFunction" : 4, "String" : 5, "Number" : 6, "Operator" : 7, "Function" : 8, } # Class variables default_color = data.QColor(data.theme.Font.CiCode.Default[1]) default_paper = data.QColor(data.theme.Paper.CiCode.Default) default_font = data.QFont(data.current_font_name, data.current_font_size) keyword_list = [ "function", "end", "if", "else", "do", "then", "while", "for", "mod", "bitand", "bitor", "bitxor", "and", "or", "not", "bitand", "bitor", "bitxor", "global", "public", "private", "return", ] type_list = [ "string", "object", "int", "real", "quality", "timestamp", ] builtin_function_list = [ "abs", "acccontrol", "accumbrowseclose", "accumbrowsefirst", "accumbrowsegetfield", "accumbrowsenext", "accumbrowsenumrecords", "accumbrowseopen", "accumbrowseprev", "alarmack", "alarmackrec", "alarmacktag", "alarmactive", "alarmcatgetformat", "alarmclear", "alarmclearrec", "alarmcleartag", "alarmcomment", "alarmcount", "alarmcountequipment", "alarmcountlist", "alarmdelete", "alarmdisable", "alarmdisablerec", "alarmdisabletag", "alarmdsp", "alarmdspclusteradd", "alarmdspclusterinuse", "alarmdspclusterremove", "alarmdsplast", "alarmdspnext", "alarmdspprev", "alarmenable", "alarmenablerec", "alarmenabletag", "alarmeventque", "alarmfilterclose", "alarmfiltereditappend", "alarmfiltereditclose", "alarmfiltereditcommit", "alarmfiltereditfirst", "alarmfiltereditlast", "alarmfiltereditnext", "alarmfiltereditopen", "alarmfiltereditprev", "alarmfiltereditset", "alarmfilterform", "alarmfilteropen", "alarmfirstcatrec", "alarmfirstprirec", "alarmfirsttagrec", "alarmgetdelay", "alarmgetdelayrec", "alarmgetdsp", "alarmgetfieldrec", "alarmgetfiltername", "alarmgetinfo", "alarmgetorderbykey", "alarmgetthreshold", "alarmgetthresholdrec", "alarmhelp", "alarmnextcatrec", "alarmnextprirec", "alarmnexttagrec", "alarmnotifyvarchange", "alarmqueryfirstrec", "alarmquerynextrec", "alarmresetquery", "alarmsetdelay", "alarmsetdelayrec", "alarmsetinfo", "alarmsetquery", "alarmsetthreshold", "alarmsetthresholdrec", "alarmsplit", "alarmsumappend", "alarmsumcommit", "alarmsumdelete", "alarmsumfind", "alarmsumfirst", "alarmsumget", "alarmsumlast", "alarmsumnext", "alarmsumprev", "alarmsumset", "alarmsumsplit", "alarmsumtype", "almbrowseack", "almbrowseclear", "almbrowseclose", "almbrowsedisable", "almbrowseenable", "almbrowsefirst", "almbrowsegetfield", "almbrowsenext", "almbrowsenumrecords", "almbrowseopen", "almbrowseprev", "almsummaryack", "almsummaryclear", "almsummaryclose", "almsummarycommit", "almsummarydelete", "almsummarydeleteall", "almsummarydisable", "almsummaryenable", "almsummaryfirst", "almsummarygetfield", "almsummarylast", "almsummarynext", "almsummarynumrecords", "almsummaryopen", "almsummaryprev", "almsummarysetfieldvalue", "almtagsack", "almtagsclear", "almtagsclose", "almtagsdisable", "almtagsenable", "almtagsfirst", "almtagsgetfield", "almtagsnext", "almtagsnumrecords", "almtagsopen", "almtagsprev", "anbyname", "arccos", "arcsin", "arctan", "areacheck", "ass", "asschain", "asschainpage", "asschainpopup", "asschainwin", "asschainwinfree", "assgetproperty", "assgetscale", "assinfo", "assinfoex", "asspage", "asspopup", "assscalestr", "asstag", "asstitle", "assvartags", "asswin", "assert", "beep", "callevent", "chainevent", "chartostr", "citectcolourtopackedrgb", "citectinfo", "clipcopy", "clippaste", "clipreadln", "clipsetmode", "clipwriteln", "clusteractivate", "clusterdeactivate", "clusterfirst", "clustergetname", "clusterisactive", "clusternext", "clusterservertypes", "clustersetname", "clusterstatus", "clusterswapactive", "codesetmode", "codetrace", "comclose", "comopen", "comread", "comreset", "comwrite", "cos", "createcontrolobject", "createobject", "ddeexec", "ddepost", "dderead", "ddewrite", "ddehexecute", "ddehgetlasterror", "ddehinitiate", "ddehpoke", "ddehreadln", "ddehrequest", "ddehsetmode", "ddehterminate", "ddehwriteln", "dllcall", "dllcallex", "dllclose", "dllopen", "date", "dateadd", "dateday", "dateinfo", "datemonth", "datesub", "dateweekday", "dateyear", "debugbreak", "debugmsg", "debugmsgset", "degtorad", "delayshutdown", "devappend", "devclose", "devcontrol", "devcurr", "devdelete", "devdisable", "deveof", "devfind", "devfirst", "devflush", "devgetfield", "devhistory", "devinfo", "devmodify", "devnext", "devopen", "devopengrp", "devprev", "devprint", "devread", "devreadln", "devrecno", "devseek", "devsetfield", "devsize", "devwrite", "devwriteln", "devzap", "displayruntimemanager", "dllclasscallmethod", "dllclasscreate", "dllclassdispose", "dllclassgetproperty", "dllclassisvalid", "dllclasssetproperty", "driverinfo", "dspancreatecontrolobject", "dspanfree", "dspangetarea", "dspangetmetadata", "dspangetmetadataat", "dspangetpos", "dspangetprivilege", "dspaninrgn", "dspaninfo", "dspanmove", "dspanmoverel", "dspannew", "dspannewrel", "dspansetmetadata", "dspansetmetadataat", "dspbar", "dspbmp", "dspbutton", "dspbuttonfn", "dspchart", "dspcol", "dspdel", "dspdelayrenderbegin", "dspdelayrenderend", "dspdirty", "dsperror", "dspfile", "dspfilegetinfo", "dspfilegetname", "dspfilescroll", "dspfilesetname", "dspfont", "dspfonthnd", "dspfullscreen", "dspgetanbottom", "dspgetancur", "dspgetanextent", "dspgetanfirst", "dspgetanfrompoint", "dspgetanheight", "dspgetanleft", "dspgetannext", "dspgetanright", "dspgetantop", "dspgetanwidth", "dspgetenv", "dspgetmouse", "dspgetmouseover", "dspgetnearestan", "dspgetparentan", "dspgetslider", "dspgettip", "dspgraybutton", "dspinfo", "dspinfodestroy", "dspinfofield", "dspinfonew", "dspinfovalid", "dspisbuttongray", "dspkernel", "dspmci", "dspmarkermove", "dspmarkernew", "dspplaysound", "dsppopupconfigmenu", "dsppopupmenu", "dsprichtext", "dsprichtextedit", "dsprichtextenable", "dsprichtextgetinfo", "dsprichtextload", "dsprichtextpgscroll", "dsprichtextprint", "dsprichtextsave", "dsprichtextscroll", "dsprubend", "dsprubmove", "dsprubsetclip", "dsprubstart", "dspsetslider", "dspsettip", "dspsettooltipfont", "dspstatus", "dspstr", "dspsym", "dspsymanm", "dspsymanmex", "dspsymatsize", "dsptext", "dsptipmode", "dsptrend", "dsptrendinfo", "dumpkernel", "engtogeneric", "entercriticalsection", "equipbrowseclose", "equipbrowsefirst", "equipbrowsegetfield", "equipbrowsenext", "equipbrowsenumrecords", "equipbrowseopen", "equipbrowseprev", "equipcheckupdate", "equipgetproperty", "equipsetproperty", "equipstatebrowseclose", "equipstatebrowsefirst", "equipstatebrowsegetfield", "equipstatebrowsenext", "equipstatebrowsenumrecords", "equipstatebrowseopen", "equipstatebrowseprev", "errcom", "errdrv", "errgethw", "errhelp", "errinfo", "errlog", "errmsg", "errset", "errsethw", "errsetlevel", "errtrap", "exec", "executedtspkg", "exp", "ftpclose", "ftpfilecopy", "ftpfilefind", "ftpfilefindclose", "ftpopen", "fact", "fileclose", "filecopy", "filedelete", "fileeof", "fileexist", "filefind", "filefindclose", "filegettime", "filemakepath", "fileopen", "fileprint", "fileread", "filereadblock", "filereadln", "filerename", "filerichtextprint", "fileseek", "filesettime", "filesize", "filesplitpath", "filewrite", "filewriteblock", "filewriteln", "fmtclose", "fmtfieldhnd", "fmtgetfield", "fmtgetfieldcount", "fmtgetfieldhnd", "fmtgetfieldname", "fmtgetfieldwidth", "fmtopen", "fmtsetfield", "fmtsetfieldhnd", "fmttostr", "formactive", "formaddlist", "formbutton", "formcheckbox", "formcombobox", "formcurr", "formdestroy", "formedit", "formfield", "formgetcurrinst", "formgetdata", "formgetinst", "formgettext", "formgoto", "formgroupbox", "forminput", "formlistaddtext", "formlistbox", "formlistdeletetext", "formlistselecttext", "formnew", "formnumpad", "formopenfile", "formpassword", "formposition", "formprompt", "formradiobutton", "formread", "formsaveasfile", "formsecurepassword", "formselectprinter", "formsetdata", "formsetinst", "formsettext", "formwndhnd", "fullname", "fuzzyclose", "fuzzygetcodevalue", "fuzzygetshellvalue", "fuzzyopen", "fuzzysetcodevalue", "fuzzysetshellvalue", "fuzzytrace", "getarea", "getbluevalue", "getenv", "getevent", "getgreenvalue", "getlanguage", "getlogging", "getpriv", "getredvalue", "getwintitle", "grpclose", "grpdelete", "grpfirst", "grpin", "grpinsert", "grpmath", "grpname", "grpnext", "grpopen", "grptostr", "halt", "hextostr", "highbyte", "highword", "htmlhelp", "hwalarmque", "iodevicecontrol", "iodeviceinfo", "iodevicestats", "infoform", "infoforman", "input", "inttoreal", "inttostr", "iserror", "kercmd", "kernelqueuelength", "kerneltableinfo", "kerneltableitemcount", "keyallowcursor", "keybs", "keydown", "keyget", "keygetcursor", "keyleft", "keymove", "keypeek", "keyput", "keyputstr", "keyreplay", "keyreplayall", "keyright", "keysetcursor", "keysetseq", "keyup", "languagefiletranslate", "leavecriticalsection", "libalarmfilterform", "ln", "log", "login", "loginform", "logout", "logoutidle", "lowbyte", "lowword", "mailerror", "maillogoff", "maillogon", "mailread", "mailsend", "makecitectcolour", "max", "menugetchild", "menugetfirstchild", "menugetgenericnode", "menugetnextchild", "menugetpagenode", "menugetparent", "menugetprevchild", "menugetwindownode", "menunodeaddchild", "menunodegetproperty", "menunodehascommand", "menunodeisdisabled", "menunodeishidden", "menunoderemove", "menunoderuncommand", "menunodesetdisabledwhen", "menunodesethiddenwhen", "menunodesetproperty", "menureload", "message", "min", "msgbrdcst", "msgclose", "msggetcurr", "msgopen", "msgrpc", "msgread", "msgstate", "msgwrite", "multimonitorstart", "multisignatureform", "multisignaturetagwrite", "name", "oledatetotime", "objectassociateevents", "objectassociatepropertywithtag", "objectbyname", "objecthasinterface", "objectisvalid", "objecttostr", "onevent", "packedrgb", "packedrgbtocitectcolour", "pagealarm", "pageback", "pagedisabled", "pagedisplay", "pageexists", "pagefile", "pagefileinfo", "pageforward", "pagegetint", "pagegetstr", "pagegoto", "pagehardware", "pagehistorydspmenu", "pagehistoryempty", "pagehome", "pageinfo", "pagelast", "pagelistcount", "pagelistcurrent", "pagelistdelete", "pagelistdisplay", "pagelistinfo", "pagemenu", "pagenext", "pagepeekcurrent", "pagepeeklast", "pagepoplast", "pagepopup", "pageprev", "pageprocessanalyst", "pageprocessanalystpens", "pagepushlast", "pagerecall", "pagerichtextfile", "pagesoe", "pageselect", "pagesetint", "pagesetstr", "pagesummary", "pagetask", "pagetransformcoords", "pagetrend", "pagetrendex", "parameterget", "parameterput", "pathtostr", "pi", "plotclose", "plotdraw", "plotfile", "plotgetmarker", "plotgrid", "plotinfo", "plotline", "plotmarker", "plotopen", "plotscalemarker", "plotsetmarker", "plottext", "plotxyline", "pow", "print", "printfont", "println", "processanalystloadfile", "processanalystpopup", "processanalystselect", "processanalystsetpen", "processanalystwin", "processisclient", "processisserver", "processrestart", "productinfo", "projectinfo", "projectrestartget", "projectrestartset", "projectset", "prompt", "pulse", "qualitycreate", "qualitygetpart", "qualityisbad", "qualityiscontrolinhibit", "qualityisgood", "qualityisoverride", "qualityisuncertain", "qualitysetpart", "qualitytostr", "queclose", "quelength", "queopen", "quepeek", "queread", "quewrite", "radtodeg", "rand", "reread", "realtostr", "repgetcluster", "repgetcontrol", "repsetcontrol", "report", "round", "soearchive", "soedismount", "soeeventadd", "soemount", "spcalarms", "spcclientinfo", "spcgethistogramtable", "spcgetsubgrouptable", "spcplot", "spcprocessxrsget", "spcprocessxrsset", "spcsetlimit", "spcspeclimitget", "spcspeclimitset", "spcsubgroupsizeget", "spcsubgroupsizeset", "sqlappend", "sqlbegintran", "sqlcall", "sqlcancel", "sqlclose", "sqlcommit", "sqlconnect", "sqlcreate", "sqldisconnect", "sqldispose", "sqlend", "sqlerrmsg", "sqlexec", "sqlfieldinfo", "sqlgetfield", "sqlgetrecordset", "sqlgetscalar", "sqlinfo", "sqlisnullfield", "sqlnext", "sqlnofields", "sqlnumchange", "sqlnumfields", "sqlopen", "sqlparamsclearall", "sqlparamssetasint", "sqlparamssetasreal", "sqlparamssetasstring", "sqlprev", "sqlquerycreate", "sqlquerydispose", "sqlrollback", "sqlrowcount", "sqlset", "sqltraceoff", "sqltraceon", "schdclose", "schdconfigclose", "schdconfigfirst", "schdconfiggetfield", "schdconfignext", "schdconfignumrecords", "schdconfigopen", "schdconfigprev", "schdfirst", "schdnext", "schdnumrecords", "schdopen", "schdprev", "schdspecialadd", "schdspecialclose", "schdspecialdelete", "schdspecialfirst", "schdspecialgetfield", "schdspecialitemadd", "schdspecialitemclose", "schdspecialitemdelete", "schdspecialitemfirst", "schdspecialitemgetfield", "schdspecialitemmodify", "schdspecialitemnext", "schdspecialitemnumrecords", "schdspecialitemopen", "schdspecialitemprev", "schdspecialmodify", "schdspecialnext", "schdspecialnumrecords", "schdspecialopen", "schdspecialprev", "scheduleitemadd", "scheduleitemdelete", "scheduleitemmodify", "scheduleitemsetrepeat", "semclose", "semopen", "semsignal", "semwait", "sendkeys", "serialkey", "serverbrowseclose", "serverbrowsefirst", "serverbrowsegetfield", "serverbrowsenext", "serverbrowsenumrecords", "serverbrowseopen", "serverbrowseprev", "serverdumpkernel", "servergetproperty", "serverinfo", "serverinfoex", "serverisonline", "serverrpc", "serverreload", "serverrestart", "servicegetlist", "setarea", "setevent", "setlanguage", "setlogging", "shutdown", "shutdownform", "shutdownmode", "sign", "sin", "sleep", "sleepms", "sqrt", "strcalcwidth", "strclean", "strfill", "strformat", "strgetchar", "strleft", "strlength", "strlower", "strmid", "strpad", "strright", "strsearch", "strsetchar", "strtochar", "strtodate", "strtofmt", "strtogrp", "strtohex", "strtoint", "strtolines", "strtolocaltext", "strtoperiod", "strtoreal", "strtotime", "strtotimestamp", "strtovalue", "strtrim", "strtruncfont", "strtruncfonthnd", "strupper", "strword", "subscriptionaddcallback", "subscriptiongetattribute", "subscriptiongetinfo", "subscriptiongetquality", "subscriptiongettag", "subscriptiongettimestamp", "subscriptiongetvalue", "subscriptionremovecallback", "switchconfig", "systime", "systimedelta", "tablelookup", "tablemath", "tableshift", "tagbrowseclose", "tagbrowsefirst", "tagbrowsegetfield", "tagbrowsenext", "tagbrowsenumrecords", "tagbrowseopen", "tagbrowseprev", "tagdebug", "tagdebugform", "tageventformat", "tageventqueue", "taggetproperty", "taggetscale", "taginfo", "taginfoex", "tagrdbreload", "tagramp", "tagread", "tagreadex", "tagresolve", "tagscalestr", "tagsetoverridebad", "tagsetoverridegood", "tagsetoverridequality", "tagsetoverrideuncertain", "tagsubscribe", "tagunresolve", "tagunsubscribe", "tagwrite", "tagwriteeventque", "tagwriteintarray", "tagwriterealarray", "tan", "taskcluster", "taskgetsignal", "taskhnd", "taskkill", "tasknew", "tasknewex", "taskresume", "tasksetsignal", "tasksuspend", "testrandomwave", "testsawwave", "testsinwave", "testsquarewave", "testtriangwave", "time", "timecurrent", "timehour", "timeinfo", "timeinttotimestamp", "timemidnight", "timemin", "timesec", "timeset", "timetostr", "timeutcoffset", "timestampadd", "timestampcreate", "timestampcurrent", "timestampdifference", "timestampformat", "timestampgetpart", "timestampsub", "timestamptostr", "timestamptotimeint", "toggle", "tracemsg", "trenddspcursorcomment", "trenddspcursorscale", "trenddspcursortag", "trenddspcursortime", "trenddspcursorvalue", "trendgetan", "trendpopup", "trendrun", "trendsetdate", "trendsetscale", "trendsetspan", "trendsettime", "trendsettimebase", "trendwin", "trendzoom", "trnaddhistory", "trnbrowseclose", "trnbrowsefirst", "trnbrowsegetfield", "trnbrowsenext", "trnbrowsenumrecords", "trnbrowseopen", "trnbrowseprev", "trnclientinfo", "trncompareplot", "trndelhistory", "trndelete", "trnecho", "trneventgettable", "trneventgettablems", "trneventsettable", "trneventsettablems", "trnexportcsv", "trnexportclip", "trnexportdbf", "trnexportdde", "trnflush", "trngetbufevent", "trngetbuftime", "trngetbufvalue", "trngetcluster", "trngetcursorevent", "trngetcursormstime", "trngetcursorpos", "trngetcursortime", "trngetcursorvalue", "trngetcursorvaluestr", "trngetdefscale", "trngetdisplaymode", "trngetevent", "trngetformat", "trngetgatedvalue", "trngetinvalidvalue", "trngetmstime", "trngetmode", "trngetpen", "trngetpencomment", "trngetpenfocus", "trngetpenno", "trngetperiod", "trngetscale", "trngetscalestr", "trngetspan", "trngettable", "trngettime", "trngetunits", "trninfo", "trnisvalidvalue", "trnnew", "trnplot", "trnprint", "trnsamplesconfigured", "trnscroll", "trnselect", "trnsetcursor", "trnsetcursorpos", "trnsetdisplaymode", "trnsetevent", "trnsetpen", "trnsetpenfocus", "trnsetperiod", "trnsetscale", "trnsetspan", "trnsettable", "trnsettime", "usercreate", "usercreateform", "userdelete", "usereditform", "userinfo", "userlogin", "userpassword", "userpasswordexpirydays", "userpasswordform", "usersetstr", "userupdaterecord", "userverify", "variablequality", "variabletimestamp", "verifyprivilegeform", "verifyprivilegetagwrite", "version", "whoami", "wincopy", "winfile", "winfree", "wingetfocus", "wingetwndhnd", "wingoto", "winmode", "winmove", "winnew", "winnewat", "winnext", "winnumber", "winpos", "winprev", "winprint", "winprintfile", "winselect", "winsetname", "winsize", "winstyle", "wintitle", "wndfind", "wndgetfileprofile", "wndgetprofile", "wndhelp", "wndinfo", "wndmonitorinfo", "wndputfileprofile", "wndputprofile", "wndshow", "wndviewer", "xmlclose", "xmlcreate", "xmlgetattribute", "xmlgetattributecount", "xmlgetattributename", "xmlgetattributevalue", "xmlgetchild", "xmlgetchildcount", "xmlgetparent", "xmlgetroot", "xmlnodeaddchild", "xmlnodefind", "xmlnodegetname", "xmlnodegetvalue", "xmlnoderemove", "xmlnodesetvalue", "xmlopen", "xmlsave", "xmlsetattribute", "_objectcallmethod", "_objectgetproperty", "_objectsetproperty", ] operator_list = [ "=", "+", "-", "*", "/", "<", ">", "@", "$", ".", "~", "&", "%", "|", "!", "?", "^", ".", ":", "\"", ] func = Sequence('function', [], ['(', '\n'], styles["Function"], False) strseq = Sequence('"', ['"', '\n'], [], styles["String"], True) comment = Sequence('//', [], ['\n'], styles["Comment"], True) mcomment = Sequence('/*', ['*/'], [], styles["MultilineComment"], True) sequence_lists = [strseq, comment, mcomment, func] multiline_sequence_list = [mcomment] sequence_start_chrs = [x.start for x in sequence_lists] # splitter = re.compile(r"(/\*|\*/|\\\"|\(\*|\*\)|//|\n|\"+|\'+|\#+|\s+|\w+|\W)") splitter = re.compile(r"(/\*|\*/|\(\*|\*\)|//|\n|\"+|\'+|\#+|\s+|\w+|\W)") # Characters that autoindent one level on pressing Return/Enter autoindent_characters = ["then", "do", ")"] def __init__(self, parent=None): """ Overridden initialization """ # Initialize superclass super().__init__() # Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) # Reset autoindentation style self.setAutoIndentStyle(0) # Set the theme self.set_theme(data.theme) def language(self): return "CiCode" def description(self, style): if style < len(self.styles): description = "Custom lexer for the CiCode programming languages" else: description = "" return description def defaultStyle(self): return self.styles["Default"] def braceStyle(self): return self.styles["Default"] def defaultFont(self, style): return data.QFont(data.current_font_name, data.current_font_size) def set_theme(self, theme): for style in self.styles: # Papers self.setPaper( data.QColor(theme.Paper.CiCode.Default), self.styles[style] ) # Fonts lexers.set_font(self, style, getattr(theme.Font.CiCode, style)) def styleText(self, start, end): """ Overloaded method for styling text. """ # Style in pure Python, VERY SLOW! editor = self.editor() if editor is None: return # Initialize the styling self.startStyling(start) # Scintilla works with bytes, so we have to adjust # the start and end boundaries text = bytearray(editor.text().lower(), "utf-8")[start:end].decode("utf-8") # Loop optimizations setStyling = self.setStyling DEFAULT = self.styles["Default"] COMMENT = self.styles["Comment"] KEYWORD = self.styles["Keyword"] BUILTINFUNCTION = self.styles["BuiltInFunction"] STRING = self.styles["String"] NUMBER = self.styles["Number"] OPERATOR = self.styles["Operator"] # Initialize various states and split the text into tokens stringing = False commenting = False multiline_commenting = False sequence = None tokens = [ (token.lower(), len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text) ] # Check if there is a style(comment, string, ...) stretching on from the previous line if start != 0: previous_style = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1) for i in self.multiline_sequence_list: if previous_style == i.style: sequence = i break # Style the tokens accordingly for i, token in enumerate(tokens): token_name = token[0] token_length = token[1] if sequence != None: if token_name in sequence.stop_sequences: if sequence.add_to_style == True: setStyling(token_length, sequence.style) else: setStyling(token_length, self.styles["Default"]) sequence = None elif any(ch in token_name for ch in sequence.stop_characters): if sequence.add_to_style == True: setStyling(token_length, sequence.style) else: setStyling(token_length, self.styles["Default"]) sequence = None else: setStyling(token_length, sequence.style) elif token_name in self.sequence_start_chrs: for i in self.sequence_lists: if token_name == i.start: if i.stop_sequences == [] and i.stop_characters == []: # Skip styling if both stop sequences and stop characters are empty setStyling(token_length, i.style) else: # Style the sequence and store the reference to it sequence = i if i.add_to_style == True: setStyling(token_length, sequence.style) else: if token_name in self.keyword_list: setStyling(token_length, KEYWORD) elif token_name in self.type_list: setStyling(token_length, KEYWORD) elif token_name in self.operator_list: setStyling(token_length, OPERATOR) elif token_name[0].isdigit(): setStyling(token_length, NUMBER) elif token_name in self.builtin_function_list: setStyling(token_length, BUILTINFUNCTION) else: setStyling(token_length, self.styles["Default"]) break elif token_name in self.keyword_list: setStyling(token_length, KEYWORD) elif token_name in self.type_list: setStyling(token_length, KEYWORD) elif token_name in self.operator_list: setStyling(token_length, OPERATOR) elif token_name[0].isdigit(): setStyling(token_length, NUMBER) elif token_name in self.builtin_function_list: setStyling(token_length, BUILTINFUNCTION) else: setStyling(token_length, DEFAULT)
def draw_line_hexagon_no_double_paint( self, position, line_width, line_color, paint_enabled=[True, True, True, True, True, True], shadow=False): qpainter = self.painter if line_width == 0: return pen = data.QPen(data.Qt.SolidLine) pen.setCapStyle(data.Qt.RoundCap) pen.setJoinStyle(data.Qt.RoundJoin) pen.setWidth(line_width) pen.setColor(line_color) qpainter.setPen(pen) hex_points = list( HexBuilder.generate_hexagon_points(self.edge_length, position)) x_correction = self.edge_length / 2 y_correction = self.edge_length / (2 * math.tan(math.radians(30))) hex_points = [(x - x_correction, y - y_correction) for x, y in hex_points] hex_lines = [] def line_test(in_line): DIFF = 3 line = in_line reversed_line = (line[1], line[0]) x1, y1 = line[0] x2, y2 = line[1] xr1, yr1 = reversed_line[0] xr2, yr2 = reversed_line[1] for l in self.stored_lines: xl1, yl1 = l[0] xl2, yl2 = l[1] if (abs(xl1 - x1) < DIFF and abs(yl1 - y1) < DIFF and abs(xl2 - x2) < DIFF and abs(yl2 - y2) < DIFF): if not (line in self.stored_lines): self.stored_lines.append(line) #self.stored_lines.append(reversed_line) return False elif (abs(xl1 - xr1) < DIFF and abs(yl1 - yr1) < DIFF and abs(xl2 - xr2) < DIFF and abs(yl2 - yr2) < DIFF): if not (reversed_line in self.stored_lines): self.stored_lines.append(line) #self.stored_lines.append(reversed_line) return False else: self.stored_lines.append(line) self.stored_lines.append(reversed_line) return True for i in range(len(hex_points)): if paint_enabled[i] == False: continue n = i + 1 if n > (len(hex_points) - 1): n = 0 if line_test((hex_points[i], hex_points[n])) == True: hex_lines.append( data.QLine(data.QPoint(*hex_points[i]), data.QPoint(*hex_points[n]))) if hex_lines: if shadow == True: shadow_0_color = data.QColor(line_color) shadow_0_color.setAlpha(64) shadow_1_color = data.QColor(line_color) shadow_1_color.setAlpha(128) pen.setWidth(line_width * 2.0) pen.setColor(shadow_0_color) qpainter.setPen(pen) qpainter.drawLines(*hex_lines) pen.setWidth(line_width * 1.5) pen.setColor(shadow_1_color) qpainter.setPen(pen) qpainter.drawLines(*hex_lines) pen.setWidth(line_width) pen.setColor(line_color) qpainter.setPen(pen) qpainter.drawLines(*hex_lines) else: qpainter.drawLines(*hex_lines)
class AWK(data.QsciLexerCustom): """ Custom lexer for the AWK programming languages """ styles = { "Default": 0, "Comment": 1, "Keyword": 2, "BuiltInVariable": 3, "BuiltInFunction": 4, "String": 5, "Number": 6, "Operator": 7, } # Class variables default_color = data.QColor(data.theme.Font.AWK.Default[1]) default_paper = data.QColor(data.theme.Paper.AWK.Default) default_font = data.QFont(data.current_font_name, data.current_font_size) keyword_list = [ "BEGIN", "delete", "for", "in", "printf", "END", "do", "function", "next", "return", "break", "else", "getline", "print", "while", "continue", "exit", "if", ] builtin_variable_list = [ "ARGC", "ARGV", "CONVFMT", "ENVIRON", "FILENAME", "FNR", "FS", "NF", "NR", "OFMT", "OFS", "ORS", "RLENGTH", "RS", "RSTART", "SUBSEP", ] builtin_function_list = [ "atan2", "index", "match", "sprintf", "substr", "close", "int", "rand", "sqrt", "system", "cos", "length", "sin", "srand", "tolower", "exp", "log", "split", "sub", "toupper", "gsub", ] operator_list = [ "=", "+", "-", "*", "/", "<", ">", "@", "$", ".", "~", "&", "%", "|", "!", "?", "^", ".", ":", "\"", ] splitter = re.compile(r"(\{\.|\.\}|\#|\'|\"\"\"|\n|\s+|\w+|\W)") # Characters that autoindent one level on pressing Return/Enter autoindent_characters = ["{"] def __init__(self, parent=None): """ Overridden initialization """ # Initialize superclass super().__init__() # Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) # Reset autoindentation style self.setAutoIndentStyle(0) # Set the theme self.set_theme(data.theme) def language(self): return "AWK" def description(self, style): if style < len(self.styles): description = "Custom lexer for the AWK programming languages" else: description = "" return description def defaultStyle(self): return self.styles["Default"] def braceStyle(self): return self.styles["Default"] def defaultFont(self, style): return data.QFont(data.current_font_name, data.current_font_size) def set_theme(self, theme): for style in self.styles: # Papers self.setPaper(data.QColor(theme.Paper.AWK.Default), self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.AWK, style)) def styleText(self, start, end): """ Overloaded method for styling text. """ # Style in pure Python, VERY SLOW! editor = self.editor() if editor is None: return # Initialize the styling self.startStyling(start) # Scintilla works with bytes, so we have to adjust # the start and end boundaries text = bytearray(editor.text(), "utf-8")[start:end].decode("utf-8") # Loop optimizations setStyling = self.setStyling operator_list = self.operator_list builtin_variable_list = self.builtin_variable_list builtin_function_list = self.builtin_function_list keyword_list = self.keyword_list DEFAULT = self.styles["Default"] COMMENT = self.styles["Comment"] KEYWORD = self.styles["Keyword"] BUILTINVARIABLE = self.styles["BuiltInVariable"] BUILTINFUNCTION = self.styles["BuiltInFunction"] STRING = self.styles["String"] NUMBER = self.styles["Number"] OPERATOR = self.styles["Operator"] # Initialize various states and split the text into tokens stringing = False commenting = False tokens = [(token, len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text)] # Style the tokens accordingly for i, token in enumerate(tokens): if commenting == True: # Continuation of comment setStyling(token[1], COMMENT) # Check if comment ends if "\n" in token[0]: commenting = False elif stringing == True: # Continuation of a string setStyling(token[1], STRING) # Check if string ends if (token[0] == "\"" and (tokens[i - 1][0] != "\\") or "\n" in token[0]): stringing = False elif token[0] == "#": setStyling(token[1], COMMENT) commenting = True elif token[0] == "\"": # Start of a string setStyling(token[1], STRING) stringing = True elif token[0] in operator_list: setStyling(token[1], OPERATOR) elif token[0] in keyword_list: setStyling(token[1], KEYWORD) elif token[0] in builtin_variable_list: setStyling(token[1], BUILTINVARIABLE) elif token[0] in builtin_function_list: setStyling(token[1], BUILTINFUNCTION) else: setStyling(token[1], DEFAULT)
class Ada(data.QsciLexerCustom): """Custom lexer for the Ada programming languages""" styles = { "Default": 0, "Comment": 1, "Keyword": 2, "String": 3, "Procedure": 4, "Number": 5, "Type": 6, "Package": 7 } #Class variables default_color = data.QColor(data.theme.Font.Ada.Default[1]) default_paper = data.QColor(data.theme.Paper.Ada.Default) default_font = data.QFont(data.current_font_name, data.current_font_size) keyword_list = [ "abort", "else", "new", "return", "abs", "elsif", "not", "reverse", "abstract", "end", "null", "accept", "entry", "select", "access", "exception", "of", "separate", "aliased", "exit", "or", "some", "all", "others", "subtype", "and", "for", "out", "synchronized", "array", "function", "overriding", "at", "tagged", "generic", "package", "task", "begin", "goto", "pragma", "terminate", "body", "private", "then", "if", "procedure", "type", "case", "in", "protected", "constant", "interface", "until", "is", "raise", "use", "declare", "range", "delay", "limited", "record", "when", "delta", "loop", "rem", "while", "digits", "renames", "with", "do", "mod", "requeue", "xor", ] splitter = re.compile(r"(\-\-|\s+|\w+|\W)") def __init__(self, parent=None): """Overridden initialization""" #Initialize superclass super().__init__() #Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) #Reset autoindentation style self.setAutoIndentStyle(0) #Set the theme self.set_theme(data.theme) def language(self): return "Ada" def description(self, style): if style <= 7: description = "Custom lexer for the Ada programming languages" else: description = "" return description def set_theme(self, theme): for style in self.styles: # Papers self.setPaper(data.QColor(theme.Paper.Ada.Default), self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.Ada, style)) def styleText(self, start, end): """ Overloaded method for styling text. NOTE: Very slow if done in Python! Using the Cython version is better. The fastest would probably be adding the lexer directly into the QScintilla source. Maybe never :-) """ #Get the global cython flag if lexers.cython_lexers_found == True: #Cython module found lexers.cython_lexers.style_ada(start, end, self, self.editor()) else: #Style in pure Python, VERY SLOW! editor = self.editor() if editor is None: return #Initialize the procedure/package counter pp_counter = [] #Initialize the styling self.startStyling(0) #Scintilla works with bytes, so we have to adjust the start and end boundaries text = bytearray(editor.text().lower(), "utf-8").decode("utf-8") #Loop optimizations setStyling = self.setStyling kw_list = self.keyword_list DEF = self.styles["Default"] KWD = self.styles["Keyword"] COM = self.styles["Comment"] STR = self.styles["String"] PRO = self.styles["Procedure"] NUM = self.styles["Number"] PAC = self.styles["Package"] # TYP = self.styles["Type"] #Initialize comment state and split the text into tokens commenting = False stringing = False tokens = [(token, len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text)] #Style the tokens accordingly for i, token in enumerate(tokens): if commenting == True: #Continuation of comment setStyling(token[1], COM) #Check if comment ends if "\n" in token[0]: commenting = False elif stringing == True: #Continuation of a string setStyling(token[1], STR) #Check if string ends if token[0] == "\"" or "\n" in token[0]: stringing = False elif token[0] == "\"": #Start of a string setStyling(token[1], STR) stringing = True elif token[0] in kw_list: #Keyword setStyling(token[1], KWD) elif token[0] == "--": #Start of a comment setStyling(token[1], COM) commenting = True elif i > 1 and tokens[i - 2][0] == "procedure": #Procedure name setStyling(token[1], PRO) #Mark the procedure if tokens[i + 1][0] != ";": pp_counter.append("PROCEDURE") elif i > 1 and (tokens[i - 2][0] == "package" or tokens[i - 2][0] == "body"): #Package name setStyling(token[1], PAC) #Mark the package pp_counter.append("PACKAGE") elif (i > 1 and tokens[i - 2][0] == "end") and (len(tokens) - 1 >= i + 1): #Package or procedure name end if len(pp_counter) > 0: if pp_counter.pop() == "PACKAGE": setStyling(token[1], PAC) else: setStyling(token[1], PRO) else: setStyling(token[1], DEF) elif functions.is_number(token[0]): #Number setStyling(token[1], NUM) else: setStyling(token[1], DEF)
def create_background_image(in_scale=1.0): """ Dinamically create the settings manipulator's background image """ # Check if the QPixmap has been created already if SettingsGuiManipulator.settings_background_image == None: scale = in_scale edge_length = 27 scaled_edge_diff = (edge_length - (edge_length * scale)) / edge_length back_color = data.theme.Settings_Background edge_color = data.QColor(data.theme.Settings_Hex_Edge) SettingsGuiManipulator.theme_name = data.theme.name def add_offset(offset): x_add = 64.0 y_add = 20.0 return (offset[0] + x_add, offset[1] + y_add) settings_background_image = data.QImage( functions.create_size(*SettingsGuiManipulator.DEFAULT_SIZE), data.QImage.Format_ARGB32_Premultiplied) settings_background_image.fill(data.Qt.transparent) # settings_background_image.fill(data.QColor(255,255,255)) qpainter = data.QPainter(settings_background_image) qpainter.setRenderHints(data.QPainter.Antialiasing | data.QPainter.TextAntialiasing | data.QPainter.SmoothPixmapTransform) # Corner options x = edge_length + 205 y = 1.8 * edge_length + 30 offset = (x, y) hb = components.HexBuilder( qpainter, offset, edge_length, scale, fill_color=back_color, line_width=2, line_color=edge_color, ) grid_list = [ (3, True), (4, True), (4, True), (4, True), (5, True), (1, True), ] hb.create_grid(*grid_list) # Label field last_step = hb.get_last_position() hb = components.HexBuilder( qpainter, offset, edge_length, scale, fill_color=data.theme.Settings_Label_Background, line_width=3, line_color=data.QColor(146, 146, 146), ) hb.set_first_position(last_step) hb.create_grid(5, 5, 0, 2, 0, 2, 3, 1, 0, 2, 3, 4) # Editor buttons offset = (90, 280) offset = add_offset(offset) row_length = 6 editor_button_count = 30 hb = components.HexBuilder( qpainter, offset, edge_length, scale, fill_color=back_color, line_width=2, line_color=edge_color, ) grid_list = hb.generate_square_grid_list(row_length, editor_button_count) hb.create_grid(*grid_list) # Editor edge hb.next_step_move(3) first_edge_hex_position = hb.get_last_position() hb = components.HexBuilder( qpainter, first_edge_hex_position, edge_length, scale, fill_color=back_color, line_width=2, line_color=edge_color, ) grid_list = [ (4, True), (5, True), (4, True), (5, True), (4, True), (5, True), (0, True), (0, True), (0, True), (0, True), (0, True), (1, True), (1, True), (2, True), (1, True), (2, True), (1, True), (2, True), (3, True), (3, True), (3, True), (3, True), (3, True), ] hb.create_grid(*grid_list) # General buttons offset = (offset[0] + (8 * hb.horizontal_step), offset[1] - (6 * hb.vertical_step)) row_length = 7 general_button_count = 56 hb = components.HexBuilder( qpainter, offset, edge_length, scale, fill_color=back_color, line_width=2, line_color=edge_color, ) grid_list = hb.generate_square_grid_list(row_length, general_button_count) hb.create_grid(*grid_list) # General edge hb.next_step_move(3) first_edge_hex_position = hb.get_last_position() hb = components.HexBuilder( qpainter, first_edge_hex_position, edge_length, scale, fill_color=back_color, line_width=2, line_color=edge_color, ) grid_list = [ (1, True), (2, True), (1, True), (2, True), (1, True), (2, True), (1, True), (0, True), (0, True), (0, True), (0, True), (0, True), (0, True), (0, True), (0, True), (5, True), (5, True), (4, True), (5, True), (4, True), (5, True), (4, True), (4, True), (3, True), (3, True), (3, True), (3, True), (3, True), (3, True), (3, True), (3, True), ] hb.create_grid(*grid_list) qpainter.end() SettingsGuiManipulator.settings_background_image = data.QPixmap.fromImage( settings_background_image) return SettingsGuiManipulator.settings_background_image
class CustomPython(data.QsciLexerCustom): class Sequence: def __init__(self, start, stop_sequences, stop_characters, style, add_to_style): self.start = start self.stop_sequences = stop_sequences self.stop_characters = stop_characters self.style = style self.add_to_style = add_to_style # Class variables # Lexer index counter for Nim styling _index = 0 index = 0 # Styles styles = { "Default": 0, "Comment": 1, "Number": 2, "DoubleQuotedString": 3, "SingleQuotedString": 4, "Keyword": 5, "TripleSingleQuotedString": 6, "TripleDoubleQuotedString": 7, "ClassName": 8, "FunctionMethodName": 9, "Operator": 10, "Identifier": 11, "CommentBlock": 12, "UnclosedString": 13, "HighlightedIdentifier": 14, "Decorator": 15, "CustomKeyword": 16, } default_color = data.QColor(data.theme.Font.Python.Default[1]) default_paper = data.QColor(data.theme.Paper.Python.Default) default_font = data.QFont(data.current_font_name, data.current_font_size) # Styling lists and characters keyword_list = list(set(keyword.kwlist + dir(builtins))) additional_list = [] sq = Sequence('\'', ['\'', '\n'], [], styles["SingleQuotedString"], True) dq = Sequence('"', ['"', '\n'], [], styles["DoubleQuotedString"], True) edq = Sequence('""', [], [], styles["DoubleQuotedString"], True) esq = Sequence('\'\'', [], [], styles["DoubleQuotedString"], True) tqd = Sequence('\'\'\'', ['\'\'\''], [], styles["TripleSingleQuotedString"], True) tqs = Sequence('"""', ['"""'], [], styles["TripleDoubleQuotedString"], True) cls = Sequence('class', [':'], ['(', '\n'], styles["ClassName"], False) defi = Sequence('def', [], ['('], styles["FunctionMethodName"], False) comment = Sequence('#', [], ['\n'], styles["Comment"], True) dcomment = Sequence('##', [], ['\n'], styles["CommentBlock"], True) decorator = Sequence('@', ['\n'], [' '], styles["Decorator"], True) sequence_lists = [ sq, dq, edq, esq, tqd, tqs, cls, defi, comment, dcomment, decorator ] multiline_sequence_list = [tqd, tqs] sequence_start_chrs = [x.start for x in sequence_lists] # Regular expression split sequence to tokenize text splitter = re.compile(r"(\\'|\\\"|\(\*|\*\)|\n|\"+|\'+|\#+|\s+|\w+|\W)") #Characters that autoindent one level on pressing Return/Enter autoindent_characters = [":"] def __init__(self, parent=None, additional_keywords=[]): """Overridden initialization""" # Initialize superclass super().__init__() # Set the lexer's index self.index = CustomPython._index CustomPython._index += 1 # Set the additional keywords self.additional_list = ["self"] self.additional_list.extend(additional_keywords) if lexers.nim_lexers_found == True: lexers.nim_lexers.python_set_keywords(self.index, additional_keywords) # Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) # Reset autoindentation style self.setAutoIndentStyle(0) # Set the theme self.set_theme(data.theme) def language(self): return "Python" def description(self, style): if style <= 16: description = "Custom lexer for the Python programming languages" else: description = "" return description def defaultStyle(self): return self.styles["Default"] def braceStyle(self): return self.styles["Default"] def defaultFont(self, style): return data.QFont(data.current_font_name, data.current_font_size) def set_theme(self, theme): for style in self.styles: # Papers paper = data.QColor(getattr(theme.Paper.Python, style)) self.setPaper(paper, self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.Python, style)) if lexers.nim_lexers_found == True: def __del__(self): lexers.nim_lexers.python_delete_keywords(self.index) def styleText(self, start, end): editor = self.editor() if editor is None: return # lexers.nim_lexers.python_style_text( # self.index, start, end, self, editor # ) lexers.nim_lexers.python_style_test(self.index, start, end) else: def styleText(self, start, end): editor = self.editor() if editor is None: return # Initialize the styling self.startStyling(start) # Scintilla works with bytes, so we have to adjust the start and end boundaries text = bytearray(editor.text(), "utf-8")[start:end].decode("utf-8") # Loop optimizations setStyling = self.setStyling # Initialize comment state and split the text into tokens sequence = None tokens = [(token, len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text)] # Check if there is a style(comment, string, ...) stretching on from the previous line if start != 0: previous_style = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1) for i in self.multiline_sequence_list: if previous_style == i.style: sequence = i break # Style the tokens accordingly for i, token in enumerate(tokens): # print(token[0].encode("utf-8")) token_name = token[0] token_length = token[1] if sequence != None: if token_name in sequence.stop_sequences: if sequence.add_to_style == True: setStyling(token_length, sequence.style) else: setStyling(token_length, self.styles["Default"]) sequence = None elif any(ch in token_name for ch in sequence.stop_characters): if sequence.add_to_style == True: setStyling(token_length, sequence.style) else: setStyling(token_length, self.styles["Default"]) sequence = None else: setStyling(token_length, sequence.style) elif token_name in self.sequence_start_chrs: for i in self.sequence_lists: if token_name == i.start: if i.stop_sequences == [] and i.stop_characters == []: # Skip styling if both stop sequences and stop characters are empty setStyling(token_length, i.style) else: # Style the sequence and store the reference to it sequence = i if i.add_to_style == True: setStyling(token_length, sequence.style) else: if token_name in self.keyword_list: setStyling(token_length, self.styles["Keyword"]) elif token_name in self.additional_list: setStyling( token_length, self.styles["CustomKeyword"]) else: setStyling(token_length, self.styles["Default"]) break elif token_name in self.keyword_list: setStyling(token_length, self.styles["Keyword"]) elif token_name in self.additional_list: setStyling(token_length, self.styles["CustomKeyword"]) elif token_name[0].isdigit(): setStyling(token_length, self.styles["Number"]) else: setStyling(token_length, self.styles["Default"])
class Oberon(data.QsciLexerCustom): """ Custom lexer for the Oberon/Oberon-2/Modula/Modula-2 programming languages """ styles = { "Default": 0, "Comment": 1, "Keyword": 2, "String": 3, "Procedure": 4, "Module": 5, "Number": 6, "Type": 7 } #Class variables default_color = data.QColor(data.theme.Font.Oberon.Default[1]) default_paper = data.QColor(data.theme.Paper.Oberon.Default) default_font = data.QFont('Courier', 10) keyword_list = [ 'ARRAY', 'IMPORT', 'RETURN', 'BEGIN', 'IN', 'THEN', 'BY', 'IS', 'TO', 'CASE', 'LOOP', 'Type', 'CONST', 'MOD', 'UNTIL', 'DIV', 'MODULE', 'VAR', 'DO', 'NIL', 'WHILE', 'ELSE', 'OF', 'WITH', 'ELSIF', 'OR', 'END', 'POINTER', 'EXIT', 'PROCEDURE', 'FOR', 'RECORD', 'IF', 'REPEAT' ] types_list = [ 'BOOLEAN', 'CHAR', 'SHORTINT', 'INTEGER', 'LONGINT', 'REAL', 'LONGREAL', 'SET' ] splitter = re.compile(r"(\(\*|\*\)|\s+|\w+|\W)") def __init__(self, parent=None): """Overridden initialization""" #Initialize superclass super().__init__() #Set the default style values self.setDefaultColor(self.default_color) self.setDefaultPaper(self.default_paper) self.setDefaultFont(self.default_font) #Reset autoindentation style self.setAutoIndentStyle(0) #Set the theme self.set_theme(data.theme) def language(self): return "Oberon/Modula-2/Component Pascal" def description(self, style): if style <= 7: description = "Custom lexer for the Oberon/Oberon-2/Modula/Modula-2/Component Pascal programming languages" else: description = "" return description def set_theme(self, theme): for style in self.styles: # Papers self.setPaper(data.QColor(theme.Paper.Oberon.Default), self.styles[style]) # Fonts lexers.set_font(self, style, getattr(theme.Font.Oberon, style)) def styleText(self, start, end): """ Overloaded method for styling text. NOTE: Very slow if done in Python! Using the Cython version is better. The fastest would probably be adding the lexer directly into the QScintilla source. Maybe never :-) """ #Get the global cython flag if lexers.cython_lexers_found == True: #Cython module found lexers.cython_lexers.style_oberon(start, end, self, self.editor()) else: #Style in pure Python, VERY SLOW! editor = self.editor() if editor is None: return #Initialize the styling self.startStyling(start) #Scintilla works with bytes, so we have to adjust the start and end boundaries text = bytearray(editor.text(), "utf-8")[start:end].decode("utf-8") #Loop optimizations setStyling = self.setStyling kw_list = self.keyword_list types_list = self.types_list DEF = self.styles["Default"] KWD = self.styles["Keyword"] COM = self.styles["Comment"] STR = self.styles["String"] PRO = self.styles["Procedure"] MOD = self.styles["Module"] NUM = self.styles["Number"] TYP = self.styles["Type"] #Initialize comment state and split the text into tokens commenting = False stringing = False tokens = [(token, len(bytearray(token, "utf-8"))) for token in self.splitter.findall(text)] #Check if there is a style(comment, string, ...) stretching on from the previous line if start != 0: previous_style = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1) if previous_style == COM: commenting = True #Style the tokens accordingly for i, token in enumerate(tokens): if commenting == True: #Continuation of comment setStyling(token[1], COM) #Check if comment ends if token[0] == "*)": commenting = False elif stringing == True: #Continuation of a string setStyling(token[1], STR) #Check if string ends if token[0] == "\"" or "\n" in token[0]: stringing = False elif token[0] == "\"": #Start of a string setStyling(token[1], STR) stringing = True elif token[0] in kw_list: #Keyword setStyling(token[1], KWD) elif token[0] in types_list: #Keyword setStyling(token[1], TYP) elif token[0] == "(*": #Start of a comment setStyling(token[1], COM) commenting = True elif i > 1 and tokens[i - 2][0] == "PROCEDURE": #Procedure name setStyling(token[1], PRO) elif i > 1 and tokens[i - 2][0] == "MODULE": #Module name (beginning) setStyling(token[1], MOD) elif (i > 1 and tokens[i - 2][0] == "END") and (len(tokens) - 1 >= i + 1): #Module or procedure name (name) if ";" in tokens[i + 1][0]: #Procedure end setStyling(token[1], PRO) elif "." in tokens[i + 1][0]: #Module end setStyling(token[1], MOD) else: setStyling(token[1], DEF) elif functions.is_number(token[0]): #Number setStyling(token[1], NUM) else: setStyling(token[1], DEF)
class Editor: """ These are the built-in defaults, attributes should be changed in other modules! """ # Default EOL style in editors (EolWindows-CRLF, EolUnix-LF, EolMac-CR) end_of_line_mode = data.QsciScintilla.EolUnix # Font colors and styles font = data.QFont( data.current_editor_font_name, data.current_editor_font_size ) brace_color = data.QColor(255, 153, 0) comment_font = data.current_editor_font_name.encode("utf-8") # Edge marker edge_marker_color = data.QColor(180, 180, 180, alpha=255) edge_marker_column = 90 # Various cursor_line_visible = False # Maximum limit of highlighting instances maximum_highlights = 300 # Global width of tabs tab_width = 4 # Zoom factor when a new editor is created (default is 0) zoom_factor = 0 """ ------------------------------------------- Keyboard shortcuts ------------------------------------------- """ class Keys: # Custom editor commands copy = 'Ctrl+C' cut = 'Ctrl+X' paste = 'Ctrl+V' undo = 'Ctrl+Z' redo = 'Ctrl+Y' select_all = 'Ctrl+A' indent = 'Tab' unindent = 'Shift+Tab' delete_start_of_word = 'Ctrl+BackSpace' delete_end_of_word = 'Ctrl+Delete' delete_start_of_line = 'Ctrl+Shift+BackSpace' delete_end_of_line = 'Ctrl+Shift+Delete' go_to_start = 'Ctrl+Home' go_to_end = 'Ctrl+End' select_page_up = 'Shift+PageUp' select_page_down = 'Shift+PageDown' select_to_start = 'Ctrl+Shift+Home' select_to_end = 'Ctrl+Shift+End' scroll_up = 'PageUp' scroll_down = 'PageDown' line_cut = 'Ctrl+L' line_copy = 'Ctrl+Shift+T' line_delete = 'Ctrl+Shift+L' line_transpose = 'Ctrl+T' line_selection_duplicate = 'Ctrl+D' @staticmethod def check_function(function_name): check_list = [x for x in dir(Editor.Keys) if not x.startswith('__')] return function_name in check_list @staticmethod def check_combination(combination): if combination.startswith("#"): combination = combination[1:] check_list = [ (x, getattr(Editor.Keys, x)) for x in dir(Editor.Keys) if not x.startswith('__') ] for name, keys in check_list: if not(isinstance(keys, str)) and not(isinstance(keys, list)): continue if isinstance(combination, list): if isinstance(keys, list): for k in keys: for c in combination: if k.strip().lower() == c.strip().lower(): return True else: for c in combination: if keys.strip().lower() == c.strip().lower(): return True elif isinstance(keys, str): if keys.strip().lower() == combination.strip().lower(): return True return False
def set_theme(self, theme): # Papers self.setPaper(data.QColor(theme.Paper.Python.Default), self.styles["Default"]) # Fonts lexers.set_font(self, "Default", theme.Font.Python.Default)