label.nim 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # author: Ethosa
  2. ## It provides primitive text rendering.
  3. import
  4. strutils,
  5. ../thirdparty/opengl,
  6. ../thirdparty/sdl2/ttf,
  7. ../core/vector2,
  8. ../core/rect2,
  9. ../core/anchor,
  10. ../core/input,
  11. ../core/enums,
  12. ../core/color,
  13. ../core/stylesheet,
  14. ../core/font,
  15. ../core/nodes_os,
  16. ../graphics/drawable,
  17. ../nodes/node,
  18. ../nodes/canvas,
  19. browsers,
  20. control
  21. type
  22. TextChangedHandler* = proc(self: LabelRef, text: string)
  23. LabelObj* = object of ControlRef
  24. on_text_changed*: TextChangedHandler
  25. text_align*: AnchorObj
  26. text*: StyleText
  27. LabelRef* = ref LabelObj
  28. let text_changed_handler*: TextChangedHandler = proc(self: LabelRef, text: string) = discard
  29. proc Label*(name: string = "Label"): LabelRef =
  30. ## Creates a new Label.
  31. ##
  32. ## Arguments:
  33. ## - `name` is a node name.
  34. runnableExamples:
  35. var text = Label("Label")
  36. nodepattern(LabelRef)
  37. controlpattern()
  38. result.rect_size.x = 40
  39. result.rect_size.y = 40
  40. result.text = stext""
  41. result.text_align = Anchor(0, 0, 0, 0)
  42. result.on_text_changed = text_changed_handler
  43. result.kind = LABEL_NODE
  44. method draw*(self: LabelRef, w, h: GLfloat) =
  45. ## This uses in the `window.nim`.
  46. procCall self.ControlRef.draw(w, h)
  47. let
  48. x = -w/2 + self.global_position.x
  49. y = h/2 - self.global_position.y
  50. self.text.renderTo(Vector2(x + self.padding.x1, y - self.padding.y1), self.rect_size, self.text_align)
  51. method duplicate*(self: LabelRef): LabelRef {.base.} =
  52. ## Duplicates Label object and create a new Label.
  53. self.deepCopy()
  54. method getText*(self: LabelRef): string {.base.} =
  55. ## Returns `StyleText` as `string`.
  56. ##
  57. ## See also:
  58. ## * `setText method <#setText.e,LabelRef,string,bool>`_
  59. $self.text
  60. method handle*(self: LabelRef, event: InputEvent, mouse_on: var NodeRef) =
  61. ## Handles user input. Thi uses in the `window.nim`.
  62. procCall self.ControlRef.handle(event, mouse_on)
  63. if event.kind in [MOUSE, MOTION]:
  64. let (c, pos) = self.text.getCharUnderPoint(
  65. self.getGlobalMousePosition(), self.global_position + self.rect_size/2 - self.text.getTextSize()/2,
  66. self.text_align)
  67. if not c.isNil() and c.is_url:
  68. var (i, j) = (pos.int, pos.int)
  69. while i - 1 > 0 and self.text.chars[i - 1].is_url:
  70. dec i
  71. while j + 1 < self.text.len and self.text.chars[j + 1].is_url:
  72. inc j
  73. self.text.setUnderline(i, j, true)
  74. self.text.rendered = false
  75. if last_event.pressed and last_event.kind == MOUSE:
  76. openDefaultBrowser(c.url)
  77. else:
  78. for i in self.text.chars:
  79. if i.is_url:
  80. i.setUnderline(false)
  81. self.text.rendered = false
  82. method setText*(self: LabelRef, text: string, save_properties: bool = false) {.base.} =
  83. ## Changes text.
  84. ##
  85. ## Arguments:
  86. ## - `text` is a new Label text.
  87. ## - `save_properties` - saves old text properties, if `true`.
  88. ##
  89. ## See also:
  90. ## * `getText method <#getText.e,LabelRef>`_
  91. var st = stext(text)
  92. if self.text.font.isNil():
  93. self.text.font = standard_font
  94. st.font = self.text.font
  95. if save_properties:
  96. for i in 0..<st.chars.len():
  97. if i < self.text.len():
  98. st.chars[i].color = self.text.chars[i].color
  99. st.chars[i].style = self.text.chars[i].style
  100. self.text = st
  101. self.rect_min_size = self.text.getTextSize()
  102. self.resize(self.rect_size.x, self.rect_size.y, true)
  103. self.text.rendered = false
  104. self.on_text_changed(self, text)
  105. method setTextAlign*(self: LabelRef, x1, y1, x2, y2: float) {.base.} =
  106. ## Changes text alignment.
  107. ##
  108. ## Arguments:
  109. ## - `x1` `y1` - parent anchor.
  110. ## - `x2` `y2` - self anchor.
  111. ##
  112. ## See also:
  113. ## * `setTextAlign method <#setTextAlign.e,LabelRef,AnchorObj>`_
  114. self.text_align = Anchor(x1, y1, x2, y2)
  115. self.text.rendered = false
  116. method setTextAlign*(self: LabelRef, align: AnchorObj) {.base.} =
  117. ## Changes text alignment.
  118. ##
  119. ## See also:
  120. ## * `setTextAlign method <#setTextAlign.e,LabelRef,float,float,float,float>`_
  121. self.text_align = align
  122. self.text.rendered = false
  123. method setTextColor*(self: LabelRef, color: ColorRef) {.base.} =
  124. ## Changes text color.
  125. ##
  126. ## Arguments:
  127. ## - `color` - new text color.
  128. self.text.setColor(color)
  129. self.text.rendered = false
  130. method setTextFont*(self: LabelRef, font: FontPtr) {.base.} =
  131. ## Changes text font.
  132. ##
  133. ## Arguments:
  134. ## - `font` - new text font.
  135. self.text.font = font
  136. self.text.rendered = false
  137. method setStyle*(self: LabelRef, s: StyleSheetRef) =
  138. ## Changes Label stylesheet.
  139. ##
  140. ## Styles:
  141. ## - `text-align` - text alignment. `0.5`; `1 0 1 0`.
  142. ## - `color` - text color. `#ffef`; `rgba(1, 1, 1, 1)`; `rgb(1, 1, 1)`.
  143. procCall self.ControlRef.setStyle(s)
  144. self.text.rendered = false
  145. for i in s.dict:
  146. case i.key
  147. # text-align: 0.5
  148. # text-align: 0.5 0 0.5 0
  149. of "text-align":
  150. let tmp = i.value.split(Whitespace)
  151. if tmp.len() == 1:
  152. if tmp[0] == "center":
  153. self.setTextAlign(0.5, 0.5, 0.5, 0.5)
  154. elif tmp[0] == "left":
  155. self.setTextAlign(0, 0.5, 0, 0.5)
  156. elif tmp[0] == "right":
  157. self.setTextAlign(1, 0.5, 1, 0.5)
  158. elif tmp[0] == "top":
  159. self.setTextAlign(0.5, 0, 0.5, 0)
  160. elif tmp[0] == "bottom":
  161. self.setTextAlign(0.5, 1, 0.5, 1)
  162. else:
  163. let tmp2 = parseFloat(tmp[0])
  164. self.setTextAlign(Anchor(tmp2, tmp2, tmp2, tmp2))
  165. elif tmp.len() == 4:
  166. self.setTextAlign(Anchor(
  167. parseFloat(tmp[0]), parseFloat(tmp[1]),
  168. parseFloat(tmp[2]), parseFloat(tmp[3]))
  169. )
  170. # color: #f6f
  171. of "color":
  172. var clr = Color(i.value)
  173. if not clr.isNil():
  174. self.setTextColor(clr)
  175. else:
  176. discard