Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Layout #185

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 52 additions & 9 deletions src/fidget.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ proc preNode(kind: NodeKind, id: string) =
current.textStyle = parent.textStyle
current.cursorColor = parent.cursorColor
current.highlightColor = parent.highlightColor
current.transparency = parent.transparency
nodeStack.add(current)
inc parent.diffIndex

Expand Down Expand Up @@ -273,28 +272,60 @@ proc orgBox*(x, y, w, h: int|float32|float32) =
current.orgBox.w = float32 w
current.orgBox.h = float32 h

proc box*(x, y, w, h: float32) =
## Sets the box dimensions.
current.box.x = x
current.box.y = y
current.box.w = w
current.box.h = h

proc box*(
x: int|float32|float64,
y: int|float32|float64,
w: int|float32|float64,
h: int|float32|float64
) =
## Sets the box dimensions with integers
current.box.x = x.float32
current.box.y = y.float32
current.box.w = w.float32
current.box.h = h.float32
## Always set box before orgBox when doing constraints.
box(float32 x, float32 y, float32 w, float32 h)
orgBox(float32 x, float32 y, float32 w, float32 h)

proc box*(rect: Rect) =
## Sets the box dimensions with integers
box(rect.x, rect.y, rect.w, rect.h)

proc x*(x: int|float32|float64) =
current.box.x = x.float32
current.orgBox.x = x.float32

proc y*(y: int|float32|float64) =
current.box.y = y.float32
current.orgBox.y = y.float32

proc w*(w: int|float32|float64) =
current.box.w = w.float32
current.orgBox.w = w.float32

proc h*(h: int|float32|float64) =
current.box.h = h.float32
current.orgBox.h = h.float32

proc xy*(x, y: int|float32|float64) =
current.box.x = x.float32
current.box.y = y.float32
current.orgBox.x = x.float32
current.orgBox.y = y.float32

proc xy*(xy: Vec2) =
current.box.xy = xy
current.orgBox.xy = xy

proc wh*(w, h: int|float32|float64) =
current.box.w = w.float32
current.box.h = h.float32
current.orgBox.w = w.float32
current.orgBox.h = h.float32

proc wh*(wh: Vec2) =
current.box.wh = wh
current.orgBox.wh = wh

proc rotation*(rotationInDeg: float32) =
## Sets rotation in degrees.
current.rotation = rotationInDeg
Expand Down Expand Up @@ -412,6 +443,14 @@ proc layoutAlign*(mode: LayoutAlign) =
## Set the layout alignment mode.
current.layoutAlign = mode

proc layoutWeight*(weight: float32) =
## Set the layout weight.
current.layoutWeight = weight

proc wrapContent*(flag: bool) =
## Set the whether wrap content or not.
current.wrapContent = flag

proc layout*(mode: LayoutMode) =
## Set the layout mode.
current.layoutMode = mode
Expand Down Expand Up @@ -448,6 +487,10 @@ template binding*(stringVariable: untyped) =
keyboard.focus(current)
onClickOutside:
keyboard.unFocus(current)
refresh()
if not current.multiline and buttonRelease[ENTER]:
keyboard.unFocus(current)
refresh()
onInput:
if stringVariable != keyboard.input:
stringVariable = keyboard.input
Expand Down
93 changes: 71 additions & 22 deletions src/fidget/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import chroma, input, sequtils, tables, vmath, json, bumpy
when defined(js):
import dom2, html/ajax
else:
import typography, typography/textboxes, tables, asyncfutures
import typography, typography/textboxes, asyncfutures

const
clearColor* = color(0, 0, 0, 0)
Expand Down Expand Up @@ -31,8 +31,9 @@ type
TextAutoResize* = enum
## Should text element resize and how.
tsNone
tsWidthAndHeight
tsWidth
tsHeight
tsWidthAndHeight

