chiark / gitweb /
usvg: Pass default options even during bundle processing.
[otter.git] / src / ui.rs
1 // Copyright 2020-2021 Ian Jackson and contributors to Otter
2 // SPDX-License-Identifier: AGPL-3.0-or-later
3 // There is NO WARRANTY.
4
5 use crate::prelude::*;
6
7 pub const HELD_SURROUND_COLOUR: &str = "black";
8
9 const MONOSPACE: HtmlLit = Html::lit(
10   r#"font-family="Latin Modern Mono, monospace" font-weight="700""#);
11
12 const USVG_DEFAULT_ARGS_TEXT: &str = include_str!("USVG_DEFAULT_ARGS.txt");
13
14 pub const DEFAULT_TABLE_SIZE: Pos = PosC::new( 300, 200 );
15 pub const DEFAULT_TABLE_COLOUR: &str = "green";
16
17 pub const SELECT_SCALE: f64 = 1.1;
18
19 // also in script.ts:redisplay_ancillaries ("halo")
20 //   nelem.setAttributeNS(null,'stroke-width','2px');
21 pub const SELECT_STROKE_WIDTH: f64 = 2.0;
22
23 pub const DEFAULT_EDGE_WIDTH: f64 = 0.2;
24 pub const INVISIBLE_EDGE_SENSITIVE: f64 = 2.;
25
26 pub const LABEL_FONT_SIZE: f64 = 4.0;
27
28 pub const HTML_TEXT_LABEL_ELEM_START: HtmlLit =
29   Html::lit(r##"text pointer-events="none""##);
30
31 #[derive(Debug,Serialize,Deserialize,Clone)]
32 pub struct TextOptions {
33   pub colour: Colour,
34   pub size: f64, // px
35 }
36
37 /// Fudge factor
38 ///
39 /// When trying to centre text, we use text-align and/or text-anchor
40 /// to do the horizontal positioning, but vertical positioning is
41 /// troublesome.  We bodge it.  Multiple the font size (in pixels)
42 /// by this, and add it to the SVG y coordinate (ie, shufting the text
43 /// down).
44 pub const SVG_FONT_Y_ADJUST_OF_FONT_SIZE: f64 =
45   include!("SVG_FONT_Y_ADJUST_OF_FONT_SIZE.txt");
46
47 pub fn default_edge_width() -> f64 { DEFAULT_EDGE_WIDTH }
48
49 pub fn monospace_font(size: u32) -> Html {
50   hformat!(r##"{} font-size="{}""##, MONOSPACE, size)
51 }
52
53 #[derive(Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize,EnumString)]
54 pub enum PresentationLayout {
55   Portrait,
56   Landscape,
57 }
58
59 type PL = PresentationLayout;
60
61 pub fn player_num_dasharray(player_num: NonZeroUsize) -> Html {
62   let n: usize = player_num.into();
63   let mut dasharray = String::with_capacity(n*3 + 4);
64   for dash in iter::once("3").chain(
65     iter::repeat("1").take(n-1))
66   {
67     write!(&mut dasharray, "{} 1 ", &dash).unwrap();
68   }
69   let spc = dasharray.pop();
70   assert_eq!(spc,Some(' '));
71   Html::from_html_string(dasharray)
72 }
73
74 pub fn player_dasharray(gplayers: &GPlayers, player: PlayerId) -> Html {
75   let kd: slotmap::KeyData = player.into();
76   let n: usize = kd.get_idx_version().0.try_into().unwrap();
77   let n: NonZeroUsize = n.try_into()
78     .unwrap_or_else(|_| gplayers.capacity().try_into().unwrap());
79   player_num_dasharray(n)
80 }
81
82 pub fn occultation_notify_update_image(piece: PieceId)
83                                        -> UnpreparedUpdates {
84   vec![Box::new(
85     move |updates: &mut PrepareUpdatesBuffer| {
86       updates.piece_update_image(piece, &None)
87         .unwrap_or_else(|e| error!("unable to send update! {:?}", e))
88     }
89   )]
90 }
91
92 impl PresentationLayout {
93   pub fn template(self) -> &'static str {
94     match self {
95       PL::Portrait => "session",
96       PL::Landscape => "landscape",
97     }
98   }
99   pub fn abbreviate_timestamps(self) -> bool {
100     match self {
101       PL::Portrait => false,
102       PL::Landscape => true,
103     }
104   }
105 }
106
107 impl Default for PresentationLayout {
108   fn default() -> Self { PL::Portrait }
109 }
110
111 #[derive(Debug)]
112 pub struct AbbrevPresentationLayout(pub PresentationLayout);
113
114 #[derive(Error,Debug,Clone,Copy)]
115 #[error("Invalid presentation layout character")]
116 pub struct InvalidAbbrevPresentationLayout;
117
118 impl FromStr for AbbrevPresentationLayout {
119   type Err = InvalidAbbrevPresentationLayout;
120   #[throws(Self::Err)]
121   fn from_str(s: &str) -> Self {
122     AbbrevPresentationLayout(match s {
123       "p" => PL::Portrait,
124       "l" => PL::Landscape,
125       _ => throw!(InvalidAbbrevPresentationLayout)
126     })
127   }
128 }
129
130 impl Display for AbbrevPresentationLayout {
131   #[throws(fmt::Error)]
132   fn fmt(&self, f: &mut fmt::Formatter) {
133     f.write_str(match self.0 {
134       PL::Portrait => "p",
135       PL::Landscape => "l",
136     })?
137   }
138 }
139
140 impl TextOptions {
141   pub fn y_adjust(&self) -> f64 {
142     self.size * SVG_FONT_Y_ADJUST_OF_FONT_SIZE
143   }
144
145   pub fn start_element(&self) -> Html {
146     hformat!{
147  r##"{} text-align="center" text-anchor="middle" x="0" y="{}" fill="{}" font-size="{}px""##,
148              HTML_TEXT_LABEL_ELEM_START,
149              self.y_adjust(), &self.colour, self.size,
150     }
151   }
152 }
153
154 pub fn usvg_default_args() -> impl Iterator<Item=&'static str> {
155   USVG_DEFAULT_ARGS_TEXT
156     .lines()
157     .map(|l| l.trim())
158     .filter(|l| l.len() > 0 && ! l.starts_with('#'))
159 }