chiark / gitweb /
wip new z
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 11 Jul 2020 14:57:35 +0000 (15:57 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 11 Jul 2020 14:57:35 +0000 (15:57 +0100)
src/bin/server.rs
src/gamestate.rs
src/global.rs
src/sse.rs
templates/script.ts
templates/session.tera

index 97ac32b0042f81a963aee4f20c64f9d34bb38586..726eb590d1d97bba35e2db517db32d9009c44eb7 100644 (file)
@@ -102,12 +102,14 @@ fn session(form : Json<SessionForm>) -> Result<Template,OE> {
         Some(o) => format!("{}",o),
       };
       uses.push(format!(
-        r##"<use id="{}" href="#{}" data-piece="{}" data-gplayer="{}" x="{}" y="{}"/>"##,
+        r##"<use id="{}" href="#{}" data-piece="{}" data-gplayer="{}" x="{}" y="{}" data-z="{}" data-zg="{}"/>"##,
         pri.id_use(),
         pri.id_piece(),
         pri.id,
         &gplayer,
-        pr.pos[0], pr.pos[1]));
+        pr.pos[0], pr.pos[1],
+        pr.zlevel.0, pr.zlevel.1,
+      ));
     }
 
     let src = SessionRenderContext {
@@ -231,7 +233,6 @@ fn api_piece_op<O: ApiPieceOp>(form : Json<ApiPiece<O>>)
         client,
         sameclient_cseq : form.cseq,
         piece : pri_for_all.id,
-        zg : pc.zlevel.1,
         op : update,
       });
 
@@ -323,7 +324,7 @@ impl ApiPieceOp for ApiPieceUngrab {
 struct ApiPieceRaise {
   z : ZCoord,
 }
-#[post("/_/api/raise", format="json", data="<form>")]
+#[post("/_/api/setz", format="json", data="<form>")]
 #[throws(OE)]
 fn api_raise(form : Json<ApiPiece<ApiPieceRaise>>)
             -> impl response::Responder<'static> {
index f6169ee5d6b3c58175cdd860cdfce8307e13e22b..3d1f17b0502322b18565be60f116adce2b160a81 100644 (file)
@@ -13,6 +13,11 @@ pub struct Generation (pub u64);
 impl Generation {
   pub fn increment(&mut self) { self.0 += 1 }
 }
+impl Display for Generation {
+  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    Display::fmt(&self.0,f)
+  }
+}
 
 visible_slotmap_key!{ VisiblePieceId('.') }
 
@@ -69,6 +74,11 @@ impl Ord for ZCoord {
   }
 }
 impl Eq for ZCoord { }
+impl Display for ZCoord {
+  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    Display::fmt(&self.0,f)
+  }
+}
 
 #[derive(Debug)]
 pub struct PieceRecord {
index f19107336e02f0d82a9af661e746c9823b33dd85..850a8516b4e76f51d1ba81a428c5f0c0c73be807 100644 (file)
@@ -30,7 +30,6 @@ pub enum PreparedUpdateEntry {
     sameclient_cseq : ClientSequence,
     piece : VisiblePieceId,
     op : PieceUpdateOp<PreparedPieceState>,
-    zg : Generation,
   },
   Log (Arc<LogEntry>),
 }
@@ -84,6 +83,16 @@ impl<NS> PieceUpdateOp<NS> {
       SetZLevel(zl) => SetZLevel(zl),
     }
   }
+  pub fn new_z_generation(&self) -> Option<Generation> {
+    use PieceUpdateOp::*;
+    match self {
+      Delete() => None,
+      Insert(_) => None,
+      Modify(_) => None,
+      Move(_) => None,
+      SetZLevel((_,zg)) => Some(*zg),
+    }
+  }
 }      
 
 #[derive(Debug)]
