From 91ae186330aec414fcaf86e1567259fd1bb8ab40 Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Tue, 22 Jan 2013 17:47:51 +0100
Subject: [PATCH 1/2] Canvas API: draw (rounded) rect and rename Dialog to
 Window.

 - std.string:
   * Add method compare
   * Add method starts_with
 - canvas.Group:
   * Add method rect for drawing (rounded) rectangles
 - Rename canvas.Dialog to canvas.Window to free the name Dialog
   for real dialogs.
---
 Nasal/canvas/api.nas | 83 ++++++++++++++++++++++++++++++++++++++++++++
 Nasal/canvas/gui.nas | 25 +++++++------
 Nasal/std/string.nas | 47 +++++++++++++++++++++++--
 3 files changed, 141 insertions(+), 14 deletions(-)

diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index fc9a8366a..c3309f4a5 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -317,6 +317,89 @@ var Group = {
 
     return nodes;
   },
+  # Create a path child drawing a (rounded) rectangle
+  #
+  # @param x    Position of left border
+  # @param y    Position of top border
+  # @param w    Width
+  # @param h    Height
+  # @param cfg  Optional settings (eg. {"border-top-radius": 5})
+  rect: func(x, y, w, h, cfg = nil)
+  {
+    var opts = (cfg != nil) ? cfg : {};
+
+    # resolve border-[top-,bottom-][left-,right-]radius
+    var br = opts["border-radius"];
+    if( typeof(br) == 'scalar' )
+      br = [br, br];
+
+    var _parseRadius = func(id)
+    {
+      var r = opts["border-" ~ id ~ "-radius"];
+      var id = std.string.new(id);
+
+      if( r == nil )
+      {
+        # parse top, bottom, left, right separate if no value specified for
+        # single corner
+        foreach(var s; ["top", "bottom", "left", "right"])
+        {
+          if( id.starts_with(s ~ "-") )
+          {
+            r = opts["border-" ~ s ~ "-radius"];
+            break;
+          }
+        }
+      }
+
+      if( r == nil )
+        return br;
+      else if( typeof(r) == 'scalar' )
+        return [r, r];
+      else
+        return r;
+    };
+
+    var path = me.createChild("path");
+
+    # top-left
+    if( (var r = _parseRadius("top-left")) != nil )
+    {
+      path.moveTo(x, y + r[1])
+          .arcSmallCWTo(r[0], r[1], 0, x + r[0], y);
+    }
+    else
+      path.moveTo(x, y);
+
+    # top-right
+    if( (r = _parseRadius("top-right")) != nil )
+    {
+      path.horizTo(x + w - r[0])
+          .arcSmallCWTo(r[0], r[1], 0, x + w, y + r[1]);
+    }
+    else
+      path.horizTo(x + w);
+
+    # bottom-right
+    if( (r = _parseRadius("bottom-right")) != nil )
+    {
+      path.vertTo(y + h - r[1])
+          .arcSmallCWTo(r[0], r[1], 0, x + w - r[0], y + h);
+    }
+    else
+      path.vertTo(y + h);
+
+    # bottom-left
+    if( (r = _parseRadius("bottom-left")) != nil )
+    {
+      path.horizTo(x + r[0])
+          .arcSmallCWTo(r[0], r[1], 0, x, y + h - r[1]);
+    }
+    else
+      path.horizTo(x);
+
+    return path.close();
+  },
   # Get a vector of all child elements
   getChildren: func()
   {
diff --git a/Nasal/canvas/gui.nas b/Nasal/canvas/gui.nas
index 44c91dd16..8cf66dc0e 100644
--- a/Nasal/canvas/gui.nas
+++ b/Nasal/canvas/gui.nas
@@ -1,14 +1,14 @@
-var Dialog = {
+var Window = {
   # Constructor
   #
-  # @param size_dlg Dialog size ([width, height])
-  new: func(size_dlg, id = nil)
+  # @param size ([width, height])
+  new: func(size, id = nil)
   {
     var m = {
-      parents: [Dialog, PropertyElement.new(["/sim/gui/canvas", "window"], id)]
+      parents: [Window, PropertyElement.new(["/sim/gui/canvas", "window"], id)]
     };
-    m.setInt("size[0]", size_dlg[0]);
-    m.setInt("size[1]", size_dlg[1]);
+    m.setInt("size[0]", size[0]);
+    m.setInt("size[1]", size[1]);
 
     # arg = [child, listener_node, mode, is_child_event]
     setlistener(m._node, func m._propCallback(arg[0], arg[2]), 0, 2);
@@ -22,26 +22,29 @@ var Dialog = {
     if( me["_canvas"] != nil )
       me._canvas.del();
   },
-  # Create the canvas to be used for this dialog
+  # Create the canvas to be used for this Window
   #
   # @return The new canvas
   createCanvas: func()
   {
-    var size_dlg = [
+    var size = [
       me.get("size[0]"),
       me.get("size[1]")
     ];
 
     me._canvas = new({
-      size: [2 * size_dlg[0], 2 * size_dlg[1]],
-      view: size_dlg,
+      size: [2 * size[0], 2 * size[1]],
+      view: size,
       placement: {
         type: "window",
         index: me._node.getIndex()
       }
     });
+
+    me._canvas.addEventListener("mousedown", func me.raise());
+    return me._canvas;
   },
-  # Set an existing canvas to be used for this dialog
+  # Set an existing canvas to be used for this Window
   setCanvas: func(canvas_)
   {
     if( !isa(canvas_, canvas.Canvas) )
diff --git a/Nasal/std/string.nas b/Nasal/std/string.nas
index d45d83ae9..ba50bcc81 100644
--- a/Nasal/std/string.nas
+++ b/Nasal/std/string.nas
@@ -11,6 +11,43 @@ var string = {
   {
     return { parents: [string], _str: str };
   },
+  # compare(s)
+  # compare(pos, n, s)
+  #
+  # @param s    String to compare to
+  # @param pos  Position of first character used to compare
+  # @param n    Number of characters to compare
+  compare: func
+  {
+    var s = "";
+    var pos = 0;
+    var n = -1;
+
+    var num = size(arg);
+    if( num == 1 )
+      s = arg[0];
+    else if( num == 3 )
+    {
+      pos = arg[0];
+      n = arg[1];
+      s = arg[2];
+    }
+    else
+      die("std::string::compare: Invalid args");
+
+    if( n < 0 )
+      n = me.size();
+    else if( n > me.size() )
+      return 0;
+
+    if( n != size(s) )
+      return 0;
+
+    for(var i = pos; i < n; i += 1)
+      if( me._str[i] != s[i] )
+        return 0;
+    return 1;
+  },
   find_first_of: func(s, pos = 0)
   {
     return me._find(pos, size(me._str), s, 1);
@@ -27,6 +64,10 @@ var string = {
   {
     return substr(me._str, pos, len);
   },
+  starts_with: func(s)
+  {
+    return me.compare(0, size(s), s);
+  },
   size: func()
   {
     return size(me._str);
@@ -63,12 +104,12 @@ var stoul = func(str, base = 10)
       var digval = _string.toupper(c) - `A` + 10;
     else
       break;
-      
+
     if( digval >= base )
       break;
-    
+
     val = val * base + digval;
   }
-  
+
   return val;
 };

From 840595fa8d17bfe7d091c4a13833995c4ee4ae49 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Tue, 22 Jan 2013 21:35:33 +0000
Subject: [PATCH 2/2] Add support for the Fuel and payload dialog to display
 the maximum arrested landing weight.  Useful for carrier aircraft.

---
 Nasal/gui.nas | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Nasal/gui.nas b/Nasal/gui.nas
index 5f9ffc1e6..a66425223 100644
--- a/Nasal/gui.nas
+++ b/Nasal/gui.nas
@@ -901,6 +901,7 @@ var showWeightDialog = func {
         tablerow("Max. Ramp Weight", "maximum-ramp-mass-lbs", "%.0f lb" );
         tablerow("Max. Takeoff  Weight", "maximum-takeoff-mass-lbs", "%.0f lb" );
         tablerow("Max. Landing  Weight", "maximum-landing-mass-lbs", "%.0f lb" );
+        tablerow("Max. Arrested Landing  Weight", "maximum-arrested-landing-mass-lbs", "%.0f lb" );
         tablerow("Max. Zero Fuel Weight", "maximum-zero-fuel-mass-lbs", "%.0f lb" );
     }