wzrd

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in Rust
git clone git://git.deurzen.net/wzrd
Log | Files | Refs | LICENSE

geometry.rs (17076B)


      1 use crate::hints::SizeHints;
      2 use crate::window::Window;
      3 
      4 use std::ops::Add;
      5 use std::ops::AddAssign;
      6 use std::ops::Sub;
      7 use std::ops::SubAssign;
      8 
      9 pub type Extents = Padding;
     10 
     11 #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
     12 pub enum Edge {
     13     Left,
     14     Right,
     15     Top,
     16     Bottom,
     17 }
     18 
     19 #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
     20 pub enum Corner {
     21     TopLeft,
     22     TopRight,
     23     BottomLeft,
     24     BottomRight,
     25 }
     26 
     27 #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
     28 pub struct Pos {
     29     pub x: i32,
     30     pub y: i32,
     31 }
     32 
     33 impl Default for Pos {
     34     fn default() -> Self {
     35         Self {
     36             x: 0,
     37             y: 0,
     38         }
     39     }
     40 }
     41 
     42 impl Pos {
     43     pub fn from_center_of_region(region: Region) -> Self {
     44         Self {
     45             x: region.pos.x + (region.dim.w as f32 / 2f32) as i32,
     46             y: region.pos.y + (region.dim.h as f32 / 2f32) as i32,
     47         }
     48     }
     49 
     50     pub fn from_center_of_dim(dim: Dim) -> Self {
     51         Self {
     52             x: dim.w / 2,
     53             y: dim.h / 2,
     54         }
     55     }
     56 
     57     pub fn values(&self) -> (i32, i32) {
     58         (self.x, self.y)
     59     }
     60 
     61     pub fn dist(
     62         &self,
     63         pos: Self,
     64     ) -> Distance {
     65         Distance {
     66             dx: (pos.x - self.x),
     67             dy: (pos.y - self.y),
     68         }
     69     }
     70 
     71     pub fn relative_to(
     72         &self,
     73         pos: Self,
     74     ) -> Self {
     75         Pos {
     76             x: self.x - pos.x,
     77             y: self.y - pos.y,
     78         }
     79     }
     80 
     81     pub fn is_origin(&self) -> bool {
     82         *self
     83             == Pos {
     84                 x: 0,
     85                 y: 0,
     86             }
     87     }
     88 }
     89 
     90 impl Add<Pos> for Pos {
     91     type Output = Self;
     92 
     93     fn add(
     94         self,
     95         other: Pos,
     96     ) -> Self::Output {
     97         Self::Output {
     98             x: self.x + other.x,
     99             y: self.y + other.y,
    100         }
    101     }
    102 }
    103 
    104 #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
    105 pub struct Dim {
    106     pub w: i32,
    107     pub h: i32,
    108 }
    109 
    110 impl Default for Dim {
    111     fn default() -> Self {
    112         Self {
    113             w: 0,
    114             h: 0,
    115         }
    116     }
    117 }
    118 
    119 impl Dim {
    120     pub fn values(&self) -> (i32, i32) {
    121         (self.w, self.h)
    122     }
    123 
    124     pub fn center(&self) -> Pos {
    125         Pos {
    126             x: (self.w as f32 / 2f32) as i32,
    127             y: (self.h as f32 / 2f32) as i32,
    128         }
    129     }
    130 
    131     pub fn nearest_corner(
    132         &self,
    133         pos: Pos,
    134     ) -> Corner {
    135         let center = self.center();
    136 
    137         if pos.x >= center.x {
    138             if pos.y >= center.y {
    139                 Corner::BottomRight
    140             } else {
    141                 Corner::TopRight
    142             }
    143         } else {
    144             if pos.y >= center.y {
    145                 Corner::BottomLeft
    146             } else {
    147                 Corner::TopLeft
    148             }
    149         }
    150     }
    151 }
    152 
    153 impl Add<Dim> for Pos {
    154     type Output = Self;
    155 
    156     fn add(
    157         self,
    158         other: Dim,
    159     ) -> Self::Output {
    160         Self::Output {
    161             x: self.x + other.w,
    162             y: self.y + other.h,
    163         }
    164     }
    165 }
    166 
    167 impl Sub<Dim> for Pos {
    168     type Output = Self;
    169 
    170     fn sub(
    171         self,
    172         other: Dim,
    173     ) -> Self::Output {
    174         Self::Output {
    175             x: self.x - other.w,
    176             y: self.y - other.h,
    177         }
    178     }
    179 }
    180 
    181 impl Sub for Pos {
    182     type Output = Dim;
    183 
    184     fn sub(
    185         self,
    186         other: Self,
    187     ) -> Self::Output {
    188         Self::Output {
    189             w: self.x - other.x,
    190             h: self.y - other.y,
    191         }
    192     }
    193 }
    194 
    195 #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
    196 pub struct Region {
    197     pub pos: Pos,
    198     pub dim: Dim,
    199 }
    200 
    201 impl Default for Region {
    202     fn default() -> Self {
    203         Self {
    204             pos: Default::default(),
    205             dim: Default::default(),
    206         }
    207     }
    208 }
    209 
    210 impl Region {
    211     pub fn new(
    212         x: i32,
    213         y: i32,
    214         w: i32,
    215         h: i32,
    216     ) -> Self {
    217         Self {
    218             pos: Pos {
    219                 x,
    220                 y,
    221             },
    222             dim: Dim {
    223                 w,
    224                 h,
    225             },
    226         }
    227     }
    228 
    229     pub fn values(&self) -> (Pos, Dim) {
    230         (self.pos, self.dim)
    231     }
    232 
    233     pub fn with_size_hints(
    234         self,
    235         size_hints: &Option<SizeHints>,
    236     ) -> Self {
    237         let mut geometry = self;
    238 
    239         if let Some(size_hints) = size_hints {
    240             size_hints.apply(&mut geometry.dim);
    241         }
    242 
    243         geometry
    244     }
    245 
    246     pub fn encompasses(
    247         &self,
    248         pos: Pos,
    249     ) -> bool {
    250         pos.x >= self.pos.x
    251             && pos.y >= self.pos.y
    252             && pos.x <= self.pos.x + self.dim.w
    253             && pos.y <= self.pos.y + self.dim.h
    254     }
    255 
    256     pub fn contains(
    257         &self,
    258         region: Region,
    259     ) -> bool {
    260         self.encompasses(region.pos) && self.encompasses(region.bottom_right())
    261     }
    262 
    263     pub fn occludes(
    264         &self,
    265         region: Region,
    266     ) -> bool {
    267         self.encompasses(region.pos) || region.encompasses(self.pos)
    268     }
    269 
    270     pub fn nearest_corner(
    271         &self,
    272         mut pos: Pos,
    273     ) -> Corner {
    274         pos += self.pos.dist(Pos {
    275             x: 0,
    276             y: 0,
    277         });
    278         self.dim.nearest_corner(pos)
    279     }
    280 
    281     pub fn quadrant_center_from_pos(
    282         &self,
    283         pos: Pos,
    284     ) -> Option<Pos> {
    285         if self.encompasses(pos) {
    286             return None;
    287         }
    288 
    289         let mut dists = vec![
    290             (Corner::TopLeft, self.pos.dist(pos).pythagorean()),
    291             (Corner::TopRight, self.top_right().dist(pos).pythagorean()),
    292             (
    293                 Corner::BottomLeft,
    294                 self.bottom_left().dist(pos).pythagorean(),
    295             ),
    296             (
    297                 Corner::BottomRight,
    298                 self.bottom_right().dist(pos).pythagorean(),
    299             ),
    300         ];
    301 
    302         dists.sort_by_key(|&(corner, dist)| dist);
    303 
    304         match dists.first().unwrap() {
    305             (Corner::TopLeft, _) => {
    306                 let (left, _) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
    307                 let (topleft, _) = left.split_at_height((left.dim.h as f64 / 2f64).round() as i32);
    308 
    309                 Some(Pos::from_center_of_region(topleft))
    310             },
    311             (Corner::TopRight, _) => {
    312                 let (_, right) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
    313                 let (topright, _) =
    314                     right.split_at_height((right.dim.h as f64 / 2f64).round() as i32);
    315 
    316                 Some(Pos::from_center_of_region(topright))
    317             },
    318             (Corner::BottomLeft, _) => {
    319                 let (left, _) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
    320                 let (_, bottomleft) =
    321                     left.split_at_height((left.dim.h as f64 / 2f64).round() as i32);
    322 
    323                 Some(Pos::from_center_of_region(bottomleft))
    324             },
    325             (Corner::BottomRight, _) => {
    326                 let (_, right) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
    327                 let (_, bottomright) =
    328                     right.split_at_height((right.dim.h as f64 / 2f64).round() as i32);
    329 
    330                 Some(Pos::from_center_of_region(bottomright))
    331             },
    332         }
    333     }
    334 
    335     pub fn split_at_width(
    336         &self,
    337         width: i32,
    338     ) -> (Self, Self) {
    339         let width = std::cmp::min(width, self.dim.w);
    340 
    341         (
    342             Self {
    343                 dim: Dim {
    344                     w: width,
    345                     ..self.dim
    346                 },
    347                 ..*self
    348             },
    349             Self {
    350                 pos: Pos {
    351                     x: self.pos.x + width,
    352                     ..self.pos
    353                 },
    354                 dim: Dim {
    355                     w: self.dim.w - width,
    356                     ..self.dim
    357                 },
    358             },
    359         )
    360     }
    361 
    362     pub fn split_at_height(
    363         &self,
    364         height: i32,
    365     ) -> (Self, Self) {
    366         let height = std::cmp::min(height, self.dim.h);
    367 
    368         (
    369             Self {
    370                 dim: Dim {
    371                     h: height,
    372                     ..self.dim
    373                 },
    374                 ..*self
    375             },
    376             Self {
    377                 pos: Pos {
    378                     y: self.pos.y + height,
    379                     ..self.pos
    380                 },
    381                 dim: Dim {
    382                     h: self.dim.h - height,
    383                     ..self.dim
    384                 },
    385             },
    386         )
    387     }
    388 
    389     pub fn with_minimum_dim(
    390         self,
    391         minimum_dim: &Dim,
    392     ) -> Self {
    393         Self {
    394             pos: self.pos,
    395             dim: Dim {
    396                 w: std::cmp::max(minimum_dim.w, self.dim.w),
    397                 h: std::cmp::max(minimum_dim.h, self.dim.h),
    398             },
    399         }
    400     }
    401 
    402     pub fn with_maximum_dim(
    403         self,
    404         maximum_dim: &Dim,
    405     ) -> Self {
    406         Self {
    407             pos: self.pos,
    408             dim: Dim {
    409                 w: std::cmp::min(maximum_dim.w, self.dim.w),
    410                 h: std::cmp::min(maximum_dim.h, self.dim.h),
    411             },
    412         }
    413     }
    414 
    415     pub fn from_absolute_inner_center(
    416         self,
    417         dim: Dim,
    418     ) -> Self {
    419         Self {
    420             pos: Pos {
    421                 x: if dim.w > self.dim.w {
    422                     self.pos.x
    423                 } else {
    424                     self.pos.x + ((self.dim.w - dim.w) as f32 / 2f32) as i32
    425                 },
    426                 y: if dim.h > self.dim.h {
    427                     self.pos.y
    428                 } else {
    429                     self.pos.y + ((self.dim.h - dim.h) as f32 / 2f32) as i32
    430                 },
    431             },
    432             dim,
    433         }
    434     }
    435 
    436     pub fn without_extents(
    437         mut self,
    438         extents: Extents,
    439     ) -> Self {
    440         self.pos.x += extents.left;
    441         self.pos.y += extents.top;
    442         self.dim.w -= extents.left + extents.right;
    443         self.dim.h -= extents.top + extents.bottom;
    444         self
    445     }
    446 
    447     pub fn with_extents(
    448         mut self,
    449         extents: Extents,
    450     ) -> Self {
    451         self.pos.x -= extents.left;
    452         self.pos.y -= extents.top;
    453         self.dim.w += extents.left + extents.right;
    454         self.dim.h += extents.top + extents.bottom;
    455         self
    456     }
    457 
    458     pub fn top_right(&self) -> Pos {
    459         Pos {
    460             x: self.pos.x + self.dim.w,
    461             y: self.pos.y,
    462         }
    463     }
    464 
    465     pub fn bottom_left(&self) -> Pos {
    466         Pos {
    467             x: self.pos.x,
    468             y: self.pos.y + self.dim.h,
    469         }
    470     }
    471 
    472     pub fn bottom_right(&self) -> Pos {
    473         Pos {
    474             x: self.pos.x + self.dim.w,
    475             y: self.pos.y + self.dim.h,
    476         }
    477     }
    478 }
    479 
    480 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    481 pub struct Padding {
    482     pub left: i32,
    483     pub right: i32,
    484     pub top: i32,
    485     pub bottom: i32,
    486 }
    487 
    488 impl Default for Padding {
    489     fn default() -> Self {
    490         Self {
    491             left: 0,
    492             right: 0,
    493             top: 0,
    494             bottom: 0,
    495         }
    496     }
    497 }
    498 
    499 impl Padding {
    500     pub fn with_each_edge(size: i32) -> Self {
    501         Self {
    502             left: size,
    503             right: size,
    504             top: size,
    505             bottom: size,
    506         }
    507     }
    508 }
    509 
    510 impl Add<Padding> for Region {
    511     type Output = Self;
    512 
    513     fn add(
    514         self,
    515         padding: Padding,
    516     ) -> Self::Output {
    517         Self::Output {
    518             pos: Pos {
    519                 x: self.pos.x - padding.left,
    520                 y: self.pos.y - padding.top,
    521             },
    522             dim: Dim {
    523                 w: self.dim.w + padding.left + padding.right,
    524                 h: self.dim.h + padding.top + padding.bottom,
    525             },
    526         }
    527     }
    528 }
    529 
    530 impl Sub<Padding> for Region {
    531     type Output = Self;
    532 
    533     fn sub(
    534         self,
    535         padding: Padding,
    536     ) -> Self::Output {
    537         Self::Output {
    538             pos: Pos {
    539                 x: self.pos.x + padding.left,
    540                 y: self.pos.y + padding.top,
    541             },
    542             dim: Dim {
    543                 w: self.dim.w - padding.left - padding.right,
    544                 h: self.dim.h - padding.top - padding.bottom,
    545             },
    546         }
    547     }
    548 }
    549 
    550 impl AddAssign<Padding> for Region {
    551     fn add_assign(
    552         &mut self,
    553         padding: Padding,
    554     ) {
    555         *self = Self {
    556             pos: Pos {
    557                 x: self.pos.x - padding.left,
    558                 y: self.pos.y - padding.top,
    559             },
    560             dim: Dim {
    561                 w: self.dim.w + padding.left + padding.right,
    562                 h: self.dim.h + padding.top + padding.bottom,
    563             },
    564         };
    565     }
    566 }
    567 
    568 impl SubAssign<Padding> for Region {
    569     fn sub_assign(
    570         &mut self,
    571         padding: Padding,
    572     ) {
    573         *self = Self {
    574             pos: Pos {
    575                 x: self.pos.x + padding.left,
    576                 y: self.pos.y + padding.top,
    577             },
    578             dim: Dim {
    579                 w: self.dim.w - padding.left - padding.right,
    580                 h: self.dim.h - padding.top - padding.bottom,
    581             },
    582         };
    583     }
    584 }
    585 
    586 impl Add<Padding> for Dim {
    587     type Output = Self;
    588 
    589     fn add(
    590         self,
    591         padding: Padding,
    592     ) -> Self::Output {
    593         Self::Output {
    594             w: self.w + padding.left + padding.right,
    595             h: self.h + padding.top + padding.bottom,
    596         }
    597     }
    598 }
    599 
    600 impl Sub<Padding> for Dim {
    601     type Output = Self;
    602 
    603     fn sub(
    604         self,
    605         padding: Padding,
    606     ) -> Self::Output {
    607         Self::Output {
    608             w: self.w - padding.left - padding.right,
    609             h: self.h - padding.top - padding.bottom,
    610         }
    611     }
    612 }
    613 
    614 impl AddAssign<Padding> for Dim {
    615     fn add_assign(
    616         &mut self,
    617         padding: Padding,
    618     ) {
    619         *self = Self {
    620             w: self.w + padding.left + padding.right,
    621             h: self.h + padding.top + padding.bottom,
    622         };
    623     }
    624 }
    625 
    626 impl SubAssign<Padding> for Dim {
    627     fn sub_assign(
    628         &mut self,
    629         padding: Padding,
    630     ) {
    631         *self = Self {
    632             w: self.w - padding.left - padding.right,
    633             h: self.h - padding.top - padding.bottom,
    634         };
    635     }
    636 }
    637 
    638 #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
    639 pub struct Distance {
    640     pub dx: i32,
    641     pub dy: i32,
    642 }
    643 
    644 impl Distance {
    645     pub fn values(&self) -> (i32, i32) {
    646         (self.dx, self.dy)
    647     }
    648 
    649     pub fn pythagorean(&self) -> i32 {
    650         let dx = self.dx.pow(2) as f64;
    651         let dy = self.dy.pow(2) as f64;
    652 
    653         (dx + dy).sqrt().round() as i32
    654     }
    655 }
    656 
    657 impl Add<Distance> for Pos {
    658     type Output = Self;
    659 
    660     fn add(
    661         self,
    662         dist: Distance,
    663     ) -> Self::Output {
    664         Self::Output {
    665             x: self.x + dist.dx,
    666             y: self.y + dist.dy,
    667         }
    668     }
    669 }
    670 
    671 impl AddAssign<Distance> for Pos {
    672     fn add_assign(
    673         &mut self,
    674         dist: Distance,
    675     ) {
    676         *self = Self {
    677             x: self.x + dist.dx,
    678             y: self.y + dist.dy,
    679         };
    680     }
    681 }
    682 
    683 impl Sub<Distance> for Pos {
    684     type Output = Self;
    685 
    686     fn sub(
    687         self,
    688         dist: Distance,
    689     ) -> Self::Output {
    690         Self::Output {
    691             x: self.x - dist.dx,
    692             y: self.y - dist.dy,
    693         }
    694     }
    695 }
    696 
    697 impl SubAssign<Distance> for Pos {
    698     fn sub_assign(
    699         &mut self,
    700         dist: Distance,
    701     ) {
    702         *self = Self {
    703             x: self.x - dist.dx,
    704             y: self.y - dist.dy,
    705         };
    706     }
    707 }
    708 
    709 impl Add<Distance> for Dim {
    710     type Output = Self;
    711 
    712     fn add(
    713         self,
    714         dist: Distance,
    715     ) -> Self::Output {
    716         Self::Output {
    717             w: (self.w + dist.dx).abs(),
    718             h: (self.h + dist.dy).abs(),
    719         }
    720     }
    721 }
    722 
    723 impl AddAssign<Distance> for Dim {
    724     fn add_assign(
    725         &mut self,
    726         dist: Distance,
    727     ) {
    728         *self = Self {
    729             w: (self.w + dist.dx).abs(),
    730             h: (self.h + dist.dy).abs(),
    731         };
    732     }
    733 }
    734 
    735 impl Sub<Distance> for Dim {
    736     type Output = Self;
    737 
    738     fn sub(
    739         self,
    740         dist: Distance,
    741     ) -> Self::Output {
    742         Self::Output {
    743             w: (self.w - dist.dx).abs(),
    744             h: (self.h - dist.dy).abs(),
    745         }
    746     }
    747 }
    748 
    749 impl SubAssign<Distance> for Dim {
    750     fn sub_assign(
    751         &mut self,
    752         dist: Distance,
    753     ) {
    754         *self = Self {
    755             w: (self.w - dist.dx).abs(),
    756             h: (self.h - dist.dy).abs(),
    757         };
    758     }
    759 }
    760 
    761 #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
    762 pub struct Ratio {
    763     pub numerator: i32,
    764     pub denominator: i32,
    765 }
    766 
    767 impl Ratio {
    768     pub fn new(
    769         numerator: i32,
    770         denominator: i32,
    771     ) -> Self {
    772         Self {
    773             numerator,
    774             denominator,
    775         }
    776     }
    777 }
    778 
    779 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    780 pub struct Strut {
    781     pub window: Window,
    782     pub width: u32,
    783 }
    784 
    785 impl Strut {
    786     pub fn new(
    787         window: Window,
    788         width: u32,
    789     ) -> Self {
    790         Self {
    791             window,
    792             width,
    793         }
    794     }
    795 }
    796 
    797 impl PartialOrd for Strut {
    798     fn partial_cmp(
    799         &self,
    800         other: &Self,
    801     ) -> Option<std::cmp::Ordering> {
    802         Some(self.cmp(other))
    803     }
    804 }
    805 
    806 impl Ord for Strut {
    807     fn cmp(
    808         &self,
    809         other: &Self,
    810     ) -> std::cmp::Ordering {
    811         other.width.cmp(&self.width)
    812     }
    813 }