Trying the 7GUIs with LablGTK3/OCaml

I have tried to implement the 7GUIs (7GUIs) with LablGTK3/OCaml.

The first 6 are done (but would need some polishing). The last one won’t be possible (there are no real Table widget in Gtk… then the gtksheet example is rather big).

I have to admit that finding some functions/method was not always easy. For changing the background of a widget, multiple methods exist and only one works. Some methods are hidden in a #misc suffix (drawing#misc#queue_draw…), I had to hack some way to create a GMisc.drawing_area of a given dimension since this constructor doesn’t like ~width or ~height. But the library seems to be rather convenient and complete.

See Implementation of 7GUIs in OCaml with LablGtk3

18 Likes

Six of the seven challenges in 329 lines of OCaml code using GTK3. All run out-of-the-box on Mac. Fantastic stuff, thanks!

1 Like

Actually, there is a table widget in GTK; it is just strangely named: GtkTreeView (available as GTree in Lablgtk). Quoting the documentation, it is “a widget that displays multi-columned lists and trees”. In particular, if you never declare a row as the child of another row, the result will not be a tree, it will be a plain table. This widget is a bit cumbersome to use because it adheres to the Model-View-Controller design pattern, but that is true of most graphical toolkits, so nothing surprising here.

2 Likes

Yes, but it is a table like the file display on a finder/explorer. When clicking, what is selected is the entire row. Then I don’t think it will be handy. Perhaps I have missed something. in gTree.props there is an editable property, but I don’t know how to deal with it.

Ok, I finally manage to create the GUI part of the spreadsheet… There miss the formulae engine…

1 Like

There is an early stage Cells implementation (with menhir and ocamllex). It support 4 float arithmetic, circular reference detection, and the dependancy handling. (279 lines of code).

Very nice thank you!

I had a quick look at this lib a while back, but knowing nothing about gtk, the examples felt a little overwhelming so your repo will be really useful as a reference point!

A little side note about styling, I find the lines quite dense and thus hard to read.

Something like this would be much easier to visually parse IMO:

let _ = GMain.init ()

let w = GWindow.window
          ~title:"Counter" ()

let hbox = GPack.hbox
             ~border_width:10
             ~packing:w#add ()

let label = GMisc.label
              ~packing:(hbox#pack ~padding:80)
              ~text:"0" ()

let button = GButton.button
               ~label:("Count")
               ~packing:(hbox#pack ~padding:4) ()

let counter = ref 0

let on_click () =
  incr counter;
  label#set_text (Int.to_string !counter)

let () =
  ignore (
    button#connect#clicked
    ~callback:on_click
  );
  ignore (
    w#connect#destroy
      ~callback:GMain.quit
  );
  w#show ();
  GMain.main ()

I understand this is a subjective matter of course, and sometimes deemed a futile conversation :slight_smile:

Also, if I can nitpick one more thing, I’d say it’s useful to the reader to document via an ignored identifier why something was discarded. Something like this:

let (_locale:string) = GMain.init ()

Having no prior knowledge, one can just read and think internally:

“Oh yeah, in this context obviously we don’t care about the locale”

and then move on to the next line.

Rather than wonder why something was ignored and what it represented → so look at the doc.

I have to admit that, I have copied dumbly the let _ = GMain.init() and haven’t tried to figure out what is the meaning of the returned result.

Yes my style is quite dense. But the advantage is to have more easily the whole thing on screen for more complex programs. And the set of widget creation forms here a consistent block, then I havn’t separated them with spaces.

I havn’t thought of the _variable_name notation. It will be quite more handy than variable=… then let ()=ignore(variable). I guess I will use it.

You will see that the crud and the cells tasks use GTree which is quite complex. The model is adequate for a tree, then instead of a single row number, we have a path which contains the number of each child through the path of different parent. And there is also an iter which I don’t really understand very well the advantage over the path (excepted it is mandatory with some methods).

The Cells is quite peculiar. There is an « activated » method launched after the double-click. I use it to exchange the contents of the cell with its formulae. (Not easy, since we have an opaque column parameter…), the validation call the « edited » method of the column, then I have to associate each column a closure for this specific column.

I guess the Cells is nearly ready with one function (SUM) which support range and list of range, the 4 arithmetic operators + 2 unary operators.

The number of lines of code is:

   21 lexer.mll
   43 parser.mly
  181 expr.ml
   73 cells.ml
  318 total

The 7th is nearly as big as the 6 first together!

Since all the spreadsheet engine is in expr.ml, cells.ml deals only with the GUI (and the Parser calls since I can have a depancy circle Parser<->Expr).

2 Likes

Note, the site has migrated here : 7GUIs

I hope my pull request will be handled soon and makes my contribution referenced.

1 Like

Fair enough :slight_smile:

Sounds great :clap: