class EnchantedQuill::Label

Attributes

active_elements[R]
category_color[R]
category_selected_color[R]
category_tap_handler[R]
customizing[R]
hashtag_color[R]
hashtag_selected_color[R]
hashtag_tap_handler[R]
height_correction[R]
line_height_multiple[R]
line_spacing[R]
maximum_line_height[R]
mention_color[R]
mention_selected_color[R]
mention_tap_handler[R]
minimum_line_height[R]
selected_element[R]
url_color[R]
url_selected_color[R]
url_tap_handler[R]

Public Instance Methods

attributedText=(attributed_text) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 184
def attributedText=(attributed_text)
  super
  update_text_storage
end
awakeFromNib() click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 22
def awakeFromNib
  super.tap do
    update_text_storage
  end
end
category_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 224
def category_color=(color)
  @category_color = color
  update_text_storage(false)
end
category_selected_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 229
def category_selected_color=(color)
  @category_selected_color = color
  update_text_storage(false)
end
customize(&block) click to toggle source
# File lib/enchanted_quill/label.rb, line 96
def customize(&block)
  @customizing = true
  block.call(self)
  @customizing = false
  update_text_storage
  self
end
delegate() click to toggle source
# File lib/enchanted_quill/label.rb, line 158
def delegate
  @delegate
end
delegate=(delegate) click to toggle source
# File lib/enchanted_quill/label.rb, line 154
def delegate=(delegate)
  @delegate = WeakRef.new(delegate)
end
drawTextInRect(rect) click to toggle source
# File lib/enchanted_quill/label.rb, line 28
def drawTextInRect(rect)
  range               = NSMakeRange(0, text_storage.length)
  text_container.size = rect.size
  new_origin          = text_origin(rect)

  layout_manager.drawBackgroundForGlyphRange(range, atPoint: new_origin)
  layout_manager.drawGlyphsForGlyphRange(range, atPoint: new_origin)
end
font=(font) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 189
def font=(font)
  super
  update_text_storage(false)
end
handle_category_tap(&block) click to toggle source
# File lib/enchanted_quill/label.rb, line 174
def handle_category_tap(&block)
  @category_tap_handler = block
end
handle_hashtag_tap(&block) click to toggle source
# File lib/enchanted_quill/label.rb, line 166
def handle_hashtag_tap(&block)
  @hashtag_tap_handler = block
end
handle_mention_tap(&block) click to toggle source
# File lib/enchanted_quill/label.rb, line 162
def handle_mention_tap(&block)
  @mention_tap_handler = block
end
handle_url_tap(&block) click to toggle source
# File lib/enchanted_quill/label.rb, line 170
def handle_url_tap(&block)
  @url_tap_handler = block
end
hashtag_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 214
def hashtag_color=(color)
  @hashtag_color = color
  update_text_storage(false)
end
hashtag_selected_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 219
def hashtag_selected_color=(color)
  @hashtag_selected_color = color
  update_text_storage(false)
end
init() click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 10
def init
  super.tap do |label|
    label.setup_label
  end
end
initWithFrame(frame) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 16
def initWithFrame(frame)
  super.tap do |label|
    label.setup_label
  end
end
layoutSubviews() click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 37
def layoutSubviews
  super
  text_container.size = self.bounds.size
end
line_height_multiple=(multiple) click to toggle source
# File lib/enchanted_quill/label.rb, line 249
def line_height_multiple=(multiple)
  @line_height_multiple = multiple
  update_text_storage(false)
end
line_spacing=(spacing) click to toggle source
# File lib/enchanted_quill/label.rb, line 244
def line_spacing=(spacing)
  @line_spacing = spacing
  update_text_storage(false)
end
maximum_line_height=(height) click to toggle source
# File lib/enchanted_quill/label.rb, line 254
def maximum_line_height=(height)
  @maximum_line_height = height
  update_text_storage(false)
end
mention_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 204
def mention_color=(color)
  @mention_color = color
  update_text_storage(false)
end
mention_selected_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 209
def mention_selected_color=(color)
  @mention_selected_color = color
  update_text_storage(false)
end
minimum_line_height=(height) click to toggle source
# File lib/enchanted_quill/label.rb, line 259
def minimum_line_height=(height)
  @minimum_line_height = height
  update_text_storage(false)
