Merge: app.nit on GNU/Linux: implement multiple windows support using a GtkStack
[nit.git] / lib / linux / ui.nit
index ed9fef5..23c1f91 100644 (file)
@@ -20,9 +20,41 @@ import gtk::v3_10
 
 import data_store
 
+# Request width of the GTK window for an app.nit application
+#
+# This is the minimum width of the window, it may grow bigger to fit content.
+fun gtk_window_width_request: Int do return 480
+
 redef class App
        redef fun setup do gtk_init
 
+       # Single GTK window of this application
+       var native_window: GtkWindow is lazy do
+               var win = new GtkWindow(new GtkWindowType.toplevel)
+               win.connect_destroy_signal_to_quit
+               win.titlebar = native_header_bar
+               win.add native_stack
+               return win
+       end
+
+       # GTK 3 header bar
+       var native_header_bar: GtkHeaderBar is lazy do
+               var bar = new GtkHeaderBar
+               bar.title = "app.nit" # TODO offer a portable API to name windows
+               bar.show_close_button = true
+
+               # TODO add back button
+
+               return bar
+       end
+
+       # Root `GtkStack` used to simulate the many app.nit windows
+       var native_stack: GtkStack is lazy do
+               var stack = new GtkStack
+               stack.homogeneous = false
+               return stack
+       end
+
        # On GNU/Linux, we go through all the callbacks once,
        # there is no complex life-cycle.
        redef fun run
@@ -32,8 +64,7 @@ redef class App
                app.on_start
                app.on_resume
 
-               var window = window
-               window.native.show_all
+               native_window.show_all
                gtk_main
 
                app.on_pause
@@ -44,6 +75,21 @@ redef class App
 
        # Spacing between GTK controls, default at 2
        var control_spacing = 2 is writable
+
+       redef fun window=(window)
+       do
+               var root_view = window.view
+               assert root_view != null
+               native_stack.add root_view.native
+               native_stack.visible_child = root_view.native
+
+               # FIXME These settings forces the GTK window to resize to its minimum
+               # size when changing app.nit windows. It is not pretty, but it could be
+               # improved with GTK 3.18 and interpolate_size.
+               native_window.resizable = false
+
+               super
+       end
 end
 
 redef class Control
@@ -64,21 +110,23 @@ redef class Control
 end
 
 redef class CompositeControl
-       redef type NATIVE: GtkContainer
-
-       redef fun add(item)
-       do
-               super
-               native.add item.native
-       end
 end
 
+# On GNU/Linux, a window is implemented by placing the `view` in a `GtkStack` in the single GTK window
 redef class Window
-       redef type NATIVE: GtkWindow
-       redef var native do
-               var win = new GtkWindow(new GtkWindowType.toplevel)
-               win.connect_destroy_signal_to_quit
-               return win
+
+       # Root view of this window
+       var view: nullable View = null
+
+       redef fun add(view)
+       do
+               if view isa View then
+                       self.view = view
+                       view.native.valign = new GtkAlign.start
+                       view.native.set_size_request(gtk_window_width_request, 0)
+               end
+
+               super
        end
 end
 
@@ -91,10 +139,17 @@ end
 
 redef class Layout
        redef type NATIVE: GtkBox
-       redef fun remove(view)
+
+       redef fun add(item)
+       do
+               super
+               if item isa View then native.add item.native
+       end
+
+       redef fun remove(item)
        do
                super
-               native.remove view.native
+               if item isa View then native.remove item.native
        end
 end
 
@@ -104,6 +159,7 @@ redef class HorizontalLayout
        redef fun add(item)
        do
                super
+               # FIXME abstract the use either homogeneous or weight to balance views size in a layout
                native.homogeneous = true
                native.set_child_packing(item.native, true, true, 0, new GtkPackType.start)
        end
@@ -116,17 +172,41 @@ redef class VerticalLayout
        do
                super
 
-               # FIXME abstract the use either homogeneous or weight to balance views size in a layout
-               native.homogeneous = true
                native.set_child_packing(item.native, true, true, 0, new GtkPackType.start)
        end
 end
 
+# On GNU/Linux, this is implemented by a `GtkListBox` inside a `GtkScrolledWindow`
 redef class ListLayout
-       redef type NATIVE: GtkListBox
-       redef var native = new GtkListBox
 
-       init do native.selection_mode = new GtkSelectionMode.none
+       redef type NATIVE: GtkScrolledWindow
+
+       redef var native = new GtkScrolledWindow
+
+       # Container inside `native`
+       var native_list_box = new GtkListBox
+
+       init do
+               native_list_box.selection_mode = new GtkSelectionMode.none
+               native.add native_list_box
+
+               # Set the size of the GtkScrolledWindow:
+               # use content width and set static height
+               native.set_policy(new GtkPolicyType.never, new GtkPolicyType.automatic)
+               native.set_size_request(gtk_window_width_request, 640)
+       end
+
+       redef fun add(item)
+       do
+               super
+               if item isa View then native_list_box.add item.native
+       end
+
+       redef fun remove(item)
+       do
+               super
+               if item isa View then native_list_box.remove item.native
+       end
 end
 
 redef class Button