khchen / wNim

Nim's Windows GUI Framework
MIT License
327 stars 17 forks source link

autoset frame(panel?) size according to its contents? #61

Closed retsyo closed 4 years ago

retsyo commented 4 years ago

In the following simplified example, a button and a label are placed side by side. The distances between button, label, and panel are 8. What I expect are:

  1. the window is resizable
  2. the texts on label and button are shown completely

I have tried 4 different layout codes which are commented out now in the following code, but none works. What is the right way? Thanks

import wNim

let app = App()

let frame = Frame()
let panel = Panel(frame)
let btn1 = Button(panel, label="a button with long label")
let lbl1 = StaticText(panel, label="a long string is here")

for i in [ btn1, lbl1 ]:
    i.font = Font(12, weight=wFontWeightBold)

proc layout() =
    panel.layout:

        #~ panel:
            #~ width = panel.getBestSize.width  # does not set the proper width
            #~ width = 8 + btn1.width + 8 + lbl1.width + 8 # does not set the proper width

        #~ frame:
            #~ width = frame.getBestSize.width  # does not set the proper width
            #~ width = 8 + btn1.width + 8 + lbl1.width + 8 # does not set the proper width

        btn1:
            left == panel.left + 8
            width == btn1.getBestSize.width + 20

        lbl1:
            top== btn1.top
            left = btn1.right + 8
            width >= lbl1.getBestSize.width

panel.wEvent_Size do (): layout()

proc main() =
    layout()
    frame.center()
    frame.show()
    app.mainLoop()

when isMainModule:
    main()
khchen commented 4 years ago

I don't understand what effect you want.

But you can use bestWidth instead of getBestSize.width Moreover, you should use relayout instead of layout for bestWidth.

If you want a demo that adjust the frame size according to the layout result, you can check examples/layout2.nim

retsyo commented 4 years ago

sorry, I can't understand examples/layout2.nim well.

In my following code, what I have expected are

  1. the distance of 1st and 4th rows is described with |-8-[TextCtrl]-8-[Button]-8-|
  2. the frame can be resized.
  3. all the TextCtrl can be resized along the width direction
  4. all the StaticText are not resizable

I have added let box = Resizable() to my code, but

  1. when I launch the application for the first time, we may find that a) some controls are cut out on the left; b) the distances between the 2 buttons and the panel.right are bigger than the set 8. I know if I change

    frame.dpiAutoScale:
    frame.minSize=(600, 300)

    to

    frame.dpiAutoScale:
    frame.minSize=(800, 300)

    can fix this problem, but will the call of layout() does so automatically launch

  2. then I enlarge the width of the frame to some stage, we can find that the distances between the 2 buttons and the panel.right get smaller, and become to 8, which is expected, at last. expected

  3. however, if I have enlarged the frame.width, I can't shrink it anymore. But In fact, the TextCtrl are expected to shrink-able expected2

import wNim

let app = App()
let frame = Frame()
frame.dpiAutoScale:
    frame.minSize=(600, 300)

let panel = Panel(frame)

let text1 = TextCtrl(panel, style=wTeReadOnly)
text1.font = Font(12, weight=wFontWeightBold)

let text2 = TextCtrl(panel, style=wTeReadOnly)
text2.font = Font(12, weight=wFontWeightBold)

let btnLoad1 = Button(panel, label="button 1")
btnLoad1.font = Font(12, weight=wFontWeightBold)

let btnLoad2 = Button(panel, label="button 2")
btnLoad2.font = Font(12, weight=wFontWeightBold)

let lbl1_1 = StaticText(panel, label="I'm label 1-1")
let text1_1 = TextCtrl(panel)
let lbl1_2 = StaticText(panel, label="I'm label 1-2")

let lbl1_3 = StaticText(panel, label="I'm label 1-3")
let text1_2 = TextCtrl(panel)
let lbl1_4 = StaticText(panel, label="I'm label 1-4")

let lbl2_0 = StaticText(panel, label="I'm label 2-0")
let lbl2_1 = StaticText(panel, label="I'm label 2-1")
let text2_1 = TextCtrl(panel)
let lbl2_2 = StaticText(panel, label="I'm label 2-2")

let lbl2_3 = StaticText(panel, label="I'm label 2-3")
let text2_2 = TextCtrl(panel)
let lbl2_4 = StaticText(panel, label="I'm label 2-4")

let notebook = NoteBook(panel)
notebook.addPage("page 1")
notebook.addPage("page 2")
notebook.addPage("page 3")

for i in [
    lbl1_1, text1_1, lbl1_2,
    lbl1_3, text1_2, lbl1_4,

    lbl2_0,
    lbl2_1, text2_1, lbl2_2,
    lbl2_3, text2_2, lbl2_4,

    notebook,
    ]:
    i.font = Font(12, weight=wFontWeightBold)

let box = Resizable()

