Kaynağa Gözat

add EditText node.

SakiKawasaki 5 yıl önce
ebeveyn
işleme
4835820dd8

+ 3 - 2
src/nodesnim.nim

@@ -26,11 +26,12 @@ import
   nodesnim/nodescontrol/box,
   nodesnim/nodescontrol/hbox,
   nodesnim/nodescontrol/vbox,
-  nodesnim/nodescontrol/grid_box
+  nodesnim/nodescontrol/grid_box,
+  nodesnim/nodescontrol/edittext
 
 export
   opengl, glut,
   window, environment,
   vector2, rect2, enums, anchor, color, exceptions, input, image,
   node, scene, canvas,
-  control, color_rect, texture_rect, label, button, box, hbox, vbox, grid_box
+  control, color_rect, texture_rect, label, button, box, hbox, vbox, grid_box, edittext

+ 14 - 0
src/nodesnim/core/image.nim

@@ -10,6 +10,12 @@ import
 discard image.init()
 
 
+type
+  GlTexture* = object
+    texture*: Gluint
+    size*: Vector2Ref
+
+
 proc load*(file: cstring, size: var Vector2Ref): Gluint =
   ## Loads image from file and returns texture ID.
   ##
@@ -37,3 +43,11 @@ proc load*(file: cstring, size: var Vector2Ref): Gluint =
   surface = nil
 
   textureid
+
+
+proc load*(file: cstring): GlTexture =
+  var
+    size: Vector2Ref
+    textureid: Gluint
+  textureid = load(file, size)
+  GlTexture(texture: textureid, size: size)

+ 3 - 0
src/nodesnim/core/input.nim

@@ -13,6 +13,7 @@ type
   InputAction* = object
     kind*: InputEventType
     key_int*: int8
+    key_cint*: cint
     button_index*: cint
     name*, key*: string
 
@@ -22,6 +23,7 @@ type
     kind*: InputEventType
     pressed*: bool
     key_int*: int8
+    key_cint*: cint
     button_index*: cint
     x*, y*, xrel*, yrel*: float
     key*: string
@@ -87,6 +89,7 @@ const
 var
   pressed_keys*: seq[string] = @[]
   pressed_keys_ints*: seq[int8] = @[]
+  pressed_keys_cints*: seq[cint] = @[]
   last_event*: InputEvent = InputEvent()
   last_key_state*: bool = false
   key_state*: bool = false

+ 1 - 1
src/nodesnim/nodescontrol/control.nim

@@ -96,7 +96,7 @@ method handle*(self: ControlPtr, event: InputEvent, mouse_on: var NodePtr) =
     if mouse_pressed and not self.pressed:
       self.pressed = true
       self.click(event.x, event.y)
-  elif not hasmouse:
+  elif not hasmouse or mouse_on != self:
     if not mouse_pressed and self.hovered:
       self.mouse_exit(event.x, event.y)
       self.hovered = false

+ 152 - 0
src/nodesnim/nodescontrol/edittext.nim

