rich_edit_text.nim 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # author: Ethosa
  2. import
  3. ../thirdparty/opengl,
  4. ../thirdparty/opengl/glut,
  5. ../core/vector2,
  6. ../core/rect2,
  7. ../core/anchor,
  8. ../core/input,
  9. ../core/enums,
  10. ../core/color,
  11. ../core/color_text,
  12. ../nodes/node,
  13. control
  14. type
  15. RichEditTextObj* = object of ControlPtr
  16. blit_caret*: bool
  17. blit_speed*: float
  18. blit_time*: float
  19. caret_position*: int
  20. font*: pointer ## Glut font data.
  21. spacing*: float ## Font spacing.
  22. size*: float ## Font size.
  23. text*: ColorTextRef
  24. hint_text*: ColorTextRef
  25. caret_color*: ColorRef
  26. text_align*: AnchorRef ## Text align.
  27. RichEditTextPtr* = ptr RichEditTextObj
  28. proc RichEditText*(name: string, variable: var RichEditTextObj): RichEditTextPtr =
  29. nodepattern(RichEditTextObj)
  30. controlpattern()
  31. variable.rect_size.x = 64
  32. variable.rect_size.y = 32
  33. variable.text = clrtext""
  34. variable.font = GLUT_BITMAP_HELVETICA_12
  35. variable.size = 12
  36. variable.spacing = 2
  37. variable.text_align = Anchor(0, 0, 0, 0)
  38. variable.hint_text = clrtext("Edit text ...", Color(0.8, 0.8, 0.8))
  39. variable.caret_position = 0
  40. variable.blit_caret = true
  41. variable.caret_color = Color(1f, 1f, 1f, 0.5)
  42. variable.blit_speed = 0.002
  43. variable.blit_time = 0f
  44. proc RichEditText*(obj: var RichEditTextObj): RichEditTextPtr {.inline.} =
  45. RichEditText("RichEditText", obj)
  46. method draw*(self: RichEditTextPtr, w, h: GLfloat) =
  47. self.calcGlobalPosition()
  48. let
  49. x = -w/2 + self.global_position.x
  50. y = h/2 - self.global_position.y
  51. text =
  52. if self.text.len() > 0:
  53. self.text
  54. else:
  55. self.hint_text
  56. glColor4f(self.background_color.r, self.background_color.g, self.background_color.b, self.background_color.a)
  57. glRectf(x, y, x+self.rect_size.x, y-self.rect_size.y)
  58. var
  59. th = 0f
  60. char_num = 0
  61. for line in text.splitLines(): # get text height
  62. th += self.spacing + self.size
  63. if th != 0:
  64. th -= self.spacing
  65. var ty = y - self.rect_size.y*self.text_align.y1 + th*self.text_align.y2 - self.size
  66. for line in text.splitLines():
  67. var tw = self.font.glutBitmapLength($line).float
  68. # Draw text:
  69. var tx = x + self.rect_size.x*self.text_align.x1 - tw * self.text_align.x2
  70. for c in line.chars:
  71. let
  72. cw = self.font.glutBitmapWidth(c.c.int).float
  73. right =
  74. if self.text_align.x2 > 0.9 and self.text_align.x1 > 0.9:
  75. 1f
  76. else:
  77. 0f
  78. bottom =
  79. if self.text_align.y2 > 0.9 and self.text_align.y1 > 0.9:
  80. 1f
  81. else:
  82. 0f
  83. if tx >= x and tx < x + self.rect_size.x+right and ty <= y and ty > y - self.rect_size.y+bottom:
  84. glColor4f(c.color.r, c.color.g, c.color.b, c.color.a)
  85. glRasterPos2f(tx, ty) # set char position
  86. self.font.glutBitmapCharacter(c.c.int) # render char
  87. inc char_num
  88. if char_num == self.caret_position and self.blit_caret and self.blit_time > 1f:
  89. glColor4f(self.caret_color.r, self.caret_color.g, self.caret_color.b, self.caret_color.a)
  90. glRectf(tx+cw, ty, tx+cw+2, ty+self.size)
  91. if self.blit_time > 2f:
  92. self.blit_time = 0f
  93. tx += cw
  94. inc char_num
  95. ty -= self.spacing + self.size
  96. self.blit_time += self.blit_speed
  97. # Press
  98. if self.pressed:
  99. self.press(last_event.x, last_event.y)
  100. method dublicate*(self: RichEditTextPtr, obj: var RichEditTextObj): RichEditTextPtr {.base.} =
  101. obj = self[]
  102. obj.addr
  103. method handle*(self: RichEditTextPtr, event: InputEvent, mouse_on: var NodePtr) =
  104. procCall self.ControlPtr.handle(event, mouse_on)
  105. if self.focused:
  106. if event.kind == KEYBOARD:
  107. if event.key_cint in pressed_keys_cints: # Special chars
  108. if event.key_cint == K_LEFT and self.caret_position > 0:
  109. self.caret_position -= 1
  110. elif event.key_cint == K_RIGHT and self.caret_position < self.text.len():
  111. self.caret_position += 1
  112. elif event.key in pressed_keys: # Normal chars
  113. if event.key_int == 8: # Backspace
  114. if self.caret_position > 1 and self.caret_position < self.text.len():
  115. self.text = self.text[0..self.caret_position-2] & self.text[self.caret_position..^1]
  116. self.caret_position -= 1
  117. elif self.caret_position == self.text.len() and self.caret_position > 0:
  118. self.text = self.text[0..^2]
  119. self.caret_position -= 1
  120. elif self.caret_position == 1:
  121. self.text = self.text[1..^1]
  122. self.caret_position -= 1
  123. elif self.caret_position > 0 and self.caret_position < self.text.len():
  124. self.text = self.text[0..self.caret_position-1] & clrtext(event.key) & self.text[self.caret_position..^1]
  125. self.caret_position += 1
  126. elif self.caret_position == 0:
  127. self.text = clrtext(event.key) & self.text
  128. self.caret_position += 1
  129. elif self.caret_position == self.text.len():
  130. self.text &= clrtext(event.key)
  131. self.caret_position += 1
  132. method setTextAlign*(self: RichEditTextPtr, align: AnchorRef) {.base.} =
  133. ## Changes text align.
  134. self.text_align = align
  135. method setTextAlign*(self: RichEditTextPtr, x1, y1, x2, y2: float) {.base.} =
  136. ## Changes text align.
  137. self.text_align = Anchor(x1, y1, x2, y2)
  138. method setText*(self: RichEditTextPtr, value: ColorTextRef) {.base.} =
  139. self.text = value