TextStyle* = object
## Holder for text styles.
Expand Down Expand Up @@ -124,6 +125,8 @@ type
constraintsHorizontal*: Constraint
constraintsVertical*: Constraint
layoutAlign*: LayoutAlign
layoutWeight*: float32
wrapContent*: bool
layoutMode*: LayoutMode
counterAxisSizingMode*: CounterAxisSizingMode
horizontalPadding*: float32
Expand Down Expand Up @@ -206,6 +209,7 @@ var
mouse* = Mouse()
keyboard* = Keyboard()
requestedFrame*: bool
requestedTick*: bool
numNodes*: int
popupActive*: bool
inPopup*: bool
Expand Down Expand Up @@ -286,7 +290,7 @@ proc resetToDefault*(node: Node)=
# node.screenBox = rect(0,0,0,0)
node.textOffset = vec2(0, 0)
node.fill = color(0, 0, 0, 0)
node.transparency = 0
node.transparency = 1
node.strokeWeight = 0
node.stroke = color(0, 0, 0, 0)
node.zLevel = 0
Expand All @@ -313,6 +317,8 @@ proc resetToDefault*(node: Node)=
node.constraintsVertical = cMin
node.layoutAlign = laMin
node.layoutMode = lmNone
node.layoutWeight = 0.0
node.wrapContent = false
node.counterAxisSizingMode = csAuto
node.horizontalPadding = 0
node.verticalPadding = 0
Expand All @@ -329,6 +335,7 @@ proc setupRoot*() =
root.uid = newUId()
root.highlightColor = parseHtmlColor("#3297FD")
root.cursorColor = rgba(0, 0, 0, 255).color
root.transparency = 1
nodeStack = @[root]
current = root
root.diffIndex = 0
Expand Down Expand Up @@ -368,10 +375,6 @@ proc consume*(mouse: Mouse) =
buttonPress[MOUSE_LEFT] = false

proc computeLayout*(parent, node: Node) =
## Computes constraints and auto-layout.
for n in node.nodes:
computeLayout(node, n)

# Constraints code.
case node.constraintsVertical:
of cMin: discard
Expand Down Expand Up @@ -412,6 +415,9 @@ proc computeLayout*(parent, node: Node) =
of tsNone:
# Fixed sized text node.
discard
of tsWidth:
# Text will grow down.
node.box.w = node.textLayoutWidth
of tsHeight:
# Text will grow down.
node.box.h = node.textLayoutHeight
Expand All @@ -420,6 +426,13 @@ proc computeLayout*(parent, node: Node) =
node.box.w = node.textLayoutWidth
node.box.h = node.textLayoutHeight

## Computes constraints and auto-layout.
for n in node.nodes:
if node.layoutMode != lmNone and
(n.layoutWeight != 0 or n.layoutAlign == laStretch):
continue
computeLayout(node, n)

# Auto-layout code.
if node.layoutMode == lmVertical:
if node.counterAxisSizingMode == csAuto:
Expand All @@ -429,13 +442,33 @@ proc computeLayout*(parent, node: Node) =
if n.layoutAlign != laStretch:
maxW = max(maxW, n.box.w)
node.box.w = maxW + node.horizontalPadding * 2


var remainHeight = node.box.h - node.verticalPadding * 2 - node.itemSpacing * (node.nodes.len - 1).float32
var totalWeight: float32

for i, n in node.nodes.pairs:
# set width of stretch
if n.layoutAlign == laStretch:
n.box.w = node.box.w - node.horizontalPadding * 2
if n.id == "16": echo n.box.w
if n.layoutWeight == 0: computeLayout(node, n)
# record weight
if n.layoutWeight == 0: remainHeight -= n.box.h
else: totalWeight += n.layoutWeight

var at = 0.0
at += node.verticalPadding
for i, n in node.nodes.reversePairs:
if i > 0:
at += node.itemSpacing
for i, n in node.nodes:
if i > 0: at += node.itemSpacing

n.box.y = at

if n.layoutWeight != 0:
n.box.h =
if remainHeight <= 0: 0.0
else: remainHeight * n.layoutWeight / totalWeight
computeLayout(node, n)

case n.layoutAlign:
of laMin:
n.box.x = node.horizontalPadding
Expand All @@ -445,12 +478,10 @@ proc computeLayout*(parent, node: Node) =
n.box.x = node.box.w - n.box.w - node.horizontalPadding
of laStretch:
n.box.x = node.horizontalPadding
n.box.w = node.box.w - node.horizontalPadding * 2
# Redo the layout for child node.
computeLayout(node, n)

at += n.box.h
at += node.verticalPadding
node.box.h = at
if node.wrapContent: node.box.h = at

if node.layoutMode == lmHorizontal:
if node.counterAxisSizingMode == csAuto:
Expand All @@ -461,12 +492,32 @@ proc computeLayout*(parent, node: Node) =
maxH = max(maxH, n.box.h)
node.box.h = maxH + node.verticalPadding * 2