@@ -0,0 +1,152 @@
+# author: Ethosa
+import
+  strutils,
+  ../thirdparty/opengl,
+  ../thirdparty/opengl/glut,
+
+  ../core/vector2,
+  ../core/rect2,
+  ../core/anchor,
+  ../core/input,
+  ../core/enums,
+  ../core/color,
+
+  ../nodes/node,
+  control
+
+
+type
+  EditTextObj* = object of ControlPtr
+    blit_caret*: bool
+    blit_speed*: float
+    blit_time*: float
+    caret_position*: int
+    font*: pointer          ## Glut font data.
+    spacing*: float         ## Font spacing.
+    size*: float            ## Font size.
+    text*: string           ## EditText text.
+    hint_text*: string
+    color*: ColorRef        ## Text color.
+    hint_color*: ColorRef   ## Hint color.
+    background_color*: ColorRef
+    caret_color*: ColorRef
+    text_align*: AnchorRef  ## Text align.
+  EditTextPtr* = ptr EditTextObj
+
+
+proc EditText*(name: string, variable: var EditTextObj): EditTextPtr =
+  nodepattern(EditTextObj)
+  controlpattern()
+  variable.rect_size.x = 64
+  variable.rect_size.y = 32
+  variable.text = ""
+  variable.font = GLUT_BITMAP_HELVETICA_12
+  variable.size = 12
+  variable.spacing = 2
+  variable.text_align = Anchor(0, 0, 0, 0)
+  variable.color = Color(1f, 1f, 1f)
+  variable.hint_color = Color(0.8, 0.8, 0.8)
+  variable.background_color = Color(0x212121ff)
+  variable.hint_text = "Edit text ..."
+  variable.caret_position = 0
+  variable.blit_caret = true
+  variable.caret_color = Color(1f, 1f, 1f, 0.5)
+  variable.blit_speed = 0.002
+  variable.blit_time = 0f
+
+proc EditText*(obj: var EditTextObj): EditTextPtr {.inline.} =
+  EditText("EditText", obj)
+
+
+method draw*(self: EditTextPtr, w, h: GLfloat) =
+  self.calcGlobalPosition()
+  let
+    x = -w/2 + self.global_position.x
+    y = h/2 - self.global_position.y
+    text =
+      if self.text.len() > 0:
+        self.text
+      else:
+        self.hint_text
+    color =
+      if self.text.len() > 0:
+        self.color
+      else:
+        self.hint_color
+
+  glColor4f(self.background_color.r, self.background_color.g, self.background_color.b, self.background_color.a)
+  glRectf(x, y, x+self.rect_size.x, y-self.rect_size.y)
+  var
+    th = 0f
+    char_num = 0
+
+  for line in text.splitLines():  # get text height
+    th += self.spacing + self.size
+  if th != 0:
+    th -= self.spacing
+  var ty = y - self.rect_size.y*self.text_align.y1 + th*self.text_align.y2 - self.size
+
+  for line in text.splitLines():
+    var tw = self.font.glutBitmapLength(line).float
+    # Draw text:
+    var tx = x + self.rect_size.x*self.text_align.x1 - tw * self.text_align.x2
+    for c in line:
+      glColor4f(color.r, color.g, color.b, color.a)
+      glRasterPos2f(tx, ty)  # set char position
+      self.font.glutBitmapCharacter(c.int)  # render char
+      tx += self.font.glutBitmapWidth(c.int).float
+
+      inc char_num
+      if char_num == self.caret_position and self.blit_caret and self.blit_time > 1f:
+        glColor4f(self.caret_color.r, self.caret_color.g, self.caret_color.b, self.caret_color.a)
+        glRectf(tx, ty, tx+2, ty+self.size)
+        if self.blit_time > 2f:
+          self.blit_time = 0f
+    inc char_num
+    ty -= self.spacing + self.size
+
+  self.blit_time += self.blit_speed
+
+  # Press
+  if self.pressed:
+    self.press(last_event.x, last_event.y)
+
+
+method handle*(self: EditTextPtr, event: InputEvent, mouse_on: var NodePtr) =
+  procCall self.ControlPtr.handle(event, mouse_on)
+
+  if self.focused:
+    if event.kind == KEYBOARD:
+      if event.key_cint in pressed_keys_cints:  # Special chars
+        if event.key_cint == K_LEFT and self.caret_position > 0:
+          self.caret_position -= 1
+        elif event.key_cint == K_RIGHT and self.caret_position < self.text.len():
+          self.caret_position += 1
+      elif event.key in pressed_keys:  # Normal chars
+        if event.key_int == 8:  # Backspace
+          if self.caret_position > 1 and self.caret_position < self.text.len():
+            self.text = self.text[0..self.caret_position-2] & self.text[self.caret_position..^1]
+            self.caret_position -= 1
+          elif self.caret_position == self.text.len() and self.caret_position > 0:
+            self.text = self.text[0..^2]
+            self.caret_position -= 1
+          elif self.caret_position == 1:
+            self.text = self.text[1..^1]
+            self.caret_position -= 1
+        elif self.caret_position > 0 and self.caret_position < self.text.len():
+          self.text = self.text[0..self.caret_position-1] & event.key & self.text[self.caret_position..^1]
+          self.caret_position += 1
+        elif self.caret_position == 0:
+          self.text = event.key & self.text
+          self.caret_position += 1
+        elif self.caret_position == self.text.len():
+          self.text &= event.key
+          self.caret_position += 1
+
+method setTextAlign*(self: EditTextPtr, align: AnchorRef) {.base.} =
+  ## Changes text align.
+  self.text_align = align
+
+method setTextAlign*(self: EditTextPtr, x1, y1, x2, y2: float) {.base.} =
+  ## Changes text align.
+  self.text_align = Anchor(x1, y1, x2, y2)

+ 7 - 1
src/nodesnim/nodescontrol/label.nim

@@ -55,7 +55,7 @@ method draw*(self: LabelPtr, w, h: GLfloat) =
     th += self.spacing + self.size
   if th != 0:
     th -= self.spacing
-  var ty = y - self.rect_size.y*self.text_align.y1 + th*self.text_align.y2
+  var ty = y - self.rect_size.y*self.text_align.y1 + th*self.text_align.y2 - self.size
 
   for line in self.text.splitLines():
     var tw = self.font.glutBitmapLength(line).float
@@ -70,3 +70,9 @@ method draw*(self: LabelPtr, w, h: GLfloat) =
   # Press
   if self.pressed:
     self.press(last_event.x, last_event.y)
+
+method setTextAlign*(self: LabelPtr, align: AnchorRef) {.base.} =
+  self.text_align = align
+
+method setTextAlign*(self: LabelPtr, x1, y1, x2, y2: float) {.base.} =
+  self.text_align = Anchor(x1, y1, x2, y2)

+ 4 - 0
src/nodesnim/nodescontrol/texture_rect.nim

@@ -102,3 +102,7 @@ method loadTexture*(self: TextureRectPtr, file: cstring) {.base.} =
   var size: Vector2Ref = Vector2Ref()
   self.texture = load(file, size)
   self.texture_size = size
