Преглед на файлове

добавил индикатор параметра, пока только линейный

kpmy преди 10 години
родител
ревизия
2d698aae20

+ 52 - 86
design/indicator.svg

@@ -33,9 +33,9 @@
      borderopacity="1.0"
      inkscape:pageopacity="1"
      inkscape:pageshadow="2"
-     inkscape:zoom="2.0000001"
-     inkscape:cx="231.34845"
-     inkscape:cy="-30.03596"
+     inkscape:zoom="1.0000001"
+     inkscape:cx="186.68632"
+     inkscape:cy="5.3199791"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
@@ -487,151 +487,117 @@
     <text
        xml:space="preserve"
        style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="177.89566"
-       y="1174.9121"
+       x="180.89566"
+       y="1172.9121"
        id="text4186-4"
        sodipodi:linespacing="125%"
        inkscape:export-xdpi="90"
        inkscape:export-ydpi="90"><tspan
          sodipodi:role="line"
-         id="tspan4188-7"
-         x="177.89566"
-         y="1174.9121"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Free Pixel';-inkscape-font-specification:'Free Pixel';letter-spacing:-1px">hunger</tspan></text>
+         x="180.89566"
+         y="1172.9121"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Free Pixel';-inkscape-font-specification:'Free Pixel';letter-spacing:-1px"
+         id="tspan4223">param</tspan></text>
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 340.79102,1069.1621 -48.70118,27.916 47.97071,28.0313 0.73047,-55.9473 z"
+       d="m 330.54102,1078.1621 -48.70118,27.916 47.97071,28.0313 0.73047,-55.9473 z"
        id="path4394"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 342.8418,1070.2871 -0.71094,54.5762 47.44922,-27.3965 -46.73828,-27.1797 z"
+       d="m 332.5918,1079.2871 -0.71094,54.5762 47.44922,-27.3965 -46.73828,-27.1797 z"
        id="path4392"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 290.84375,1098.7422 -0.17383,55.832 48.14844,-27.7988 -47.97461,-28.0332 z"
+       d="m 280.59375,1107.7422 -0.17383,55.832 48.14844,-27.7988 -47.97461,-28.0332 z"
        id="path4390"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 390.66406,1099.2266 -47.73242,27.5586 47.5625,27.7929 0.16992,-55.3515 z"
+       d="m 380.41406,1108.2266 -47.73242,27.5586 47.5625,27.7929 0.16992,-55.3515 z"
        id="path4388"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#ced6b5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 340.50335,1172.8794 -39.85741,-23.1763 0.14263,-46.1057 39.9998,-22.9297 39.85757,23.1767 -0.14255,46.1057 z"
+       d="m 330.25335,1181.8794 -39.85741,-23.1763 0.14263,-46.1057 39.9998,-22.9297 39.85757,23.1767 -0.14255,46.1057 z"
        id="path4158-4-0"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 340.59961,1083.668 -35.89258,20.7832 35.35352,20.6582 0.54101,-41.4395 -0.002,-0 z"
+       d="m 330.34961,1092.668 -35.89258,20.7832 35.35352,20.6582 0.54101,-41.4395 -0.002,0 z"
        id="path4408"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 342.65234,1084.8496 -0.52148,40.0137 34.96289,-20.1856 -34.44141,-19.8281 z"
+       d="m 332.40234,1093.8496 -0.52148,40.0137 34.96289,-20.1856 -34.44141,-19.8281 z"
        id="path4406"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 303.30078,1106.0215 0.0527,41.2305 35.46484,-20.4766 -35.51758,-20.7539 z"
+       d="m 293.05078,1115.0215 0.0527,41.2305 35.46484,-20.4766 -35.51758,-20.7539 z"
        id="path4404"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 377.95508,1106.5645 -35.02344,20.2207 35.07422,20.496 -0.0508,-40.7167 z"
+       d="m 367.70508,1115.5645 -35.02344,20.2207 35.07422,20.496 -0.0508,-40.7167 z"
        id="path4402"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 340.01562,1128.4688 304.45508,1149 l 35.0293,20.1641 0.53124,-40.6953 z"