var remainWidth = node.box.w - node.horizontalPadding * 2 - node.itemSpacing * (node.nodes.len - 1).float32
var totalWeight: float32

for i, n in node.nodes.pairs:
# set width of stretch
if n.layoutAlign == laStretch:
n.box.h = node.box.h - node.verticalPadding * 2
if n.layoutWeight == 0: computeLayout(node, n)
# record weight
if n.layoutWeight == 0: remainWidth -= n.box.w
else: totalWeight += n.layoutWeight


var at = 0.0
at += node.horizontalPadding
for i, n in node.nodes.reversePairs:
if i > 0:
at += node.itemSpacing
for i, n in node.nodes:
if i > 0: at += node.itemSpacing

n.box.x = at

if n.layoutWeight != 0:
n.box.w =
if remainWidth <= 0: 0.0
else: remainWidth * n.layoutWeight / totalWeight
computeLayout(node, n)

case n.layoutAlign:
of laMin:
n.box.y = node.verticalPadding
Expand All @@ -476,12 +527,10 @@ proc computeLayout*(parent, node: Node) =
n.box.y = node.box.h - n.box.h - node.verticalPadding
of laStretch:
n.box.y = node.verticalPadding
n.box.h = node.box.h - node.verticalPadding * 2
# Redo the layout for child node.
computeLayout(node, n)

at += n.box.w
at += node.horizontalPadding
node.box.w = at
if node.wrapContent: node.box.w = at

proc computeScreenBox*(parent, node: Node) =
## Setups screenBoxes for the whole tree.
Expand Down
23 changes: 13 additions & 10 deletions src/fidget/opengl/base.nim
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ var
cursorGrab*: CursorHandle
cursorNSResize*: CursorHandle

proc getWindow*(): staticglfw.Window {.inline.} = window

proc setCursor*(cursor: CursorHandle) =
echo "set cursor"
window.setCursor(cursor)
Expand Down Expand Up @@ -130,18 +132,17 @@ proc updateLoop*(poll = true) =
of RepaintOnEvent:
if poll:
pollEvents()
if not requestedFrame or minimized:
# Only repaint when necessary
when not defined(emscripten):
sleep(16)
if minimized or not (requestedFrame or (tickMain != nil and requestedTick)):
return
requestedFrame = false
preInput()
if tickMain != nil:
if tickMain != nil and requestedTick:
requestedTick = false
preTick()
tickMain()
postTick()
drawAndSwap()
if requestedFrame:
requestedFrame = false
drawAndSwap()
postInput()

of RepaintOnFrame:
Expand Down Expand Up @@ -247,13 +248,13 @@ proc onSetKey(
textBox.delete(shift)
of LETTER_C: # copy
if ctrl:
base.window.setClipboardString(textBox.copy())
base.window.setClipboardString(textBox.copy().cstring)
of LETTER_V: # paste
if ctrl:
textBox.paste($base.window.getClipboardString())
of LETTER_X: # cut
if ctrl:
base.window.setClipboardString(textBox.cut())
base.window.setClipboardString(textBox.cut().cstring)
of LETTER_A: # select all
if ctrl:
textBox.selectAll()
Expand Down Expand Up @@ -302,7 +303,7 @@ proc onSetCharCallback(window: staticglfw.Window, character: cuint) {.cdecl.} =
keyboard.state = KeyState.Press
keyboard.keyString = Rune(character).toUTF8()

proc start*(openglVersion: (int, int), msaa: MSAA, mainLoopMode: MainLoopMode) =
proc start*(openglVersion: (int, int), msaa: MSAA, mainLoopMode: MainLoopMode, hints: openArray[array[0 .. 1, int]]) =
if init() == 0:
quit("Failed to intialize GLFW.")

Expand All @@ -317,6 +318,8 @@ proc start*(openglVersion: (int, int), msaa: MSAA, mainLoopMode: MainLoopMode) =
windowHint(CONTEXT_VERSION_MAJOR, openglVersion[0].cint)
windowHint(CONTEXT_VERSION_MINOR, openglVersion[1].cint)

for hint in hints: windowHint(hint[0].cint, hint[1].cint)

if fullscreen:
let
monitor = getPrimaryMonitor()
Expand Down
Loading