Skip to content

Commit

Permalink
Refactor ruby_editor and make methods private. Move platform specific…
Browse files Browse the repository at this point in the history
… font code into Qt.rb. #129
  • Loading branch information
jmthomas committed May 12, 2015
1 parent 5db28d4 commit 01af4d1
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 134 deletions.
18 changes: 18 additions & 0 deletions lib/cosmos/gui/qt.rb
Expand Up @@ -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
Expand Down
240 changes: 129 additions & 111 deletions lib/cosmos/gui/text/ruby_editor.rb
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -143,34 +147,27 @@ 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

CHAR_57 = Qt::Char.new(57)

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;")

@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)

Expand All @@ -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
Expand All @@ -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
Expand All @@ -271,84 +237,35 @@ 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)

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()
Expand Down Expand Up @@ -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
6 changes: 1 addition & 5 deletions lib/cosmos/tools/data_viewer/data_viewer_component.rb
Expand Up @@ -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)

Expand Down
6 changes: 1 addition & 5 deletions lib/cosmos/tools/handbook_creator/handbook_creator_config.rb
Expand Up @@ -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
Expand Down

0 comments on commit 01af4d1

Please sign in to comment.