end
on_touch(touch) click to toggle source
# File lib/enchanted_quill/label.rb, line 104
def on_touch(touch)
  location = touch.locationInView(self)
  avoid_super_call = false

  case touch.phase
  when UITouchPhaseBegan, UITouchPhaseMoved
    if element = element_at_location(location)
      if element.range.location != (selected_element && selected_element.range.location) ||
         element.range.length != (selected_element && selected_element.range.length)

         update_attributed_when_selected(false)
         @selected_element = element
         update_attributed_when_selected(true)
       end
       avoid_super_call = true
    else
      update_attributed_when_selected(false)
      @selected_element = nil
    end
  when UITouchPhaseEnded
    return avoid_super_call unless selected_element

    case selected_element.type
    when :category then did_tap_category(selected_element.word)
    when :mention  then did_tap_mention(selected_element.word)
    when :hashtag  then did_tap_hashtag(selected_element.word)
    when :url      then did_tap_string_url(selected_element.word)
    else
    end

    Dispatch::Queue.concurrent.after(0.1) do
      Dispatch::Queue.main.async do
        update_attributed_when_selected(false)
        @selected_element = nil
      end
    end
    avoid_super_call = true
  when UITouchPhaseCancelled
    Dispatch::Queue.concurrent.after(0.1) do
      Dispatch::Queue.main.async do
        update_attributed_when_selected(false)
        @selected_element = nil
      end
    end
  when UITouchPhaseStationary
  end

  avoid_super_call
end
rect_fitting_text_for_container_size(size, for_number_of_line: num_of_lines) click to toggle source
# File lib/enchanted_quill/label.rb, line 72
def rect_fitting_text_for_container_size(size, for_number_of_line: num_of_lines)
  text_container.size = size;
  text_container.maximumNumberOfLines = num_of_lines
  text_bounds = layout_manager.boundingRectForGlyphRange(NSMakeRange(0, layout_manager.numberOfGlyphs),
                  inTextContainer: text_container)
  total_lines = text_bounds.size.height / self.font.lineHeight

  height = text_bounds.size.height
  if num_of_lines > 0 && (num_of_lines < total_lines)
    height -= (total_lines - num_of_lines) * self.font.lineHeight
  elsif (num_of_lines > 0 && (num_of_lines > total_lines))
    height += (num_of_lines - total_lines) * self.font.lineHeight
  end

  width  = text_bounds.size.width.ceil
  height = (attributedText && attributedText.mutableString.blank?) ? 0 : height.ceil
  CGRectMake(text_bounds.origin.x, text_bounds.origin.y, width, height)
end
requiresConstraintBasedLayout() click to toggle source

Override UIView methods

# File lib/enchanted_quill/label.rb, line 92
def requiresConstraintBasedLayout
  true
end
setBounds(bounds) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 52
def setBounds(bounds)
  super
  update_text_container_size(bounds.size)
end
setFrame(frame) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 47
def setFrame(frame)
  super
  update_text_container_size(frame.size)
end
setPreferredMaxLayoutWidth(preferred_max_layout_width) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 42
def setPreferredMaxLayoutWidth(preferred_max_layout_width)
  super
  update_text_container_size(self.bounds.size)
end
setup_label() click to toggle source
# File lib/enchanted_quill/label.rb, line 288
def setup_label
  @setup_label ||= begin
    @customizing = false
    @active_elements = {}
    @height_correction = 0
    self.line_height_multiple    = 1
    self.textColor               = UIColor.blackColor
    self.mention_color           = UIColor.blueColor
    self.mention_selected_color  = UIColor.blueColor.colorWithAlphaComponent(0.5)
    self.hashtag_color           = UIColor.blueColor
    self.hashtag_selected_color  = UIColor.blueColor.colorWithAlphaComponent(0.5)
    self.category_color          = UIColor.brownColor
    self.category_selected_color = UIColor.brownColor.colorWithAlphaComponent(0.5)
    self.url_color               = UIColor.blueColor
    self.url_selected_color      = UIColor.blueColor.colorWithAlphaComponent(0.5)

    text_storage.addLayoutManager(layout_manager)
    layout_manager.addTextContainer(text_container)
    text_container.lineFragmentPadding = 0
    text_container.maximumNumberOfLines = 0
    self.userInteractionEnabled = true
  end
end
text=(text) click to toggle source

override UILabel attributes

Calls superclass method
# File lib/enchanted_quill/label.rb, line 179
def text=(text)
  super
  update_text_storage
end
textAlignment=(alignment) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 199
def textAlignment=(alignment)
  super
  update_text_storage(false)
end
textColor=(color) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 194
def textColor=(color)
  super
  update_text_storage(false)
end
textRectForBounds(bounds, limitedToNumberOfLines: num_of_lines) click to toggle source

Override UILabel Methods

# File lib/enchanted_quill/label.rb, line 66
def textRectForBounds(bounds, limitedToNumberOfLines: num_of_lines)
        required_rect = rect_fitting_text_for_container_size(bounds.size, for_number_of_line: num_of_lines)
        text_container.size = required_rect.size
        required_rect
