chiark / gitweb /
currency: Initial skeleton
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 17 Apr 2022 22:05:30 +0000 (23:05 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 17 Apr 2022 23:21:31 +0000 (00:21 +0100)
Can render, but no special behaviours.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/currency.rs [new file with mode: 0644]
src/lib.rs
src/spec.rs

diff --git a/src/currency.rs b/src/currency.rs
new file mode 100644 (file)
index 0000000..e39cfc2
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright 2020-2021 Ian Jackson and contributors to Otter
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+//! Currency
+//!
+//! A "Currency" piece
+//!  - has an image, which is another piece which it displays
+//!  - has special counting behaviour on drag and drop
+//!  - represents a *quanity*
+
+// Future plans
+//  - occultable, to hide the quantity
+//  - can have a back face which is less manipulable (if image has 2 faces)
+
+use crate::prelude::*;
+
+const QTY_FONT_SIZE: f64 = 6.;
+
+type Qty = u32;
+
+#[derive(Debug,Serialize,Deserialize)]
+pub struct Spec {
+  image: Box<dyn PieceSpec>,
+  qty: Qty,
+  currency: String,
+  #[serde(default="default_min_unit")] min_unit: Qty,
+}
+
+fn default_min_unit() -> Qty { 1 }
+
+#[derive(Debug,Serialize,Deserialize)]
+pub struct Banknote {
+  itemname: String,
+  image: Arc<dyn InertPieceTrait>,
+  qty: Qty,
+  currency: String,
+  min_unit: Qty,
+}
+
+#[typetag::serde(name="Currency")]
+impl PieceSpec for Spec {
+  #[throws(SpecError)]
+  fn load(&self, _: usize, gpc: &mut GPiece, ig: &Instance, depth: SpecDepth)
+          -> PieceSpecLoaded {
+    gpc.rotateable = false;
+
+    let Spec { ref image, ref currency, qty, min_unit } = *self;
+
+    let SpecLoaded { p: image, occultable:_ } =
+      image.load_inert(ig, depth)?;
+
+    let itemname = format!("currency-{}", image.itemname());
+
+    if image.nfaces() != 1 {
+      throw!(SpecError::WrongNumberOfFaces {
+        got: image.nfaces(), got_why: "image".into(),
+        exp: 1,              exp_why: "needed".into(),
+      });
+    }
+        
+    if (qty % min_unit) != 0 {
+      throw!(SpecError::CurrencyQtyNotMultipleOfUnit)
+    }
+
+    let bnote = Banknote {
+      image: image.into(),
+      currency: currency.clone(),
+      itemname, qty, min_unit,
+    };
+
+    SpecLoaded { p: Box::new(bnote) as _, occultable: None }
+  }
+}
+
+#[dyn_upcast]
+impl OutlineTrait for Banknote {
+  delegate!{
+    to self.image {
+      fn outline_path(&self, scale: f64) -> Result<Html, IE>;
+      fn thresh_dragraise(&self) -> Result<Option<Coord>, IE>;
+      fn bbox_approx(&self) -> Result<Rect, IE>;
+    }
+  }
+}
+
+#[dyn_upcast]
+impl PieceBaseTrait for Banknote {
+  fn nfaces(&self) -> RawFaceId { self.image.nfaces() }
+  fn itemname(&self) -> &str { &self.itemname }
+}
+
+#[typetag::serde(name="Currency")]
+impl PieceTrait for Banknote {
+  #[throws(IE)]
+  fn describe_html(&self, gpc: &GPiece, _: &GameOccults) -> Html {
+    hformat!("{}, {} {}",
+             self.image.describe_html(gpc.face)?,
+             self.qty, Html::from_txt(&self.currency))
+  }
+
+  #[throws(IE)]
+  fn svg_piece(&self, f: &mut Html, gpc: &GPiece, _gs: &GameState,
+               vpid: VisiblePieceId) {
+    self.image.svg(f, vpid, gpc.face, &gpc.xdata)?;
+    
+    let label_font_size = QTY_FONT_SIZE;
+    let label_y_adj = label_font_size * SVG_FONT_Y_ADJUST_OF_FONT_SIZE;
+
+    hwrite!(f,
+            r##"<text text-align="center" text-anchor="middle" x="0" y="{}" font-size="{}">{} {}</text>"##,
+            label_y_adj, label_font_size,
+            self.qty, &self.currency)?;
+  }
+}
index 4cc863f43bddcc4f538f508b2ebb9fedc017eb5e..7394bd94ac047737d4556c5512dd8b09b543c833 100644 (file)
@@ -29,6 +29,7 @@ pub mod childio;
 pub mod clock;
 pub mod commands;
 pub mod config;
+pub mod currency;
 pub mod deck;
 pub mod dice;
 pub mod debugmutex;
index d429c715fae9f8ff4d31a950eb7124441284bd04..47e211ec24cd2f80033f7b024c1a669d631830bd 100644 (file)
@@ -87,6 +87,8 @@ pub enum SpecError {
   #[error("invalid size scale")]             InvalidSizeScale,
   #[error("multiple faces required")]        MultipleFacesRequired,
   #[error("far too many faces ({0})")]       FarTooManyFaces(usize),
+  #[error("currency quantity not multiple of minimum unit")]
+  CurrencyQtyNotMultipleOfUnit,
   #[error("coordinate overflow")]
   CoordinateOverflow(#[from] CoordinateOverflow),
   #[error("image for supposedly-occultable piece \