proc layout() =

    panel.layout:

        text1:
            left == panel.left + 8
            top == panel.top + 8
            width == (panel.width - 8*3) - btnLoad1.width

        btnLoad1:
            top == text1.top
            left - 8 == text1.right
            width == max(btnLoad1.getBestSize.width, btnLoad2.getBestSize.width) + 20
            right + 8 == panel.right
            bottom == text1.bottom

        lbl1_1:
            left == lbl2_0.right
            top == btnLoad1.bottom + 10
            width == lbl1_1.getBestSize.width

        text1_1:
            left == lbl1_1.right + 8
            top == lbl1_1.top
            width == text2_1.width

        lbl1_2:
            left == text1_1.right + 8
            top == lbl1_1.top
            width == lbl1_2.getBestSize.width

        lbl1_3:
            left == lbl2_3.left
            top == lbl1_2.top
            width == lbl1_3.getBestSize.width

        text1_2:
            left == lbl1_3.right + 8
            top == lbl1_3.top
            width == text1_1.width

        lbl1_4:
            left == text1_2.right + 8
            top == text1_2.top
            width == lbl1_4.getBestSize.width

        lbl2_0:
            left == text1.left
            top == lbl1_1.bottom + 8
            width == lbl2_0.getBestSize.width

        lbl2_1:
            left == lbl2_0.right
            top == lbl2_0.top
            width == lbl2_1.getBestSize.width

        text2_1:
            left == lbl2_1.right + 8
            top == lbl2_1.top

        lbl2_2:
            left == text2_1.right + 8
            top == lbl2_1.top
            width == lbl2_2.getBestSize.width

        lbl2_3:
            left == lbl2_2.right + 10
            top == lbl2_2.top
            width == lbl2_3.getBestSize.width

        text2_2:
            left == lbl2_3.right + 8
            top == lbl2_3.top
            width == text2_1.width
            width >= 50

        lbl2_4:
            left == text2_2.right + 8
            top == text2_2.top
            right + 8 == panel.width
            width == lbl2_4.getBestSize.width

        text2:
            left == text1.left
            top == lbl2_4.bottom + 10
            width == text1.width

        btnLoad2:
            left == btnLoad1.left
            top == text2.top
            width == btnLoad1.width
            height == btnLoad1.height

        notebook:
            top == btnLoad2.bottom + 20
            left == panel.left + 8
            right == panel.right - 8

        box:
            top = 0
            left = 0
            width = text1.width + btnLoad1.width + 8*3
            bottom = notebook.bottom + 8

    let boxSize = box.layoutSize
    frame.minClientSize = boxSize
    #~ frame.size = boxSize
    #~ frame.maxClientSize = (wDefault, boxSize.height)

panel.wEvent_Size do (): layout()

proc main() =
    layout()
    frame.center()
    frame.show()
    app.mainLoop()

when isMainModule:
    main()
khchen commented 4 years ago

Is this what you want (in autolayout VFL):

import wNim

let app = App()
let frame = Frame()

frame.dpiAutoScale:
  frame.font = Font(9.0, weight=wFontWeightBold)

let panel = Panel(frame)
let text1 = TextCtrl(panel, style=wTeReadOnly)
let text2 = TextCtrl(panel, style=wTeReadOnly)
let btnLoad1 = Button(panel, label="button 1")
let btnLoad2 = Button(panel, label="button 2")
let lbl1_1 = StaticText(panel, label="I'm label 1-1")
let text1_1 = TextCtrl(panel)
let lbl1_2 = StaticText(panel, label="I'm label 1-2")
let lbl1_3 = StaticText(panel, label="I'm label 1-3")
let text1_2 = TextCtrl(panel)
let lbl1_4 = StaticText(panel, label="I'm label 1-4")
let lbl2_0 = StaticText(panel, label="I'm label 2-0")
let lbl2_1 = StaticText(panel, label="I'm label 2-1")
let text2_1 = TextCtrl(panel)
let lbl2_2 = StaticText(panel, label="I'm label 2-2")
let lbl2_3 = StaticText(panel, label="I'm label 2-3")
let text2_2 = TextCtrl(panel)
let lbl2_4 = StaticText(panel, label="I'm label 2-4")

let notebook = NoteBook(panel)
notebook.addPage("page 1")
notebook.addPage("page 2")
notebook.addPage("page 3")

let box = Resizable()

proc layout() =
  panel.autorelayout """
    spacing: 8
    H: |-[text1]-[btnLoad1(btnLoad1.bestWidth)]-|
    H: |->[lbl1_1]-[text1_1]-[lbl1_2]-[lbl1_3]-[text1_2]-[lbl1_4]-|
    H: |->[lbl2_0]-[lbl2_1]-[text2_1]-[lbl2_2]-[lbl2_3]-[text2_2]-[lbl2_4]-|
    H: |-[text2]-[btnLoad2(btnLoad2.bestWidth)]-|
    H: |-[notebook]-|

    V: |-[text1,btnLoad1(btnLoad1.bestHeight)]-
      [lbl1_1,lbl1_2,lbl1_3,lbl1_4,text1_1,text1_2]-
      [lbl2_0,lbl2_1,lbl2_2,lbl2_3,lbl2_4,text2_1,text2_2]-
      [text2,btnLoad2(btnLoad2.bestHeight)]-
      [notebook]-|

    C: box.width = lbl2_4.right - lbl2_0.left + 32
  """

  frame.minSize = (box.layoutSize.width, wDefault)

panel.wEvent_Size do (): layout()

proc main() =
  layout()
  frame.center()
  frame.show()
  app.mainLoop()

when isMainModule:
  main()
khchen commented 4 years ago

BTW, I am fixing the syntax and behavior of view stacks in VFL. So you can write following code in next release.

  panel.autorelayout """
    spacing: 8
    H: |-[row1:[text1]-[btnLoad1(btnLoad1.bestWidth)]]-|
    H: |->[row2:[lbl1_1]-[text1_1]-[lbl1_2]-[lbl1_3]-[text1_2]-[lbl1_4]]-|
    H: |->[row3:[lbl2_0]-[lbl2_1]-[text2_1]-[lbl2_2]-[lbl2_3]-[text2_2]-[lbl2_4]]-|
    H: |-[row4:[text2]-[btnLoad2(btnLoad2.bestWidth)]]-|
    H: |-[notebook]-|

    V: |-[row1(btnLoad1.bestHeight)]-[row2]-[row3]-[row4(btnLoad2.bestHeight)]-[notebook]-|

    C: box.width = lbl2_4.right - lbl2_0.left + 32
  """
retsyo commented 4 years ago

thank you for your help and everlasting improvements on wNim