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

Grid not showing up as expected #54

Open
seydar opened this issue Aug 9, 2023 · 10 comments
Open

Grid not showing up as expected #54

seydar opened this issue Aug 9, 2023 · 10 comments

Comments

@seydar
Copy link

seydar commented Aug 9, 2023

I am 100% sure that this is a PEBKAC case, but I'm not sure where else to turn:

require 'glimmer-dsl-libui'
include Glimmer

window("Test", 500, 500) {
  grid {

    area {
      left 1
      top 0

      rectangle(0, 0, 150, 500) {
        fill 0xff0000
      }
    }

    non_wrapping_multiline_entry {
      left 0
      top 0

      text "asdf"
    }
  }
}.show

Shows up as the attached image.

What's happening: the rectangle is all the way to the left
What should happen: the rectangle should begin within its spot in the grid.

Obviously, I recognize that this is just my unfamiliarity with library, but I'm hoping for some guidance on where to turn to.

Screen Shot 2023-08-09 at 6 32 42 PM
@seydar seydar changed the title Unable to show grid within class Grid not showing up as expect Aug 9, 2023
@seydar seydar changed the title Grid not showing up as expect Grid not showing up as expected Aug 9, 2023
@seydar
Copy link
Author

seydar commented Aug 9, 2023

I guess I have a couple usage questions:

  • how do I specify the width of an arbitrary element (in this case non_wrapping_multiline_entry?
  • how do I get it to show up after the rectangle? or even below the rectangle? changing the order to be top 0, left 0 for the area and top 1, left 0 for the multiline_entry just gets me the same as the image above.

@seydar
Copy link
Author

seydar commented Aug 11, 2023

Here's another example; it should be a green rectangle above a red rectangle, but the red rectangle doesn't appear.

require 'glimmer-dsl-libui'

class Test
  include Glimmer

  def launch
    window("Test", 500, 500) {
      margined true

      grid {

        area {
          left 0; xspan 1
          top  0; yspan 1
          rectangle(0, 0, 500, 200) {
            fill 0x00ff00
          }
        }

        area {
          left 0; xspan 1
          top  1; yspan 1

          rectangle(0, 0, 500, 200) {
            fill 0x0000ff
          }
        }

      }

    }.show
  end
end

Test.new.launch
Screen Shot 2023-08-11 at 3 35 58 PM

@AndyObtiva
Copy link
Owner

AndyObtiva commented Aug 12, 2023

Thank you for submitting this issue.

The last scenario you shared is definitely not supported. It is mentioned in the Glimmer DSL for LibUI API gotchas:
https://github.com/AndyObtiva/glimmer-dsl-libui#api-gotchas

It seems that the C libui library does not support nesting multiple area controls under a grid as only the first one shows up in that scenario. To workaround that limitation, use a vertical_box with nested horizontal_boxs instead to include multiple areas in a GUI.

From doing some testing, it seems non_wrapping_multiline_entry does not play well with grid either, but entry and label do.

I personally learned to avoid using grid and just use a combination of horizontal_box and vertical_box, sometimes including empty label controls if I needed to add blank space.

Given that the underlying C libui library is still alpha, it seems like the grid layout is not ready for prime time yet, especially when including area or non_wrapping_multiline_entry in it.

On the other hand, Glimmer DSL for SWT's grid layout is 100% feature complete and solid, including the ability to specify the size of each grid in pixels using layout data. You could try it instead if you're willing to build apps with JRuby.

grid layout

For example, I built this app using the SWT grid layout, taking advantage of every advanced feature in it:

Math Bowling 2:
https://github.com/AndyObtiva/MathBowling
math bowling

But, going back to Glimmer DSL for LibUI, like I mentioned, I would recommend just using a combination of horizontal_box and vertical_box.

If you could provide me with a quick mockup or description of the graphical user interface you are trying to build, maybe I could advise you on how to build it using Glimmer DSL for LibUI.

If you haven't checked the project examples already, I highly recommend checking out the project examples as that's the fastest way to learn it.:

Tetris is a good example of using area and non-area controls: https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#tetris

Tetris

@seydar
Copy link
Author

seydar commented Aug 16, 2023

Fantastic! Thank you very much for the response.

From doing some testing, it seems non_wrapping_multiline_entry does not play well with grid either, but entry and label do.

I personally learned to avoid using grid and just use a combination of horizontal_box and vertical_box, sometimes including empty label controls if I needed to add blank space.

Given that the underlying C libui library is still alpha, it seems like the grid layout is not ready for prime time yet, especially when including area or non_wrapping_multiline_entry in it.

This is what I was looking to hear — glad I'm not crazy.

Unfortunately, I'm building a GUI for a tool I wrote that leans on the NArray C library in a non-trivial way, so I can't use JRuby/SWT. I've been wrestling with grid and have gotten it to finally work, although it wasn't easy. Here's what I have so far:

Screen Shot 2023-08-13 at 3 22 11 PM

I would like to use a combination of horizontal_box and vertical_box, but I don't know how to give them uneven space (like the table on the left and the large graph of vertexes and edges) — my attempts for the above image end up splitting the screen in half. However, you manage to do it in tetris.rb, so I'm going to play around some more and see what I can make happen.

Thanks again!

@AndyObtiva
Copy link
Owner

AndyObtiva commented Aug 18, 2023

Wow! This GUI you built looks amazing! You're some sort of a genius to have figurd this out. Could I include that screenshot in Glimmer DSL for LibUI's Applications? Also, is it an open-source software project by any chance? Would you mind at least sharing how you got the grid working (view code or part of it only)?

By the way, with horizontal_box and vertical_box, in order to ensure not all controls have the same size, you set the property stretchy false for ones that shouldn't stretch to take up all available remaining space. However, I just tested it with area, and unfortunately, the stretchy option applied to table (to prevent it from stretching) does not work correctly when an area is inside the same horizontal_box along with it. I reported the issue (and other issues) to the upstream libui-ng C library project: libui-ng/libui-ng#216

@seydar
Copy link
Author

seydar commented Aug 18, 2023

I'm so glad you like it, thank you so much! Please feel free to include the screenshot wherever you want!

I would like it to be open source, but I'm trying to use this software to maybe start a company, so I can't quite release it yet until I figure out how to somehow find work with the underlying software.

That said, I'm working on rewriting the GUI to use MVP, so I can definitely make the GUI open source. I'll have it up shortly and let you know.

@AndyObtiva
Copy link
Owner

It doesn't have to be open-source at all. I only asked just in case so I'd learn more about the project. But, I respect closed-source software too, especially when it's for a business. I work for a company with closed source software, so I totally understand. You don't have to open-source it.

Thank you for allowing me to share the screenshot. I added it under Glimmer DSL for LibUI Applications:
https://github.com/AndyObtiva/glimmer-dsl-libui/tree/master#electric-avenue

@seydar
Copy link
Author

seydar commented Aug 20, 2023

Here's the GUI code for it (I just tried to rewrite it to be more like MVP with observers, but it's tough — I'm not used to this style, or GUI programming in general).

https://github.com/seydar/electric_gui

I'm open to any feedback you have on how I should structure things.

@AndyObtiva
Copy link
Owner

AndyObtiva commented Aug 21, 2023

OK, thank you for sharing. I will take a look when I get a chance.

@AndyObtiva
Copy link
Owner

AndyObtiva commented Aug 30, 2023

I took a look.

Your app.rb generally looks good. I like how you abstracted components out into methods.

In Glimmer DSL for LibUI terminology, this technique is called Method-Based Custom Keywords. Or, more casually, method-based custom controls (components).

Also, I liked your usage of data-binding and how it pulled data cleanly from pure presenters (overall.rb and congestion.rb). It was very well done.

I noticed that you declared histogram.rb (and plotter.rb) as a Presenter. However, it is used as a View given that it is rendering GUI. Usually, Presenters present information that is summarized from Models as pure data, and then that pure data is rendered as GUI in Views outside of Presenters (a layer above). And, Presenters generally don't mix in Glimmer. They're a layer below Glimmer (which is only mixed into Views in general).

You could have avoided that by extracting this bit of code from app.rb into histogram.rb, and putting histogram.rb under a views directory.

    @hist = area {
      left x; xspan xs
      top  y; yspan ys
      vexpand true

      on_draw do |area|
        rectangle(0, 0, area[:area_width], area[:area_height]) {
          fill 0xFFFFFF
        }

        @histogram.plot area
      end
    }

The same could have been done for plotter.rb:

    @plot = area {
      left x; xspan xs
      top  y; yspan ys

      on_draw {|area|
        @plotter.scale_area area, PLOT
        self.desc = grid_description

        # Background
        rectangle(0, 0, area[:area_width], area[:area_height]) {
          fill 0xffffff
        }

        # Graph
        @plotter.plot_flows

        # Info
        @plotter.plot_info_box
      }

      on_mouse_up do |area_event|
        @plotter.select_info_box(area_event[:x], area_event[:y])
        @plot.queue_redraw_all
      end
    }

To do that, you could use the other Glimmer DSL for LibUI custom control technique, which is called Class-Based Custom Keywords, or class-based custom controls. Glimmer will automatically convert such classes into underscored keywords. So, if you declare a Histogram custom control, you can later use it with histogram in a View that mixes Glimmer. A Plotter class becomes plotter in Glimmer View code.

This code is a small example of how to build a class-based custom control (it generates the address_view keyword):

class AddressView
  include Glimmer::LibUI::CustomControl
  
  options :address
  
  body {
    vertical_box {
      address.each_pair do |attribute, value|
        label_pair(model: address, attribute: attribute, value: value)
      end
    }
  }
end

This can later be used from another View like this:

  window {
    horizontal_box {
      address_view(address: shipping_address)
      address_view(address: billing_address)
    }
  }

To learn more how to build class-based custom controls, I highly recommend checking out the examples/class_based_custom_controls.rb example:
https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#class-based-custom-controls

Another bit of feedback is app.rb could have taken advantage of the new Glimmer DSL for LibUI module for building applications Glimmer::LibUI::Application (aka Glimmer::LibUI::CustomWindow):
https://github.com/AndyObtiva/glimmer-dsl-libui#usage

It expects declaring the GUI code cleanly inside body, and it takes care of the rest whe you call ClassName.launch (it also supports before_body and after_body hooks in case there is a need to execute code before or after initialization of the body, so any code in initialize goes into before_body if you refactor).

require 'glimmer-dsl-libui'

class SomeGlimmerApp
  include Glimmer::LibUI::Application
  
  body {
    window('hello world', 300, 200) {
      button('Button') {
        on_clicked do
          puts 'Button Clicked'
        end
      }
    }
  }
end

SomeGlimmerApp.launch

In summary:

  • Your declaration of View components via methods in app.rb is great! That technique is called method-based custom controls.
  • Your usage of data-binding with clean presenters overall.rb and congestion.rb is great.
  • app.rb could optionally use include Glimmer::LibUI::Application instead of include Glimmer to automate some of the boilerplate work. Any code that was in initialize would move to before_body if you make this refactoring.
  • histogram.rb (and other similar presenters that mix in Glimmer to build View GUI like plotter.rb) should become a class-based custom control and live in a views directory.
  • If there is logic that is needed to be done to produce data for View components, it should be separated into clean presenters that do NOT mix in Glimmer. This is OPTIONAL and is not always necessary. Sometimes, the logic is simple enough to just live inside the View (custom control) classes.
  • You can add a models directory to store Model classes that you rely on in the Presenters as a lower layer that provides the base data before it is summarized in a form that could be rendered in a View. This is not needed if your Model layer is actually living outside the application in some library (like in electric_avenue.rb)

I hope that I provided enough feedback. If you have any further questions, feel free to ask.

Cheers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants