123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- # author: Ethosa
- ## It provides primitive scroll box.
- import ../thirdparty/sdl2 except Color, glBindTexture
- import
- ../thirdparty/gl,
- ../core/vector2,
- ../core/rect2,
- ../core/anchor,
- ../core/input,
- ../core/enums,
- ../core/color,
- ../core/themes,
- ../private/templates,
- ../nodes/node,
- ../nodes/canvas,
- ../graphics/drawable,
- control
- type
- ScrollObj* = object of ControlObj
- thumb_y_has_mouse*, thumb_x_has_mouse*: bool
- thumb_width*, thumb_height*: float
- viewport_w*, viewport_h*: float
- viewport_x*, viewport_y*: float
- thumb_color*: ColorRef
- back_color*: ColorRef
- ScrollRef* = ref ScrollObj
- proc Scroll*(name: string = "Scroll"): ScrollRef =
- ## Creates a new Scroll.
- ##
- ## Arguments:
- ## - `name` is a node name.
- runnableExamples:
- var sc = Scroll("Scroll")
- nodepattern(ScrollRef)
- controlpattern()
- result.rect_size.x = 256
- result.rect_size.y = 256
- result.viewport_h = 256
- result.viewport_w = 256
- result.viewport_x = 0
- result.viewport_y = 0
- result.thumb_width = 8
- result.thumb_height = 8
- result.back_color = current_theme~accent_dark
- result.thumb_color = current_theme~accent
- result.thumb_y_has_mouse = false
- result.thumb_x_has_mouse = false
- result.mousemode = MOUSEMODE_IGNORE
- result.kind = SCROLL_NODE
- method addChild*(self: ScrollRef, other: NodeRef) =
- ## Adds a new node in Scroll.
- ##
- ## Arguments:
- ## - `other` is other Node.
- if self.children.len() == 0:
- self.children.add(other)
- other.parent = self
- method duplicate*(self: ScrollRef): ScrollRef {.base.} =
- ## Duplicates Scroll object and create a new Scroll.
- self.deepCopy()
- method draw*(self: ScrollRef, w, h: GLfloat) =
- ## This uses in the `window.nim`.
- {.warning[LockLevel]: off.}
- let
- x = -w/2 + self.global_position.x
- y = h/2 - self.global_position.y
- self.background.draw(x, y, self.rect_size.x, self.rect_size.y)
- # Press
- if self.pressed:
- self.on_press(self, last_event.x, last_event.y)
- method scrollBy*(self: ScrollRef, x, y: float) {.base.} =
- ## Scrolls by `x` and `y`, if available.
- if x + self.viewport_x + self.viewport_w < self.rect_size.x and x + self.viewport_x > 0:
- self.viewport_x += x
- elif x < 0:
- self.viewport_x = 0
- elif x > 0:
- self.viewport_x = self.rect_size.x - self.viewport_w
- if y + self.viewport_y + self.viewport_h < self.rect_size.y and y + self.viewport_y > 0:
- self.viewport_y += y
- elif y < 0:
- self.viewport_y = 0
- elif y > 0:
- self.viewport_y = self.rect_size.y - self.viewport_h
- method scrollTo*(self: ScrollRef, x, y: float) {.base.} =
- ## Scrolls to `x` and `y` position.
- if x + self.viewport_w < self.rect_size.x and x > 0:
- self.viewport_x = x
- elif x < 0:
- self.viewport_x = 0
- elif x > 0:
- self.viewport_x = self.rect_size.x - self.viewport_w
- if y + self.viewport_h < self.rect_size.y and y > 0:
- self.viewport_y = y
- elif y < 0:
- self.viewport_y = 0
- elif y > 0:
- self.viewport_y = self.rect_size.y - self.viewport_h
- method handle*(self: ScrollRef, event: InputEvent, mouse_on: var NodeRef) =
- ## handles user input. This uses in the `window.nim`.
- procCall self.ControlRef.handle(event, mouse_on)
- let
- mouse_in = Rect2(self.global_position, Vector2(self.viewport_w, self.viewport_h)).contains(event.x, event.y)
- thumb_h = self.viewport_h * (self.viewport_h / self.rect_size.y)
- thumb_w = self.viewport_w * (self.viewport_w / self.rect_size.x)
- thumb_x = self.viewport_w * (self.viewport_x / self.rect_size.x)
- thumb_y = self.viewport_h * (self.viewport_y / self.rect_size.y)
- mouse_in_y = Rect2(
- self.global_position.x + self.viewport_w - self.thumb_width,
- self.global_position.y + thumb_y,
- self.thumb_width,
- thumb_h
- ).contains(event.x, event.y)
- mouse_in_x = Rect2(
- self.global_position.x + thumb_x,
- self.global_position.y + self.viewport_h - self.thumb_height,
- thumb_w,
- self.thumb_height
- ).contains(event.x, event.y)
- if mouse_in: # Keyboard movement
- if event.kind == KEYBOARD:
- if event.key_int in pressed_keys_cint: # Special chars
- if event.key_int == K_UP:
- self.scrollBy(0, -40)
- elif event.key_int == K_DOWN:
- self.scrollBy(0, 40)
- elif event.kind == WHEEL:
- self.scrollBy(0, -20 * event.yrel)
- # Mouse Y
- if (mouse_in_y and mouse_pressed and event.kind == MOUSE) or self.thumb_y_has_mouse:
- self.thumb_y_has_mouse = true
- self.scrollBy(0, event.yrel)
- mouse_on = self
- if not mouse_pressed and self.thumb_y_has_mouse:
- self.thumb_y_has_mouse = false
- mouse_on = nil
- # Mouse X
- if (mouse_in_x and mouse_pressed and event.kind == MOUSE) or self.thumb_x_has_mouse:
- self.thumb_x_has_mouse = true
- self.scrollBy(event.xrel, 0)
- mouse_on = self
- if not mouse_pressed and self.thumb_x_has_mouse:
- self.thumb_x_has_mouse = false
- mouse_on = nil
- method postdraw*(self: ScrollRef, w, h: GLfloat) =
- ## This uses in the `window.nim`.
- let
- x = -w/2 + self.global_position.x
- y = h/2 - self.global_position.y
- if self.children.len() > 0:
- var child = self.children[0]
- self.resize(child.CanvasRef.rect_size.x, child.CanvasRef.rect_size.y)
- let
- thumb_h = self.viewport_h * (self.viewport_h / self.rect_size.y)
- thumb_w = self.viewport_w * (self.viewport_w / self.rect_size.x)
- thumb_x = self.viewport_w * (self.viewport_x / self.rect_size.x)
- thumb_y = self.viewport_h * (self.viewport_y / self.rect_size.y)
- child.CanvasRef.position.x = -self.viewport_x
- child.CanvasRef.position.y = -self.viewport_y
- # Vertical
- if self.viewport_h < self.rect_size.y:
- # Back:
- glColor4f(self.back_color.r, self.back_color.g, self.back_color.b, self.back_color.a)
- glRectf(x + self.viewport_w - self.thumb_width, y, x+self.viewport_w, y-self.viewport_h)
- # Thumb:
- glColor4f(self.thumb_color.r, self.thumb_color.g, self.thumb_color.b, self.thumb_color.a)
- glRectf(x + self.viewport_w - self.thumb_width, y - thumb_y, x+self.viewport_w, y - thumb_y - thumb_h)
- # Horizontal
- if self.viewport_w < self.rect_size.x:
- # Back:
- glColor4f(self.back_color.r, self.back_color.g, self.back_color.b, self.back_color.a)
- glRectf(x, y - self.viewport_h + self.thumb_height, x + self.viewport_w - self.thumb_width, y-self.viewport_h)
- # Thumb:
- glColor4f(self.thumb_color.r, self.thumb_color.g, self.thumb_color.b, self.thumb_color.a)
- glRectf(x + thumb_x, y - self.viewport_h + self.thumb_height, x + thumb_x + thumb_w, y-self.viewport_h)
|