+       d="m 331.51562,1242.9688 -35.56054,20.5312 35.0293,20.1641 0.53124,-40.6953 z"
        id="path4400"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <path
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 342.08008,1128.6816 -0.53125,40.7012 35.25195,-20.4121 -34.7207,-20.2891 z"
+       d="m 352.08008,1227.1816 -0.53125,40.7012 35.25195,-20.4121 -34.7207,-20.2891 z"
        id="path4175-9"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90" />
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Free Pixel';-inkscape-font-specification:'Free Pixel';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="-345.7438"
-       y="1179.2764"
-       id="text4379"
-       sodipodi:linespacing="125%"
-       transform="matrix(0.83578615,-0.54905511,0.54905511,0.83578615,0,0)"
-       inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90"><tspan
-         sodipodi:role="line"
-         id="tspan4381"
-         x="-345.7438"
-         y="1179.2764"
-         style="font-size:15px;letter-spacing:-1px">fat</tspan></text>
+       inkscape:export-ydpi="90"
+       inkscape:connector-curvature="0" />
     <text
        xml:space="preserve"
        style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="863.04865"
-       y="834.72418"
+       x="319.46799"
+       y="1166.7213"
        id="text4410"
        sodipodi:linespacing="125%"
-       transform="matrix(0.85435775,0.51968533,-0.51968533,0.85435775,0,0)"
+       transform="matrix(0.99994418,0.0105655,-0.0105655,0.99994418,0,0)"
        inkscape:export-xdpi="90"
-       inkscape:export-ydpi="90"><tspan
+       inkscape:export-ydpi="90"
+       inkscape:transform-center-x="2.9999999"
+       inkscape:transform-center-y="11"><tspan
          sodipodi:role="line"
          id="tspan4412"
-         x="863.04865"
-         y="834.72418"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Free Pixel';-inkscape-font-specification:'Free Pixel';letter-spacing:-1px">slim</tspan></text>
+         x="319.46799"
+         y="1166.7213"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:'Free Pixel';-inkscape-font-specification:'Free Pixel';letter-spacing:-1px">fitness</tspan></text>
     <path
        inkscape:connector-curvature="0"
        style="fill:#bac1a3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="m 197.25292,1129.0739 -20.39934,35.1335 40.71818,-0.1648 -20.31884,-34.9687 z"
+       d="m 246.00292,1243.3239 -20.39934,35.1335 40.71818,-0.1648 -20.31884,-34.9687 z"
        id="path4194-8"
        inkscape:export-xdpi="90"
        inkscape:export-ydpi="90" />
-    <path
-       sodipodi:type="star"
-       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#bac1a3;stroke-width:0.37519264;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       id="path4429"
-       sodipodi:sides="6"
-       sodipodi:cx="340.5"
-       sodipodi:cy="1125.8622"
-       sodipodi:r1="56.685535"
-       sodipodi:r2="49.091114"
-       sodipodi:arg1="0.52680461"
-       sodipodi:arg2="1.0504034"
-       inkscape:flatsided="true"
-       inkscape:rounded="0"
-       inkscape:randomized="0"
-       d="m 389.5,1154.3622 -49.18172,28.1852 -49,-28.5 0.18172,-56.6852 49.18172,-28.1853 49,28.5 z"
-       transform="matrix(1.0661,0,0,1.0661381,-22.257057,-73.212294)" />
-    <path
-       sodipodi:type="star"
-       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#bac1a3;stroke-width:0.37765563;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       id="path4429-4"
-       sodipodi:sides="6"
-       sodipodi:cx="340.5"
-       sodipodi:cy="1125.8622"
-       sodipodi:r1="56.685535"
-       sodipodi:r2="49.091114"
-       sodipodi:arg1="0.52680461"
-       sodipodi:arg2="1.0504034"
-       inkscape:flatsided="true"
-       inkscape:rounded="0"
-       inkscape:randomized="0"
-       d="m 389.5,1154.3622 -49.18172,28.1852 -49,-28.5 0.18172,-56.6852 49.18172,-28.1853 49,28.5 z"
-       transform="matrix(0,1.0610154,-1.0573199,0,1387.3965,765.33644)" />
   </g>
 </svg>

BIN
design/progress.xcf


+ 5 - 5
lib/app/demo_updater.dart

@@ -1,21 +1,21 @@
 part of loop;
 
