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