end
touchesBegan(touches, withEvent: event) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 264
def touchesBegan(touches, withEvent: event)
  touches = touches && touches.allObjects
  touch   = touches.first
  return unless touch
  return if on_touch(touch)
  super
end
touchesCancelled(touches, withEvent: event) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 272
def touchesCancelled(touches, withEvent: event)
  touches = touches && touches.allObjects
  touch   = touches.first
  return unless touch
  on_touch(touch)
  super
end
touchesEnded(touches, withEvent: event) click to toggle source
Calls superclass method
# File lib/enchanted_quill/label.rb, line 280
def touchesEnded(touches, withEvent: event)
  touches = touches && touches.allObjects
  touch   = touches.first
  return unless touch
  return if on_touch(touch)
  super
end
update_text_container_size(size) click to toggle source
# File lib/enchanted_quill/label.rb, line 57
def update_text_container_size(size)
        container_size = size
        width  = [size.width, self.preferredMaxLayoutWidth].min
  height = 0
        text_container.size = CGSizeMake(width, height)
end
url_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 234
def url_color=(color)
  @url_color = color
  update_text_storage(false)
end
url_selected_color=(color) click to toggle source
# File lib/enchanted_quill/label.rb, line 239
def url_selected_color=(color)
  @url_selected_color = color
  update_text_storage(false)
end

Private Instance Methods

add_default_attributes(mut_attr_string) click to toggle source
# File lib/enchanted_quill/label.rb, line 372
def add_default_attributes(mut_attr_string)
  range_pointer = Pointer.new(NSRange.type)
  attributes = mut_attr_string.attributesAtIndex(0, effectiveRange: range_pointer).dup

  attributes[NSFontAttributeName] = self.font
  attributes[NSForegroundColorAttributeName] = self.textColor

  mut_attr_string.addAttributes(attributes, range: range_pointer[0])
  mut_attr_string
end
add_line_break(attr_string) click to toggle source
# File lib/enchanted_quill/label.rb, line 428
def add_line_break(attr_string)
  mut_attr_string = NSMutableAttributedString.alloc.initWithAttributedString(attr_string)

  range_pointer = Pointer.new(NSRange.type)
  attributes = mut_attr_string.attributesAtIndex(0, effectiveRange: range_pointer).dup

  current_paragraph_style = attributes[NSParagraphStyleAttributeName] && attributes[NSParagraphStyleAttributeName].mutableCopy
  paragraph_style = current_paragraph_style || NSMutableParagraphStyle.alloc.init
  paragraph_style.lineBreakMode      = NSLineBreakByWordWrapping
  paragraph_style.alignment          = textAlignment
  paragraph_style.lineSpacing        = line_spacing if line_spacing
  paragraph_style.lineHeightMultiple = line_height_multiple

  paragraph_style.minimumLineHeight = if minimum_line_height && minimum_line_height > 0
                                        minimum_line_height
                                      else
                                        font.lineHeight * line_height_multiple
                                      end

  paragraph_style.maximumLineHeight = if maximum_line_height and maximum_line_height > 0
                                        maximum_line_height
                                      else
                                        font.lineHeight * line_height_multiple
                                      end

  attributes[NSParagraphStyleAttributeName] = paragraph_style
  mut_attr_string.setAttributes(attributes, range: range_pointer[0])
  mut_attr_string
end
clear_active_elements() click to toggle source
# File lib/enchanted_quill/label.rb, line 360
def clear_active_elements
  @selected_element = nil
  @active_elements  = {}
end
did_tap_category(category) click to toggle source
# File lib/enchanted_quill/label.rb, line 531
def did_tap_category(category)
  if category_tap_handler
    category_tap_handler.call(category)
  elsif delegate && delegate.respond_to?('did_select_text:type:')
    delegate.did_select_text(category, type: :category)
  end
end
did_tap_hashtag(hashtag) click to toggle source
# File lib/enchanted_quill/label.rb, line 514
def did_tap_hashtag(hashtag)
  if hashtag_tap_handler
    hashtag_tap_handler.call(hashtag)
  elsif delegate && delegate.respond_to?('did_select_text:type:')
    delegate.did_select_text(hashtag, type: :hashtag)
  end
end
did_tap_mention(username) click to toggle source
# File lib/enchanted_quill/label.rb, line 506
def did_tap_mention(username)
  if mention_tap_handler
    mention_tap_handler.call(username)
  elsif delegate && delegate.respond_to?('did_select_text:type:')
    delegate.did_select_text(username, type: :mention)
  end
end
did_tap_string_url(url) click to toggle source
# File lib/enchanted_quill/label.rb, line 522
def did_tap_string_url(url)
  url = NSURL.URLWithString(url)
  if url_tap_handler
    url_tap_handler.call(url)
  elsif delegate && delegate.respond_to?('did_select_text:type:')
    delegate.did_select_text(url, type: :url)
  end