-const daySec = 24*60*60;
+const daySec = 24 * 60 * 60;
 
 const launchCount = 2; //два раза в сутки надо кормить, то есть, полностью оголодает за 12 часов
 const deltaHunger = 1 / (daySec ~/ launchCount);
 
-void update(Model m){
+void update(Model m) {
   Duration delta = new DateTime.now().difference(m.lastUpdate);
   double hunger = delta.inSeconds * deltaHunger;
-  m.hunger(hunger);
+  m.hunger(hunger * 100);
 
   m.lastUpdate = new DateTime.now();
 }
 
 typedef Model UpdateFunction(Model m);
 
-class ModelUpdateRequest{
+class ModelUpdateRequest {
   UpdateFunction upd;
   ModelUpdateRequest(this.upd);
-}
+}

+ 21 - 23
lib/app/loop.dart

@@ -10,56 +10,54 @@ import 'package:uuid/uuid.dart';
 part 'model.dart';
 part 'demo_updater.dart';
 
-class ModelComponentInit{
+class ModelComponentInit {
   Model _m;
   Model get model => _m;
   ModelComponentInit(this._m);
 }
 
-class ModelComponentRegister{}
+class ModelComponentRegister {}
 
-class AppStart{}
+class AppStart {}
 
-Model load(){
-    var name = window.sessionStorage[SESSION];
-    assert(name != null);
-    var obj = window.sessionStorage[name];
-    print(obj);
-    if (obj != null)
-      return codec.decode(obj, new Model());
-    else{
-      Model m = new Model.born(name);
-      save(m);
-      return m;
-    }
+Model load() {
+  var name = window.sessionStorage[SESSION];
+  assert(name != null);
+  var obj = window.sessionStorage[name];
+  print(obj);
+  if (obj != null) return codec.decode(obj, new Model()); else {
+    Model m = new Model.born(name);
+    save(m);
+    return m;
+  }
 }
 
-Model process(Model m){
+Model process(Model m) {
   update(m);
   return m;
 }
 
-Model notify(Model m){
+Model notify(Model m) {
   bus.fire(new ModelUpdated(m));
   return m;
 }
 
-void save(Model m){
+void save(Model m) {
   var name = window.sessionStorage[SESSION];
   assert(name != null);
   window.sessionStorage[name] = codec.encode(m);
 }
 
-run(){
+run() {
   save(notify(process(load())));
   return true;
 }
 
-void handle(event){
-  if(event is ModelComponentRegister){
+void handle(event) {
+  if (event is ModelComponentRegister) {
     bus.fire(new ModelComponentInit(load()));
-  }else if(event is ModelUpdateRequest){
+  } else if (event is ModelUpdateRequest) {
     assert(event.upd != null);
     save(notify(event.upd(load())));
   }
-}
+}

+ 8 - 8
lib/app/model.dart

@@ -1,30 +1,30 @@
 part of loop;
 
-class ModelUpdated{
+class ModelUpdated {
   Model _m;
   Model get model => _m;
   ModelUpdated(this._m);
 }
 
 @Entity()
-class Model{
+class Model {
   String uuid;
   String name;
   DateTime lastUpdate;
   DateTime birthday;
   num fullness;
 
-  int get hashCode{
+  int get hashCode {
     return uuid.hashCode;
   }
 
   Duration get age => new DateTime.now().difference(birthday);
 
-  void feed(double x){
-    fullness = max(0.0, min(fullness+x, 1.0));
+  void feed(double x) {
+    fullness = max(0.0, min(fullness + x, 1.0));
   }
 
-  void hunger(double x){
+  void hunger(double x) {
     feed(-x);
   }
 
@@ -32,10 +32,10 @@ class Model{
   //for serialization purpose
   Model();
 
-  Model.born(this.name){
+  Model.born(this.name) {
     this.uuid = new Uuid().v5("in:ocsf:dart", "chi");
     this.birthday = new DateTime.now();
     this.lastUpdate = new DateTime.now();
     this.fullness = 1.0;
   }
-}
+}

+ 72 - 75
lib/poly/chi_canvas.dart

@@ -29,15 +29,15 @@ class Point {
 
   Point(this.x, this.y);
   String toString() => '{x: $x, y: $y, col: "$col"}';
-  Map<String, Object> toMap(){
+  Map<String, Object> toMap() {
     Map<String, Object> ret = new Map();
-    ret["x"]=x;
-    ret["y"]=y;
-    ret["col"]=col.toString();
+    ret["x"] = x;
+    ret["y"] = y;
+    ret["col"] = col.toString();
     return ret;
   }
 
-  Point.fromMap(Map<String, Object> m){
+  Point.fromMap(Map<String, Object> m) {
     this.x = m["x"];
     this.y = m["y"];
     this.col = new Color.hex(m["col"]);
@@ -50,41 +50,41 @@ class Image {
 
   Map<Tuple2<int, int>, Point> data = new Map();
 
-  Image.import(String js){
+  Image.import(String js) {
     Map<String, Object> r;
     r = JSON.decode(js);
     String name = r["name"];
-    if(name == null || name == ""){
+    if (name == null || name == "") {
       name = "noname";
     }
     data.clear();
     List<Map<String, Object>> pl = r["data"];
-    if(pl!=null){
+    if (pl != null) {
       //normalize
       Point min = new Point(0xFFFFFFFF, 0xFFFFFFFF);
       Point max = new Point(0, 0);
 
-      pl.forEach((Map<String, Object> m){
+      pl.forEach((Map<String, Object> m) {
         Point p = new Point.fromMap(m);
-        if(p.x <= min.x) min.x = p.x;
-        if(p.y <= min.y) min.y = p.y;
-        if(p.x >= max.x) max.x = p.x;
-        if(p.y >= max.y) max.y = p.y;
+        if (p.x <= min.x) min.x = p.x;
+        if (p.y <= min.y) min.y = p.y;
+        if (p.x >= max.x) max.x = p.x;
+        if (p.y >= max.y) max.y = p.y;
       });
 
-      if(min.x==0xFFFFFFFF){
+      if (min.x == 0xFFFFFFFF) {
         min = null;
-      }else{
+      } else {
         width = max.x - min.x + 1;
         height = max.y - min.y + 1;
       }
-      pl.forEach((Map<String, Object>m){
+      pl.forEach((Map<String, Object> m) {
         Point p = new Point.fromMap(m);
-        if(min != null){
+        if (min != null) {
           p.x = p.x - min.x;
           p.y = p.y - min.y;
         }
-        data[new Tuple2(p.x, p.y)]=p;
+        data[new Tuple2(p.x, p.y)] = p;
       });
 
     }
@@ -92,7 +92,7 @@ class Image {
 }
 
 @CustomTag("chi-canvas")
-class ChiCanvas extends PolymerElement implements ChiEventListener{
+class ChiCanvas extends PolymerElement implements ChiEventListener {
   @published int base = DEFAULT_INNER_SIDE;
   @published bool transparent = true;
   @published String href = "";
@@ -100,8 +100,8 @@ class ChiCanvas extends PolymerElement implements ChiEventListener{
   @published int left = 0;
 
   int get INNER_SIDE => base;
-  int get OUTER_SIDE => INNER_SIDE+2*INNER_MARGIN+2*OUTER_STROKE;
-  int get DOT => OUTER_SIDE+2*OUTER_MARGIN;
+  int get OUTER_SIDE => INNER_SIDE + 2 * INNER_MARGIN + 2 * OUTER_STROKE;
+  int get DOT => OUTER_SIDE + 2 * OUTER_MARGIN;
   int get TOP => top;
   int get LEFT => left;
 
@@ -116,7 +116,7 @@ class ChiCanvas extends PolymerElement implements ChiEventListener{
   int get nx => width ~/ DOT;
   int get ny => height ~/ DOT;
 
-  void back(){
+  void back() {
     RgbColor color;
 
     color = BG_COLOR.toRgbColor();
@@ -130,14 +130,14 @@ class ChiCanvas extends PolymerElement implements ChiEventListener{
 
     int w = 0;
     int h = 0;
-    int y = 2*OUTER_MARGIN;
-    while(y<height){
-      int x = 2*OUTER_MARGIN;
+    int y = 2 * OUTER_MARGIN;
+    while (y < height) {
+      int x = 2 * OUTER_MARGIN;
       w = 0;
-      while(x<width){
+      while (x < width) {
         _ctx.strokeRect(x, y, OUTER_SIDE, OUTER_SIDE);
-        _ctx.fillRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE+INNER_MARGIN, INNER_SIDE, INNER_SIDE);
-        _ctx.strokeRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
+        _ctx.fillRect(x + OUTER_STROKE + INNER_MARGIN, y + OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
+        _ctx.strokeRect(x + OUTER_STROKE + INNER_MARGIN, y + OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
         w++;
         x = x + DOT;
       }
@@ -146,37 +146,37 @@ class ChiCanvas extends PolymerElement implements ChiEventListener{
     }
   }
 
-  void front(){
-     int w = 0;
-     int h = 0;
-     _ctx.setStrokeColorRgb(0xFF, 0, 0);
-     _ctx.strokeRect(2*OUTER_MARGIN + LEFT*DOT, 2*OUTER_MARGIN + TOP*DOT, img.width*DOT-2, img.height*DOT-2);
-     int y = 2*OUTER_MARGIN + TOP*DOT;
-     while(y<height && h<img.height){
-       int x = 2*OUTER_MARGIN + LEFT*DOT;
-       w = 0;
-       while(x<width && w<img.width){
-         var p = new Tuple2<int, int>(w, h);
-         Point tp = img.data[p];
-         if (tp!=null){
-           var color = tp.col.toRgbColor();
-           _ctx.setFillColorRgb(color.r, color.g, color.b);
-           _ctx.setStrokeColorRgb(color.r, color.g, color.b);
-           _ctx.strokeRect(x, y, OUTER_SIDE, OUTER_SIDE);
-           _ctx.fillRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE+INNER_MARGIN, INNER_SIDE, INNER_SIDE);
-           _ctx.strokeRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
-         }
-         w++;
-         x = x + DOT;
-       }
-       h++;
-       y = y + DOT;
-     }
+  void front() {
+    int w = 0;
+    int h = 0;
+    _ctx.setStrokeColorRgb(0xFF, 0, 0);
+    _ctx.strokeRect(2 * OUTER_MARGIN + LEFT * DOT, 2 * OUTER_MARGIN + TOP * DOT, img.width * DOT - 2, img.height * DOT - 2);
+    int y = 2 * OUTER_MARGIN + TOP * DOT;
+    while (y < height && h < img.height) {
+      int x = 2 * OUTER_MARGIN + LEFT * DOT;
+      w = 0;
+      while (x < width && w < img.width) {
+        var p = new Tuple2<int, int>(w, h);
+        Point tp = img.data[p];
+        if (tp != null) {
+          var color = tp.col.toRgbColor();
+          _ctx.setFillColorRgb(color.r, color.g, color.b);
+          _ctx.setStrokeColorRgb(color.r, color.g, color.b);
+          _ctx.strokeRect(x, y, OUTER_SIDE, OUTER_SIDE);
+          _ctx.fillRect(x + OUTER_STROKE + INNER_MARGIN, y + OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
+          _ctx.strokeRect(x + OUTER_STROKE + INNER_MARGIN, y + OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
+        }
+        w++;
+        x = x + DOT;
+      }
+      h++;
+      y = y + DOT;
+    }
   }
 
-  void prepare(int w, int h){
-    _root.width = 1+(w ~/ DOT) * DOT;
-    _root.height = 1+(h ~/ DOT) * DOT;
+  void prepare(int w, int h) {
+    _root.width = 1 + (w ~/ DOT) * DOT;
+    _root.height = 1 + (h ~/ DOT) * DOT;
     _ctx.imageSmoothingEnabled = false;
     _ctx.translate(0.5, 0.5);
     _ctx.scale(1, 1);
@@ -184,39 +184,36 @@ class ChiCanvas extends PolymerElement implements ChiEventListener{
     width = w;
     height = h;
 
-    if(href!=""){
+    if (href != "") {
       Future load = HttpRequest.request(href, mimeType: 'application/octet-stream', responseType: 'arraybuffer');
-        load.then((req){
-              Uint8List ul = (req.response as ByteBuffer).asUint8List();
-              String js = UTF8.decode(ul);
-              img = new Image.import(js);
-              front();
-          },
-          onError: (e){
-            window.alert("$href not found $e");
-          });
+      load.then((req) {
+        Uint8List ul = (req.response as ByteBuffer).asUint8List();
+        String js = UTF8.decode(ul);
+        img = new Image.import(js);
+        front();
+      }, onError: (e) {
+        window.alert("$href not found $e");
+      });
     }
     //print("$href ~ $nx:$ny::$base");
   }
 
   @override
-  void attached(){
+  void attached() {
     prepare(_div.clientWidth, _div.clientHeight);
-    if (!transparent)
-      back();
-    if (img != null)
-      front();
+    if (!transparent) back();
+    if (img != null) front();
   }
 
   @override
-  void listen(event){
+  void listen(event) {
 
   }
 
-  ChiCanvas.created() : super.created(){
+  ChiCanvas.created() : super.created() {
     _div = ($['root_canvas_container'] as DivElement);
     _root = ($['root_canvas'] as CanvasElement);
     _ctx = _root.context2D;
     listenTo(this);
   }
-}
+}

+ 27 - 25
lib/poly/chi_canvas.html

@@ -1,26 +1,28 @@
 <link rel="import" href="../../../packages/polymer/polymer.html">
-<polymer-element name="chi-canvas" attributes="base transparent href top left">
-  <template>
-     <style>
-      :host{
-        width: 100%;
-        height: 100%;
-      }
-      #root_canvas_bg{
-        width: 100%;
-        height: 100%;
-      }
-      #root_canvas_container {
-        width: calc(100% - 30px);
-        height: calc(100% - 6px);
-        margin-left: 15px;
-        margin-right: 15px;
-        margin-top: 3px;
-      }
-    </style>
-    <div id="root_canvas_bg">
-      <div id="root_canvas_container"><canvas id="root_canvas"></canvas></div>
-    </div>
-  </template>
-  <script type="application/dart" src="chi_canvas.dart"></script>
-</polymer-element>
+<polymer-element name="chi-canvas"
+  attributes="base transparent href top left"> <template>
+<style>
+:host {
+  width: 100%;
+  height: 100%;
+}
+
+#root_canvas_bg {
+  width: 100%;
+  height: 100%;
+}
+
+#root_canvas_container {
+  width: calc(100% -                     30px);
+  height: calc(100% -                     6px);
+  margin-left: 15px;
+  margin-right: 15px;
+  margin-top: 3px;
+}
+</style>
+<div id="root_canvas_bg">
+  <div id="root_canvas_container">
+    <canvas id="root_canvas"></canvas>
+  </div>
+</div>
+</template> <script type="application/dart" src="chi_canvas.dart"></script> </polymer-element>

+ 12 - 13
lib/poly/chi_controls.dart

@@ -5,35 +5,34 @@ import 'package:polymer/polymer.dart';
 import 'package:chi/tools.dart';
 import 'package:chi/app/loop.dart';
 
-Model feed(Model m){
+Model feed(Model m) {
   m.feed(0.01);
   return m;
 }
 
 @CustomTag("chi-controls")
-class ChiControls extends PolymerElement implements ChiEventListener{
+class ChiControls extends PolymerElement implements ChiEventListener {
 
   int _hm;
 
   @override
-  void listen(event){
-    if(event is AppStart){
+  void listen(event) {
+    if (event is AppStart) {
       bus.fire(new ModelComponentRegister());
-    }else if(event is ModelComponentInit){
-      if(_hm == null)
-        _hm = event.model.hashCode;
-    }else if (_hm!=null){
-      if(event is ModelUpdated){
-        ($["info"] as ParagraphElement).appendText(".");
+    } else if (event is ModelComponentInit) {
+      if (_hm == null) _hm = event.model.hashCode;
+    } else if (_hm != null) {
+      if (event is ModelUpdated) {
+
       }
     }
   }
 
-  void doFeed(Event e, var detail, Node target){
+  void doFeed(Event e, var detail, Node target) {
     bus.fire(new ModelUpdateRequest(feed));
   }
 
-  ChiControls.created() : super.created(){
+  ChiControls.created() : super.created() {
     listenTo(this);
   }
-}
+}

+ 5 - 8
lib/poly/chi_controls.html

@@ -1,8 +1,5 @@
-<link rel="import" href="../../../packages/polymer/polymer.html"/>
-<polymer-element name="chi-controls">
-  <template>
-    <p id="info"></p>
-    <input type="button" on-click="{{doFeed}}" id="feed" value="Покормить"/>
-  </template>
-  <script type="application/dart" src="chi_controls.dart"></script>
-</polymer-element>
+<link rel="import" href="../../../packages/polymer/polymer.html" />
+<polymer-element name="chi-controls"> <template>
+<p id="info"></p>
+<input type="button" on-click="{{doFeed}}" id="feed" value="Покормить" />
+</template> <script type="application/dart" src="chi_controls.dart"></script> </polymer-element>

+ 107 - 0
lib/poly/chi_meter.dart

@@ -0,0 +1,107 @@
+library elem;
+
+import 'dart:html';
+import 'package:polymer/polymer.dart';
+import 'package:chi/tools.dart';
+import 'package:chi/app/loop.dart';
+import 'package:color/color.dart';
+
+final Color BG_COLOR = new Color.hex("ced6b5");
+final Color SHADE_COLOR = new Color.hex("bac1a3");
+final Color BLACK = new Color.hex("000000");
+
+@CustomTag("chi-meter")
+class ChiMeter extends PolymerElement implements ChiEventListener {
+  int _hm;
+  CanvasRenderingContext2D ctx;
+  int width;
+  int height;
+  double _value = 0.0;
+  double get value => _value;
+
+  set value(double x) {
+    _value = x;
+    doDraw();
+  }
+
+  @published String property = "";
+
+  void setValue(Model m) {
+    switch (property) {
+      case "hunger":
+        value = m.fullness;
+        break;
+      default:
+        throw new ArgumentError.value(property, "", "неизвестный параметр");
+    }
+  }
+
+  @override
+  void listen(event) {
+    if (event is AppStart) {
+      bus.fire(new ModelComponentRegister());
+    } else if (event is ModelComponentInit) {
+      if (_hm == null) {
+        _hm = event.model.hashCode;
+        setValue(event.model);
+      }
+    } else if (_hm != null) {
+      if (event is ModelUpdated) {
+        setValue(event.model);
+      }
+    }
+  }
+
+  void doDraw() {
+    final int BAR_HEIGHT = height - 4;
+    final int BAR_WIDTH = BAR_HEIGHT ~/ 2;
+    final int count = -1 + ((width - 8) ~/ (BAR_WIDTH + 1));
+    final int _width = count * (BAR_WIDTH + 1) + 3;
+    final int val = (count * value).round();
+
+    ctx.clearRect(0, 0, width, height);
+    var color = BG_COLOR.toRgbColor();
+    ctx.setFillColorRgb(color.r, color.g, color.b);
+    ctx.fillRect(0, 0, _width, height);
+
+    color = BLACK.toRgbColor();
+    ctx.setFillColorRgb(color.r, color.g, color.b);
+    ctx.fillRect(0, 0, _width, 1);
+    ctx.fillRect(0, 0, 1, height);
+    ctx.fillRect(0, height - 1, _width, 1);
+    ctx.fillRect(_width - 1, 0, 1, height);
+
+    int x = 2;
+    int y = 2;
+    for (int i = 0; i < count; i++) {
+      if (i < val) color = BLACK.toRgbColor(); else color = SHADE_COLOR.toRgbColor();
+
+      ctx.setFillColorRgb(color.r, color.g, color.b);
+      ctx.fillRect(x, y, BAR_WIDTH, BAR_HEIGHT);
+      x = x + BAR_WIDTH + 1;
+    }
+  }
+
+  void prepare(int w, int h) {
+    var root = ($["meter_canvas"] as CanvasElement);
+    root.width = w;
+    root.height = h;
+    width = w;
+    height = h;
+
+    ctx = root.context2D;
+    ctx.imageSmoothingEnabled = false;
+  }
+
+  @override
+  void attached() {
+    assert(property != "");
+    var div = ($["meter_container"] as DivElement);
+    prepare(div.clientWidth, div.clientHeight);
+    doDraw();
+  }
+
+  ChiMeter.created() : super.created() {
+    listenTo(this);
+  }
+}

+ 8 - 0
lib/poly/chi_meter.html

@@ -0,0 +1,8 @@
+<link rel="import" href="../../../packages/polymer/polymer.html" />
+<polymer-element name="chi-meter" attributes="property">
+<template>
+<link rel="stylesheet" href="styles/meter.css">
+<div id="meter_container">
+  <canvas id="meter_canvas"></canvas>
+</div>
+</template> <script type="application/dart" src="chi_meter.dart"></script> </polymer-element>

+ 4 - 0
lib/poly/styles/meter.css

@@ -0,0 +1,4 @@
+#meter_container {
+  width: 100%;
+  height: 100%;
+}

+ 10 - 8
web/app/app.dart

@@ -5,15 +5,17 @@ import 'package:chi/storage.dart';
 import 'package:chi/app/loop.dart' as loop;
 import 'package:chi/tools.dart';
 
-main(){
+main() {
   initTools();
-  if(window.sessionStorage.containsKey(SESSION)){
+  if (window.sessionStorage.containsKey(SESSION)) {
     initPolymer().run(() {
-        Polymer.onReady.then((_) {
-          bus.on().listen(loop.handle);
-          bus.fire(new loop.AppStart());
-          Future.doWhile((){return new Future.delayed(new Duration(seconds: 10), loop.run);});
+      Polymer.onReady.then((_) {
+        bus.on().listen(loop.handle);
+        bus.fire(new loop.AppStart());
+        Future.doWhile(() {
+          return new Future.delayed(new Duration(seconds: 1), loop.run);
         });
+      });
     });
- }else window.location.replace("/");
-}
+  } else window.location.replace("/");
+}

BIN
web/app/fonts/FreePixel.ttf


+ 31 - 17
web/app/index.html

@@ -1,24 +1,38 @@
 <!DOCTYPE html>
 
 <html>
-  <head>
-  	<meta charset="utf-8">
-  	<meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>chi :: pet</title>
-    <link rel="stylesheet" href="styles/index.css">
-    <link rel="import" href="packages/chi/poly/chi_canvas.html">
-    <link rel="import" href="packages/chi/poly/chi_controls.html">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>chi :: pet</title>
+<link rel="stylesheet" href="styles/index.css">
+<link rel="import" href="packages/chi/poly/chi_canvas.html">
+<link rel="import" href="packages/chi/poly/chi_controls.html">
+<link rel="import" href="packages/chi/poly/chi_meter.html">
 </head>
-  <body unresolved>
-    <div id="pane">
-      <div class="layer"><chi-canvas base="6" transparent="false"></chi-canvas></div>
-      <div class="layer"><chi-canvas base="6" href="../img/eye0.json" top="20" left="30"></chi-canvas></div>
+<body unresolved>
+<div id="meters">
+  <div class="meter-label">
+    hunger:
+  </div>
+  <div class="meter">
+      <chi-meter property="hunger"></chi-meter>
     </div>
-    <div id="controls">
-      <chi-controls></chi-controls>
+  </div>
+  <div id="pane">
+    <div class="layer">
+      <chi-canvas base="6" transparent="false"></chi-canvas>
     </div>
-    <script type="application/dart" src="app.dart"></script>
-    <!-- for this next line to work, your pubspec.yaml file must have a dependency on 'browser' -->
-    <script src="packages/browser/dart.js"></script>
-  </body>
+    <div class="layer">
+      <chi-canvas base="6" href="../img/eye0.json" top="20" left="30"></chi-canvas>
+    </div>
+  </div>
+  <br/>
+  <div id="controls">
+    <chi-controls></chi-controls>
+  </div>
+  <script type="application/dart" src="app.dart"></script>
+  <!-- for this next line to work, your pubspec.yaml file must have a dependency on 'browser' -->
+  <script src="packages/browser/dart.js"></script>
+</body>
 </html>

+ 18 - 2
web/app/styles/index.css

@@ -1,4 +1,4 @@
-.layer{
+.layer {
   width: 100%;
   height: 100%;
   position: absolute;
@@ -6,10 +6,26 @@
   left: 0px;
 }
 
-#pane{
+#pane {
   width: 800px;
   height: 600px;
   border: 1px solid black;
   background-color: #ced6b5;
   position: relative;
+}
+
+.meter {
+  width: 250px;
+  height: 16px;
+}
+
+.meter-label{
+  font-family: pixel;
+  font-size: 12pt;
+  color: #000000;
+}
+
+@font-face {
+     font-family: pixel;
+     src: url('../fonts/FreePixel.ttf');
 }