index 296b57f4b05d2e176f99d1ea2f8bcb8b1bdd1a7a..fe2b43b3a80a2943e47316bb1ade39943a9049b1 100644 (file)
@@ -51,7 +51,7 @@ enum TransmitUpdate<'u> {
   Recorded {
     piece : VisiblePieceId,
     cseq : ClientSequence,
-    zg : Generation,
+    zg : Option<Generation>,
   },
   Piece {
     piece : VisiblePieceId,
@@ -95,8 +95,9 @@ impl Read for UpdateReader {
       for u in &next.us {
         let tu = match u {
           &PreparedUpdateEntry::Piece
-          { piece, client, sameclient_cseq : cseq, zg, .. }
+          { piece, client, sameclient_cseq : cseq, ref op }
           if client== self.client => {
+            let zg = op.new_z_generation();
             TransmitUpdate::Recorded { piece, cseq, zg }
           },
           &PreparedUpdateEntry::Piece { piece, ref op, .. } => {
index da9ee8148c584ba40807c4fa4674568dbbe5c646..b6d033390bf58e0fcf97f998514fb3861b3bb6bb 100644 (file)
@@ -13,6 +13,7 @@
 //         .piece   piece id (static)
 //         .gplayer  grabbed user (player id string, or "")
 //         .cseq     client sequence (see PROTOCOL.md)
+//         .z, .zg   Z level
 //      container to allow quick movement and hang stuff off
 //
 //   delem
@@ -60,6 +61,7 @@ var ctoken : string;
 
 var svg_ns : string;
 var space : SVGGraphicsElement;
+var def_marker : SVGGraphicsElement;
 var logdiv : HTMLElement;
 var status_node : HTMLElement;
 
@@ -129,12 +131,16 @@ function api_piece(f: (meth: string, payload: Object) => void,
   })
 }
 
+function svg_element(id: string): SVGGraphicsElement | null {
+  let elem = document.getElementById(id);
+  return elem as unknown as (SVGGraphicsElement | null);
+}
 function piece_element(base: string, piece: PieceId): SVGGraphicsElement | null
 {
-  let elem = document.getElementById(base+piece);
-  return elem as unknown as (SVGGraphicsElement | null);
+  return svg_element(base+piece);
 }
 
+
 // ----- clicking/dragging pieces -----
 
 enum DRAGGING { // bitmask
@@ -227,24 +233,21 @@ function drag_mousemove(e: MouseEvent) {
 function drag_mouseup(e: MouseEvent) {
   console.log('mouseup', dragging);
   let ddr2 : number = drag_mousemove(e);
-  let piece = drag_uelem!.dataset.piece!;
+  let uelem = drag_uelem!;
+  let piece = uelem.dataset.piece!;
   let pelem = piece_element('piece',piece)!;
   let dragraise = +pelem.dataset.dragraise!;
   console.log('CHECK RAISE ', dragraise, dragraise*dragraise, ddr2);
   if (dragraise > 0 && ddr2 >= dragraise*dragraise) {
-    let marker = piece_element('raisemarker',piece);
-    if (marker == null) {
-      marker = document.createElementNS(svg_ns,'defs')! as
-                   SVGGraphicsElement;
-      marker.setAttributeNS(null,'id','raisemarker'+piece);
-      drag_uelem!.parentNode!.insertBefore(marker, drag_uelem!);
-    }
-    raise_piece(drag_uelem!);
-    api_piece(api, "raise", piece, drag_uelem!, { });
+    piece_set_zlevel(uelem, (old_top) => {
+      let z = old_top.dataset.z! + 1;
+      uelem.dataset.z = z;
+      api_piece(api, "setz", piece, uelem, { z: z });
+    });
   }
   if (dragging == DRAGGING.MAYBE_UNGRAB ||
       dragging == (DRAGGING.MAYBE_GRAB | DRAGGING.YES)) {
-    set_ungrab(drag_uelem!, pelem);
+    set_ungrab(uelem, pelem);
     api_piece(api, 'ungrab', piece, drag_uelem!, { });
   }
   drag_cancel();
@@ -315,14 +318,36 @@ pieceops.Modify = <PieceHandler>function
   console.log('MODIFY DONE');
 }
 
-function raise_piece(uelem: SVGGraphicsElement) {
-  uelem.parentElement!.appendChild(uelem);
+function piece_set_zlevel(uelem: SVGGraphicsElement,
+                         modify : (old_top: SVGGraphicsElement) => void) {
+  // Calls modify, which should set .dataset.z and/or .gz, and/or
+  // make any necessary API call.
+  //
+  // Then moves uelem to the right place in the DOM.  This is done
+  // by assuming that uelem ought to go at the end, so this is
+  // O(new depth), which is right (since the UI for inserting
+  // an object is itself O(new depth) UI operations to prepare.
+/*
+  let old_top = def_marker.previousElementSibling! as  unknown as SVGGraphicsElement;
+  modify(old_top);
+  let container = uelem.parentElement!;
+  container.insertBefore(def_marker, uelem);
+
+  let previous = uelem | null;
+  while ((previous = previous.previousElementSibling) != null &&
+        piece_z_before(uelem, previous)) {
+  }
+  if (previous != uelem) {
+    constainer.insertAfter(previous, uelem);
+  }
+*/
 }
-
-pieceops.Raise = <PieceHandler>function
-(piece, info: { } ) {
-  var uelem = piece_element('use',piece)!;
-  raise_piece(uelem);
+function piece_z_before(a: SVGGraphicsElement, b: SVGGraphicsElement) {
+  if (+(a.dataset.z !) < +(b.dataset.z !)) return true;
+  if (+(a.dataset.z !) > +(b.dataset.z !)) return false;
+  if (+(a.dataset.zg!) < +(b.dataset.zg!)) return true;
+  if (+(a.dataset.zg!) > +(b.dataset.zg!)) return false;
+  return false;
 }
 
 pieceops.Move = <PieceHandler>function
@@ -333,10 +358,20 @@ pieceops.Move = <PieceHandler>function
   uelem.setAttributeNS(null, "y", info[1]+"");
 }
 
+pieceops.SetZLevel = <PieceHandler>function
+(piece, info: { z: Number, zg: Generation }) {
+  let uelem = piece_element('use',piece)!;
+  piece_set_zlevel(uelem, (old_top)=>{
+    uelem.dataset.z  = info.z +"";
+    uelem.dataset.zg = info.zg+"";
+  });
+}
+
 messages.Recorded = <MessageHandler>function
-(j: { piece: PieceId, cseq: ClientSeq, gen: Generation } ) {
+(j: { piece: PieceId, cseq: ClientSeq, gen: Generation,
+      zg: Generation|null } ) {
   let piece = j.piece;
-  var uelem = document.getElementById('use'+piece)!;
+  var uelem = piece_element('use',piece)!;
   if (uelem.dataset.cseq != null && j.cseq >= +uelem.dataset.cseq) {
     delete uelem.dataset.cseq;
     let marker = piece_element('raisemarker',piece);
@@ -344,6 +379,11 @@ messages.Recorded = <MessageHandler>function
       marker.remove();
     }
   }
+  if (j.zg != null) {
+    piece_set_zlevel(uelem, (old_top: SVGGraphicsElement)=>{
+      uelem.dataset.zg = j.zg+"";
+    });
+  }
   gen = j.gen;
 }
 
@@ -365,8 +405,10 @@ function startup() {
   gen = +body.dataset.gen!;
   status_node = document.getElementById('status')!;
   status_node.innerHTML = 'js-done';
-  space = document.getElementById('space') as unknown as SVGGraphicsElement;
   logdiv = document.getElementById("log")!;
+
+  space = svg_element('space')!;
+  def_marker = svg_element("def_marker")!;
   svg_ns = space.getAttribute('xmlns')!;
 
   var es = new EventSource("/_/updates/"+ctoken+'/'+gen);
index fbcf1b0273be9314979bf49524764239448b4fb7..c5b03d5f75c2679964e3504b3f1e7620e03dc41e 100644 (file)
@@ -17,6 +17,7 @@
 {%- for piece in uses %}
       {{piece}}
 {%- endfor %}
+      <defs id="def_marker"></defs>
 {%- for piece in defs %}
       <defs id="defs{{ piece.0 }}">{{ piece.1 }}</defs>
 {%- endfor %}