+
+method setTexture*(self: TextureRectPtr, gltexture: GlTexture) {.base.} =
+  self.texture = gltexture.texture
+  self.texture_size = gltexture.size

+ 42 - 0
src/nodesnim/window.nim

@@ -90,6 +90,8 @@ proc mouse(button, state, x, y: cint) {.cdecl.} =
 
 proc keyboardpress(c: int8, x, y: cint) {.cdecl.} =
   ## Called when press any key on keyboard.
+  if c < 0:
+    return
   let key = $c.char
   check(InputEventKeyboard, last_event.pressed, true)
   last_event.key = key
@@ -107,6 +109,8 @@ proc keyboardpress(c: int8, x, y: cint) {.cdecl.} =
 
 proc keyboardup(c: int8, x, y: cint) {.cdecl.} =
   ## Called when any key no more pressed.
+  if c < 0:
+    return
   let key = $c.char
   check(InputEventKeyboard, false, false)
   last_event.key = key
@@ -126,6 +130,42 @@ proc keyboardup(c: int8, x, y: cint) {.cdecl.} =
 
   current_scene.handleScene(last_event, mouse_on, paused)
 
+proc keyboardspecialpress(c: cint, x, y: cint) {.cdecl.} =
+  ## Called when press any key on keyboard.
+  if c < 0:
+    return
+  check(InputEventKeyboard, last_event.pressed, true)
+  last_event.key_cint = c
+  last_event.x = x.float
+  last_event.y = y.float
+  if c notin pressed_keys_cints:
+    pressed_keys_cints.add(c)
+  last_event.kind = KEYBOARD
+  last_key_state = key_state
+  key_state = true
+
+  current_scene.handleScene(last_event, mouse_on, paused)
+
+proc keyboardspecialup(c: cint, x, y: cint) {.cdecl.} =
+  ## Called when any key no more pressed.
+  if c < 0:
+    return
+  check(InputEventKeyboard, false, false)
+  last_event.key_cint = c
+  last_event.x = x.float
+  last_event.y = y.float
+  last_event.kind = KEYBOARD
+  last_key_state = key_state
+  key_state = false
+  var i = 0
+  for k in pressed_keys_cints:
+    if k == c:
+      pressed_keys_cints.delete(i)
+      break
+    inc i
+
+  current_scene.handleScene(last_event, mouse_on, paused)
+
 proc motion(x, y: cint) {.cdecl.} =
   ## Called on any mouse motion.
   last_event.kind = MOTION
@@ -207,6 +247,8 @@ proc windowLaunch* =
   glutMouseFunc(mouse)
   glutKeyboardFunc(keyboardpress)
   glutKeyboardUpFunc(keyboardup)
+  glutSpecialFunc(keyboardspecialpress)
+  glutSpecialUpFunc(keyboardspecialup)
   glutMotionFunc(motion)
   glutPassiveMotionFunc(motion)
   if main_scene == nil:

+ 2 - 0
tests/README.md

@@ -14,3 +14,5 @@
 12. [Use Box node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test12.nim)
 13. [Use HBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test13.nim)
 14. [Use VBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test14.nim)
+15. [Use GridBox node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test15.nim)
+16. [Use TextEdit node.](https://github.com/Ethosa/nodesnim/blob/master/tests/test16.nim)

+ 23 - 0
tests/test16.nim

@@ -0,0 +1,23 @@
+# --- Test 16. Use EditText node. --- #
+import nodesnim
+
+
+Window("hello world")
+
+var
+  mainobj: SceneObj
+  main = Scene("Main", mainobj)
+
+  edittextobj: EditTextObj
+  edittext = EditText(edittextobj)
+
+main.addChild(edittext)
+
+edittext.color = Color(1f, 1f, 1f)  # default text color.
+edittext.hint_color = Color(1f, 0.6, 1f)
+edittext.resize(512, 256)
+
+
+addScene(main)
+setMainScene("Main")
+windowLaunch()

+ 1 - 1
tests/test8.nim

@@ -15,7 +15,7 @@ main.addChild(texturerect)
 
 texturerect.loadTexture("assets/sharp.jpg")  # Load image from file.
 texturerect.resize(256, 256)
-texturerect.texture_mode = TEXTURE_CROP
+texturerect.texture_mode = TEXTURE_KEEP_ASPECT_RATIO  # Can be also TEXTURE_CROP or TEXTURE_FILL_XY
 texturerect.texture_anchor = Anchor(0.5, 1, 0.5, 1)
 
 

+ 1 - 1
tests/test9.nim

@@ -14,7 +14,7 @@ var
 main.addChild(label)
 
 label.text = "Hello, world!\nsecondline\nThis is a long sentence."  # Change label text.
-label.text_align = Anchor(0.2, 0.5, 0.2, 0.5)  # try to change it ^^.
+label.setTextAlign(0.2, 0.5, 0.2, 0.5)  # try to change it ^^.
 label.setSizeAnchor(1, 1)
 label.color = Color(1f, 1f, 1f)  # default text color.