scroll.nim 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. # author: Ethosa
  2. ## It provides primitive scroll box.
  3. import ../thirdparty/sdl2 except Color, glBindTexture
  4. import
  5. ../thirdparty/gl,
  6. ../core/vector2,
  7. ../core/rect2,
  8. ../core/anchor,
  9. ../core/input,
  10. ../core/enums,
  11. ../core/color,
  12. ../core/themes,
  13. ../private/templates,
  14. ../nodes/node,
  15. ../nodes/canvas,
  16. ../graphics/drawable,
  17. control
  18. type
  19. ScrollObj* = object of ControlObj
  20. thumb_y_has_mouse*, thumb_x_has_mouse*: bool
  21. thumb_width*, thumb_height*: float
  22. viewport_w*, viewport_h*: float
  23. viewport_x*, viewport_y*: float
  24. thumb_color*: ColorRef
  25. back_color*: ColorRef
  26. ScrollRef* = ref ScrollObj
  27. proc Scroll*(name: string = "Scroll"): ScrollRef =
  28. ## Creates a new Scroll.
  29. ##
  30. ## Arguments:
  31. ## - `name` is a node name.
  32. runnableExamples:
  33. var sc = Scroll("Scroll")
  34. nodepattern(ScrollRef)
  35. controlpattern()
  36. result.rect_size.x = 256
  37. result.rect_size.y = 256
  38. result.viewport_h = 256
  39. result.viewport_w = 256
  40. result.viewport_x = 0
  41. result.viewport_y = 0
  42. result.thumb_width = 8
  43. result.thumb_height = 8
  44. result.back_color = current_theme~accent_dark
  45. result.thumb_color = current_theme~accent
  46. result.thumb_y_has_mouse = false
  47. result.thumb_x_has_mouse = false
  48. result.mousemode = MOUSEMODE_IGNORE
  49. result.kind = SCROLL_NODE
  50. method addChild*(self: ScrollRef, other: NodeRef) =
  51. ## Adds a new node in Scroll.
  52. ##
  53. ## Arguments:
  54. ## - `other` is other Node.
  55. if self.children.len() == 0:
  56. self.children.add(other)
  57. other.parent = self
  58. method duplicate*(self: ScrollRef): ScrollRef {.base.} =
  59. ## Duplicates Scroll object and create a new Scroll.
  60. self.deepCopy()
  61. method draw*(self: ScrollRef, w, h: GLfloat) =
  62. ## This uses in the `window.nim`.
  63. {.warning[LockLevel]: off.}
  64. let
  65. x = -w/2 + self.global_position.x
  66. y = h/2 - self.global_position.y
  67. self.background.draw(x, y, self.rect_size.x, self.rect_size.y)
  68. # Press
  69. if self.pressed:
  70. self.on_press(self, last_event.x, last_event.y)
  71. method scrollBy*(self: ScrollRef, x, y: float) {.base.} =
  72. ## Scrolls by `x` and `y`, if available.
  73. if x + self.viewport_x + self.viewport_w < self.rect_size.x and x + self.viewport_x > 0:
  74. self.viewport_x += x
  75. elif x < 0:
  76. self.viewport_x = 0
  77. elif x > 0:
  78. self.viewport_x = self.rect_size.x - self.viewport_w
  79. if y + self.viewport_y + self.viewport_h < self.rect_size.y and y + self.viewport_y > 0:
  80. self.viewport_y += y
  81. elif y < 0:
  82. self.viewport_y = 0
  83. elif y > 0:
  84. self.viewport_y = self.rect_size.y - self.viewport_h
  85. method scrollTo*(self: ScrollRef, x, y: float) {.base.} =
  86. ## Scrolls to `x` and `y` position.
  87. if x + self.viewport_w < self.rect_size.x and x > 0:
  88. self.viewport_x = x
  89. elif x < 0:
  90. self.viewport_x = 0
  91. elif x > 0:
  92. self.viewport_x = self.rect_size.x - self.viewport_w
  93. if y + self.viewport_h < self.rect_size.y and y > 0:
  94. self.viewport_y = y
  95. elif y < 0:
  96. self.viewport_y = 0
  97. elif y > 0:
  98. self.viewport_y = self.rect_size.y - self.viewport_h
  99. method handle*(self: ScrollRef, event: InputEvent, mouse_on: var NodeRef) =
  100. ## handles user input. This uses in the `window.nim`.
  101. procCall self.ControlRef.handle(event, mouse_on)
  102. let
  103. mouse_in = Rect2(self.global_position, Vector2(self.viewport_w, self.viewport_h)).contains(event.x, event.y)
  104. thumb_h = self.viewport_h * (self.viewport_h / self.rect_size.y)
  105. thumb_w = self.viewport_w * (self.viewport_w / self.rect_size.x)
  106. thumb_x = self.viewport_w * (self.viewport_x / self.rect_size.x)
  107. thumb_y = self.viewport_h * (self.viewport_y / self.rect_size.y)
  108. mouse_in_y = Rect2(
  109. self.global_position.x + self.viewport_w - self.thumb_width,
  110. self.global_position.y + thumb_y,
  111. self.thumb_width,
  112. thumb_h
  113. ).contains(event.x, event.y)
  114. mouse_in_x = Rect2(
  115. self.global_position.x + thumb_x,
  116. self.global_position.y + self.viewport_h - self.thumb_height,
  117. thumb_w,
  118. self.thumb_height
  119. ).contains(event.x, event.y)
  120. if mouse_in: # Keyboard movement
  121. if event.kind == KEYBOARD:
  122. if event.key_int in pressed_keys_cint: # Special chars
  123. if event.key_int == K_UP:
  124. self.scrollBy(0, -40)
  125. elif event.key_int == K_DOWN:
  126. self.scrollBy(0, 40)
  127. elif event.kind == WHEEL:
  128. self.scrollBy(0, -20 * event.yrel)
  129. # Mouse Y
  130. if (mouse_in_y and mouse_pressed and event.kind == MOUSE) or self.thumb_y_has_mouse:
  131. self.thumb_y_has_mouse = true
  132. self.scrollBy(0, event.yrel)
  133. mouse_on = self
  134. if not mouse_pressed and self.thumb_y_has_mouse:
  135. self.thumb_y_has_mouse = false
  136. mouse_on = nil
  137. # Mouse X
  138. if (mouse_in_x and mouse_pressed and event.kind == MOUSE) or self.thumb_x_has_mouse:
  139. self.thumb_x_has_mouse = true
  140. self.scrollBy(event.xrel, 0)
  141. mouse_on = self
  142. if not mouse_pressed and self.thumb_x_has_mouse:
  143. self.thumb_x_has_mouse = false
  144. mouse_on = nil
  145. method postdraw*(self: ScrollRef, w, h: GLfloat) =
  146. ## This uses in the `window.nim`.
  147. let
  148. x = -w/2 + self.global_position.x
  149. y = h/2 - self.global_position.y
  150. if self.children.len() > 0:
  151. var child = self.children[0]
  152. self.resize(child.CanvasRef.rect_size.x, child.CanvasRef.rect_size.y)
  153. let
  154. thumb_h = self.viewport_h * (self.viewport_h / self.rect_size.y)
  155. thumb_w = self.viewport_w * (self.viewport_w / self.rect_size.x)
  156. thumb_x = self.viewport_w * (self.viewport_x / self.rect_size.x)
  157. thumb_y = self.viewport_h * (self.viewport_y / self.rect_size.y)
  158. child.CanvasRef.position.x = -self.viewport_x
  159. child.CanvasRef.position.y = -self.viewport_y
  160. # Vertical
  161. if self.viewport_h < self.rect_size.y:
  162. # Back:
  163. glColor4f(self.back_color.r, self.back_color.g, self.back_color.b, self.back_color.a)
  164. glRectf(x + self.viewport_w - self.thumb_width, y, x+self.viewport_w, y-self.viewport_h)
  165. # Thumb:
  166. glColor4f(self.thumb_color.r, self.thumb_color.g, self.thumb_color.b, self.thumb_color.a)
  167. glRectf(x + self.viewport_w - self.thumb_width, y - thumb_y, x+self.viewport_w, y - thumb_y - thumb_h)
  168. # Horizontal
  169. if self.viewport_w < self.rect_size.x:
  170. # Back:
  171. glColor4f(self.back_color.r, self.back_color.g, self.back_color.b, self.back_color.a)
  172. glRectf(x, y - self.viewport_h + self.thumb_height, x + self.viewport_w - self.thumb_width, y-self.viewport_h)
  173. # Thumb:
  174. glColor4f(self.thumb_color.r, self.thumb_color.g, self.thumb_color.b, self.thumb_color.a)
  175. glRectf(x + thumb_x, y - self.viewport_h + self.thumb_height, x + thumb_x + thumb_w, y-self.viewport_h)