diff --git a/lib/cosmos/gui/qt.rb b/lib/cosmos/gui/qt.rb index 7b514e95e..602822d87 100644 --- a/lib/cosmos/gui/qt.rb +++ b/lib/cosmos/gui/qt.rb @@ -175,6 +175,24 @@ def self.getFont(font_face, font_size, font_attrs = nil, font_italics = false) font end + # Get the default small font for the platform (Windows, Mac, Linux) + def self.get_default_small_font + if Kernel.is_windows? + Cosmos.getFont("courier", 9) + else + Cosmos.getFont("courier", 12) + end + end + + # Get the default font for the platform (Windows, Mac, Linux) + def self.get_default_font + if Kernel.is_windows? + Cosmos.getFont("Courier", 10) + else + Cosmos.getFont("Courier", 14) + end + end + def self.getFontMetrics(font) font_metrics = FONT_METRICS[font] unless font_metrics diff --git a/lib/cosmos/gui/text/ruby_editor.rb b/lib/cosmos/gui/text/ruby_editor.rb index bf7fcd699..27686ce80 100644 --- a/lib/cosmos/gui/text/ruby_editor.rb +++ b/lib/cosmos/gui/text/ruby_editor.rb @@ -16,15 +16,19 @@ module Cosmos class RubyEditor < CompletionTextEdit + # private slot used to connect to the blockCountChanged signal slots 'line_count_changed()' + # private slot used to connect to the updateRequest signal slots 'update_line_number_area(const QRect &, int)' + signals 'breakpoint_set(int)' signals 'breakpoint_cleared(int)' signals 'breakpoints_cleared()' attr_accessor :enable_breakpoints - # This works but slows down the GUI significantly when pasting a large (10k line) block of code into the editor + # This works but slows down the GUI significantly when + # pasting a large (10k line) block of code into the editor class RubySyntax < Qt::SyntaxHighlighter # Ruby keywords - http://www.ruby-doc.org/docs/keywords/1.9/ # Also include some common methods that are typically called by @@ -84,7 +88,7 @@ def self.create_format(color = Cosmos::BLACK, style='') # 'class' followed by an identifier ['\bclass\b\s*(\w+)', 1, STYLES['class']], # Ruby symbol - ['\s:\b\w+', 0, STYLES['symbol']], + [':\b\w+', 0, STYLES['symbol']], # Ruby namespace operator ['\b\w+(::\b\w+)+', 0, STYLES['class']], # Ruby global @@ -143,12 +147,8 @@ def initialize(editor) self end - def sizeHint() - return Qt::Size(@codeEditor.lineNumberAreaWidth(), 0) - end - def paintEvent(event) - @codeEditor.lineNumberAreaPaintEvent(event) + @codeEditor.line_number_area_paint_event(event) end end @@ -156,13 +156,9 @@ def paintEvent(event) def initialize(parent) super(parent) - if Kernel.is_windows? - setFont(Cosmos.getFont("Courier", 10)) - @fontMetrics = Cosmos.getFontMetrics(Cosmos.getFont("Courier", 10)) - else - setFont(Cosmos.getFont("Courier", 14)) - @fontMetrics = Cosmos.getFontMetrics(Cosmos.getFont("Courier", 14)) - end + font = Cosmos.get_default_font + setFont(font) + @fontMetrics = Cosmos.getFontMetrics(font) # This is needed so text searching highlights correctly setStyleSheet("selection-background-color: lightblue; selection-color: black;") @@ -170,7 +166,8 @@ def initialize(parent) @breakpoints = [] @enable_breakpoints = false - # RubySyntax works but slows down the GUI significantly when pasting a large (10k line) block of code into the editor + # RubySyntax works but slows down the GUI significantly when + # pasting a large (10k line) block of code into the editor @syntax = RubySyntax.new(document()) @lineNumberArea = LineNumberArea.new(self) @@ -188,46 +185,16 @@ def dispose def context_menu(point) menu = createStandardContextMenu() - if @enable_breakpoints - menu.addSeparator() - - add_breakpoint = Qt::Action.new(tr("Add Breakpoint"), self) - add_breakpoint.statusTip = tr("Add a breakpoint at this line") - add_breakpoint.connect(SIGNAL('triggered()')) { breakpoint_click(point) } - menu.addAction(add_breakpoint) - - clear_breakpoint = Qt::Action.new(tr("Clear Breakpoint"), self) - clear_breakpoint.statusTip = tr("Clear an existing breakpoint at this line") - clear_breakpoint.connect(SIGNAL('triggered()')) { breakpoint_click(point, false) } - menu.addAction(clear_breakpoint) - - clear_all_breakpoints = Qt::Action.new(tr("Clear All Breakpoints"), self) - clear_all_breakpoints.statusTip = tr("Clear all existing breakpoints") - clear_all_breakpoints.connect(SIGNAL('triggered()')) do - clear_breakpoints() - emit breakpoints_cleared - end - menu.addAction(clear_all_breakpoints) - end - return menu - end + return menu unless @enable_breakpoints - def breakpoint_click(point, add_breakpoint = true) - line = point.y / @fontMetrics.height() + 1 + firstVisibleBlock().blockNumber() - if add_breakpoint - if line <= document.blockCount() - breakpoint(line) - emit breakpoint_set(line) - end - else - if line <= document.blockCount() - clear_breakpoint(line) - emit breakpoint_cleared(line) - end - end + menu.addSeparator() + menu.addAction(create_add_breakpoint_action(point)) + menu.addAction(create_clear_breakpoint_action(point)) + menu.addAction(create_clear_all_breakpoints_action()) + menu end - def breakpoint(line) + def add_breakpoint(line) @breakpoints << line @lineNumberArea.repaint end @@ -244,19 +211,18 @@ def clear_breakpoints def comment_or_uncomment_lines cursor = textCursor - # Figure out if the cursor has a selection - no_selection = true - no_selection = false if cursor.hasSelection + no_selection = cursor.hasSelection ? false : true # Start the edit block so this can be all undone with a single undo step cursor.beginEditBlock selection_end = cursor.selectionEnd # Initially place the cursor at the beginning of the selection - # If nothing is selected this will just put the cursor at the beginning of the current line + # If nothing is selected this will just put the cursor at the beginning + # of the current line cursor.setPosition(textCursor.selectionStart) cursor.movePosition(Qt::TextCursor::StartOfLine) result = true - while (cursor.position < selection_end and result == true) or (no_selection) + while (cursor.position < selection_end && result == true) || (no_selection) # Check for a special comment if cursor.block.text =~ /^\S*#~/ cursor.deleteChar @@ -271,63 +237,27 @@ def comment_or_uncomment_lines # Move the cursor to the beginning of the next line cursor.movePosition(Qt::TextCursor::StartOfLine) result = cursor.movePosition(Qt::TextCursor::Down) - # If nothing was selected then we're working with a single line and we can break + # If nothing was selected then its a single line so break break if no_selection end cursor.endEditBlock end - def lineNumberAreaWidth - digits = 1 - my_document = document() - max = [1, my_document.blockCount()].max - - # Figure the line number power of ten to determine how much space we need - while (max >= 10) - max /= 10 - digits += 1 - end - # We'll always display space for 5 digits so the line number area - # isn't constantly expanding and contracting - digits = 5 if digits < 5 - digits += 1 # always allow room for a breakpoint symbol - # Get the font width of the character 57 ('9') - # times the number of digits to display - return (3 + @fontMetrics.width(CHAR_57) * digits) - end - - def line_count_changed - setViewportMargins(lineNumberAreaWidth(), 0, 0, 0) - update - end - - def update_line_number_area(rect, dy) - if (dy) - @lineNumberArea.scroll(0, dy) - else - @lineNumberArea.update(0, rect.y(), @lineNumberArea.width(), rect.height()) - end - my_viewport = viewport() - viewport_rect = my_viewport.rect() - line_count_changed() if (rect.contains(viewport_rect)) - viewport_rect.dispose - end - def resizeEvent(e) super(e) cr = self.contentsRect() rect = Qt::Rect.new(cr.left(), cr.top(), - lineNumberAreaWidth(), + line_number_area_width(), cr.height()) @lineNumberArea.setGeometry(rect) cr.dispose rect.dispose end - def lineNumberAreaPaintEvent(event) + def line_number_area_paint_event(event) painter = Qt::Painter.new(@lineNumberArea) - # On initialization sometimes we get some weird bad conditions so check for them + # Check for weird bad initialization conditions if painter.isActive and not painter.paintEngine.nil? event_rect = event.rect() painter.fillRect(event_rect, Qt::lightGray) @@ -335,20 +265,7 @@ def lineNumberAreaPaintEvent(event) block = firstVisibleBlock() blockNumber = block.blockNumber() - offset = contentOffset() - rect = blockBoundingGeometry(block) - rect2 = rect.translated(offset) - top = rect2.top() - rect3 = blockBoundingRect(block) - bottom = top + rect3.height() - offset.dispose - offset = nil - rect.dispose - rect = nil - rect2.dispose - rect2 = nil - rect3.dispose - rect3 = nil + top, bottom = block_top_and_bottom(block) width = @lineNumberArea.width() height = @fontMetrics.height() @@ -392,6 +309,107 @@ def lineNumberAreaPaintEvent(event) painter.dispose painter = nil end + + private + + def line_count_changed + setViewportMargins(line_number_area_width(), 0, 0, 0) + update + end + + def update_line_number_area(rect, dy) + if (dy) + @lineNumberArea.scroll(0, dy) + else + @lineNumberArea.update(0, rect.y(), @lineNumberArea.width(), rect.height()) + end + my_viewport = viewport() + viewport_rect = my_viewport.rect() + line_count_changed() if (rect.contains(viewport_rect)) + viewport_rect.dispose + end + + def line_number_area_width + digits = 1 + my_document = document() + max = [1, my_document.blockCount()].max + + # Figure the line number power of ten to determine how much space we need + while (max >= 10) + max /= 10 + digits += 1 + end + # We'll always display space for 5 digits so the line number area + # isn't constantly expanding and contracting + digits = 5 if digits < 5 + digits += 1 # always allow room for a breakpoint symbol + # Get the font width of the character 57 ('9') + # times the number of digits to display + return (3 + @fontMetrics.width(CHAR_57) * digits) + end + + def line_at_point(point) + line = point.y / @fontMetrics.height() + 1 + + firstVisibleBlock().blockNumber() + yield line if line <= document.blockCount() + end + + def create_add_breakpoint_action(point) + add_breakpoint = Qt::Action.new(tr("Add Breakpoint"), self) + add_breakpoint.statusTip = tr("Add a breakpoint at this line") + add_breakpoint.connect(SIGNAL('triggered()')) do + line_at_point(point) do |line| + add_breakpoint(line) + emit breakpoint_set(line) + end + end + add_breakpoint + end + + def create_clear_breakpoint_action(point) + clear_breakpoint = Qt::Action.new(tr("Clear Breakpoint"), self) + clear_breakpoint.statusTip = tr("Clear an existing breakpoint at this line") + clear_breakpoint.connect(SIGNAL('triggered()')) do + line_at_point(point) do |line| + clear_breakpoint(line) + emit breakpoint_cleared(line) + end + end + clear_breakpoint + end + + def create_clear_all_breakpoints_action + clear_all_breakpoints = Qt::Action.new(tr("Clear All Breakpoints"), self) + clear_all_breakpoints.statusTip = tr("Clear all existing breakpoints") + clear_all_breakpoints.connect(SIGNAL('triggered()')) do + clear_breakpoints + emit breakpoints_cleared + end + clear_all_breakpoints + end + + # Get the top and bottom coordinates of the block in viewport coordinates + def block_top_and_bottom(block) + # bounding rect of the text block in content coordinates + rect = blockBoundingGeometry(block) + offset = contentOffset() # content origin in viewport coordinates + # translate the rect to get visual coordinates on the viewport + rect2 = rect.translated(offset) + top = rect2.top() + # bounding rect in block coordinates + rect3 = blockBoundingRect(block) + bottom = top + rect3.height() + # Now call the destructors and set to nil to allow garbage collection + offset.dispose + offset = nil + rect.dispose + rect = nil + rect2.dispose + rect2 = nil + rect3.dispose + rect3 = nil + return top, bottom + end end end # module Cosmos diff --git a/lib/cosmos/tools/data_viewer/data_viewer_component.rb b/lib/cosmos/tools/data_viewer/data_viewer_component.rb index 78abf1876..f22668a0f 100644 --- a/lib/cosmos/tools/data_viewer/data_viewer_component.rb +++ b/lib/cosmos/tools/data_viewer/data_viewer_component.rb @@ -39,11 +39,7 @@ def initialize_gui @text = Qt::PlainTextEdit.new @text.setReadOnly(true) @text.setMaximumBlockCount(@max_block_count) - if Kernel.is_windows? - @text.font = Cosmos.getFont("courier", 9) - else - @text.font = Cosmos.getFont("courier", 12) - end + @text.font = Cosmos.get_default_small_font @text.setWordWrapMode(Qt::TextOption::NoWrap) @top_layout.addWidget(@text) diff --git a/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb b/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb index f63139063..b920a15f4 100644 --- a/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +++ b/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb @@ -83,11 +83,7 @@ def create_pdf(hide_ignored, progress_dialog = nil) if @pdf if progress_dialog Qt.execute_in_main_thread(true) do - if Kernel.is_windows? - progress_dialog.set_text_font(Cosmos.getFont("courier",10)) - else - progress_dialog.set_text_font(Cosmos.getFont("courier",14)) - end + progress_dialog.set_text_font(Cosmos.get_default_font) end end Cosmos.set_working_dir do diff --git a/lib/cosmos/tools/script_runner/script_runner_frame.rb b/lib/cosmos/tools/script_runner/script_runner_frame.rb index 86ff968cd..96a546ef4 100644 --- a/lib/cosmos/tools/script_runner/script_runner_frame.rb +++ b/lib/cosmos/tools/script_runner/script_runner_frame.rb @@ -650,7 +650,7 @@ def prompt_if_running_on_close # Implement the breakpoint callbacks from the RubyEditor ###################################### def breakpoint_set(line) - ScriptRunnerFrame.breakpoint(current_tab_filename(), line) + ScriptRunnerFrame.set_breakpoint(current_tab_filename(), line) end def breakpoint_cleared(line) @@ -1060,7 +1060,7 @@ def hide_debug @debug_frame = nil end - def self.breakpoint(filename, line_number) + def self.set_breakpoint(filename, line_number) filename = File.basename(filename) @@breakpoints[filename] ||= {} @@breakpoints[filename][line_number] = true @@ -1645,7 +1645,7 @@ def mark_breakpoints(filename) breakpoints = @@breakpoints[File.basename(filename)] if breakpoints breakpoints.each do |line_number, present| - @active_script.breakpoint(line_number) if present + @active_script.add_breakpoint(line_number) if present end end end diff --git a/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb b/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb index c612b677c..366b93df4 100644 --- a/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb +++ b/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb @@ -25,11 +25,7 @@ def initialize(parent_layout, target_name, packet_name, item_name, width = 200, @items_per_row = items_per_row.to_i setFixedSize(width.to_i, height.to_i) setReadOnly(true) - if Kernel.is_windows? - setFont(Cosmos.getFont("courier", 10)) - else - setFont(Cosmos.getFont("courier", 14)) - end + setFont(Cosmos.get_default_font) parent_layout.addWidget(self) if parent_layout end diff --git a/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb b/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb index d2df347c7..5e956e180 100644 --- a/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb +++ b/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb @@ -26,11 +26,7 @@ def initialize (parent_layout, target_name, packet_name, item_name, width = 200, @bytes_per_row = @bytes_per_word * @words_per_row @addr_format = ConfigParser.handle_nil(addr_format) @addr_format << ' ' if @addr_format - if Kernel.is_windows? - setFont(Cosmos.getFont("courier", 10)) - else - setFont(Cosmos.getFont("courier", 14)) - end + setFont(Cosmos.get_default_font) end def format_value(data)