scroll.nim 6.4 KB

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