end
element_at_location(location) click to toggle source
# File lib/enchanted_quill/label.rb, line 482
def element_at_location(location)
  return unless text_storage.length > 0

  y = location.y - height_correction
  correct_location = CGPointMake(location.x, y)
  bounding_rect    = layout_manager.boundingRectForGlyphRange(NSMakeRange(0, text_storage.length), inTextContainer: text_container)

  return unless CGRectContainsPoint(bounding_rect, correct_location)

  index = layout_manager.glyphIndexForPoint(correct_location, inTextContainer: text_container)

  active_element = nil
  active_elements.values.flatten.each do |element|
    if index < text_storage.length - 1 &&
       index >= element.range.location &&
       index < element.range.location + element.range.length
      active_element = element
      break
    end
  end

  active_element
end
layout_manager() click to toggle source
# File lib/enchanted_quill/label.rb, line 318
def layout_manager
  @layout_manager ||= NSLayoutManager.alloc.init
end
parse_text_and_extract_active_elements(attr_string) click to toggle source
# File lib/enchanted_quill/label.rb, line 406
def parse_text_and_extract_active_elements(attr_string)
  text_string = attr_string.string
  text_length = text_string.length
  text_range  = NSMakeRange(0, text_length)

  # urls
  url_elements = ElementCreator.create_url_elements(text_string, text_range)
  @active_elements[:url] = url_elements

  # hash_tags
  hashtag_elements = ElementCreator.create_hashtag_elements(text_string, text_range)
  @active_elements[:hashtag] = hashtag_elements

  # mentions
  mention_elements = ElementCreator.create_mentions_elements(text_string, text_range)
  @active_elements[:mention] = mention_elements

  # categories
  category_elements = ElementCreator.create_category_elements(text_string, text_range)
  @active_elements[:category] = category_elements
end
text_container() click to toggle source
# File lib/enchanted_quill/label.rb, line 322
def text_container
  @text_container ||= NSTextContainer.alloc.init
end
text_origin(rect) click to toggle source
# File lib/enchanted_quill/label.rb, line 365
def text_origin(rect)
  used_rect          = layout_manager.usedRectForTextContainer(text_container)
  @height_correction = (rect.size.height - used_rect.size.height) / 2
  glyph_origin_y     = height_correction > 0 ? rect.origin.y + height_correction : rect.origin.y
  CGPointMake(rect.origin.x, glyph_origin_y)
end
text_storage() click to toggle source
# File lib/enchanted_quill/label.rb, line 326
def text_storage
  @text_storage ||= NSTextStorage.alloc.init
end
update_attributed_when_selected(selected) click to toggle source
# File lib/enchanted_quill/label.rb, line 458
def update_attributed_when_selected(selected)
  return unless @selected_element

  attributes = text_storage.attributesAtIndex(0, effectiveRange: nil).dup
  unless selected
    case @selected_element.type
    when :category then attributes[NSForegroundColorAttributeName] = category_color
    when :hashtag  then attributes[NSForegroundColorAttributeName] = hashtag_color
    when :mention  then attributes[NSForegroundColorAttributeName] = mention_color
    when :url      then attributes[NSForegroundColorAttributeName] = url_color
    end
  else
    case @selected_element.type
    when :category then attributes[NSForegroundColorAttributeName] = category_selected_color || category_color
    when :hashtag  then attributes[NSForegroundColorAttributeName] = hashtag_selected_color  || hashtag_color
    when :mention  then attributes[NSForegroundColorAttributeName] = mention_selected_color  || mention_color
    when :url      then attributes[NSForegroundColorAttributeName] = url_selected_color      || url_color
    end
  end

  text_storage.addAttributes(attributes, range: @selected_element.range)
  setNeedsDisplay
end
update_text_storage(parse_text = true) click to toggle source
# File lib/enchanted_quill/label.rb, line 330
def update_text_storage(parse_text = true)
  return if customizing

  attributed_text = attributedText
  if attributed_text.nil? || attributed_text.length == 0
    clear_active_elements
    text_storage.setAttributedString(NSAttributedString.alloc.initWithString(''))
    setNeedsDisplay
    return
  end

  mut_attr_string = add_line_break(attributed_text)
  mut_attr_string = add_default_attributes(mut_attr_string)

  if parse_text
    clear_active_elements
    parse_text_and_extract_active_elements(mut_attr_string)
    active_elements_values = @active_elements.values.flatten.compact

    if active_elements_values.count > 0
      add_link_attribute(mut_attr_string)
      text_storage.setAttributedString(mut_attr_string)
      setNeedsDisplay
    end
  end

  text_storage.setAttributedString(mut_attr_string)
  setNeedsDisplay
end