corner code looks correct but doesn't show up
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 10 Apr 2025 16:16:24 +0000 (09:16 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 10 Apr 2025 16:16:24 +0000 (09:16 -0700)
rust/pspp/src/output/pivot/output.rs

index a8f844fca43f1e13e63288dc59835271495b9d5b..297bf1a0776ba812c73f81246007bd297f33f602 100644 (file)
@@ -157,11 +157,13 @@ impl PivotTable {
     }
 
     pub fn output_body(&self, layer_indexes: &[usize], printing: bool) -> Table {
-        let headings =
-            EnumMap::from_fn(|axis| Headings::new(self, axis, layer_indexes, self.look.omit_empty));
+        let headings = EnumMap::from_fn(|axis| Headings::new(self, axis, layer_indexes));
 
         let data = Coord2::from_fn(|axis| headings[axis].width());
-        let stub = Coord2::from_fn(|axis| headings[!axis].height());
+        let mut stub = Coord2::from_fn(|axis| headings[!axis].height());
+        if headings[Axis2::Y].row_label_position == LabelPosition::Corner && stub.y() == 0 {
+            stub[Axis2::Y] = 1;
+        }
         let mut body = Table::new(
             Coord2::from_fn(|axis| data[axis] + stub[axis]),
             stub,
@@ -171,7 +173,7 @@ impl PivotTable {
         );
 
         for h in [Axis2::X, Axis2::Y] {
-            headings[h].render(&mut body, headings[!h].height(), h.into(), false, false);
+            headings[h].render(&mut body, stub[h], h.into(), false, false);
         }
 
         for (row_indexes, y) in headings[Axis2::Y].values.iter().zip(stub[Axis2::Y]..) {
@@ -193,6 +195,9 @@ impl PivotTable {
                 );
             }
         }
+
+        // Insert corner text, but only if there's a stub and only if row labels
+        // are not in the corner.
         if (self.corner_text.is_some() || self.look.row_label_position == LabelPosition::Corner)
             && stub.x() > 0
             && stub.y() > 0
@@ -368,6 +373,18 @@ impl<'a> Heading<'a> {
         })
     }
 
+    fn move_dimension_labels_to_corner(&mut self) -> bool {
+        if self.dimension.root.show_label {
+            for column in self.columns.iter_mut() {
+                column.groups.remove(0);
+            }
+            self.height -= 1;
+            true
+        } else {
+            false
+        }
+    }
+
     fn width(&self) -> usize {
         self.columns.len()
     }
@@ -383,6 +400,7 @@ impl<'a> Heading<'a> {
         rotate_inner_labels: bool,
         rotate_outer_labels: bool,
         inner: bool,
+        dimension_label_position: LabelPosition,
     ) {
         let v = !h;
 
@@ -476,29 +494,58 @@ impl<'a> Heading<'a> {
                 }
             }
         }
+
+        if dimension_label_position == LabelPosition::Corner {
+            dbg!(v_ofs..v_ofs + 1, 0..h_ofs);
+            dbg!(&self.dimension.root);
+            table.put(
+                Rect2::new(v_ofs..v_ofs + 1, 0..h_ofs),
+                CellInner {
+                    rotate: false,
+                    area: Area::Corner,
+                    value: self.dimension.root.name.clone(),
+                },
+            );
+            dbg!(&table);
+        }
     }
 }
 
 struct Headings<'a> {
     headings: Vec<Heading<'a>>,
+    row_label_position: LabelPosition,
     h: Axis2,
     values: AxisEnumeration,
 }
 
 impl<'a> Headings<'a> {
-    fn new(pt: &'a PivotTable, h: Axis2, layer_indexes: &[usize], omit_empty: bool) -> Self {
-        let column_enumeration = pt.enumerate_axis(h.into(), layer_indexes, omit_empty);
+    fn new(pt: &'a PivotTable, h: Axis2, layer_indexes: &[usize]) -> Self {
+        let column_enumeration = pt.enumerate_axis(h.into(), layer_indexes, pt.look.omit_empty);
+
+        let mut headings = pt.axes[h.into()]
+            .dimensions
+            .iter()
+            .copied()
+            .enumerate()
+            .rev()
+            .filter_map(|(axis_index, dim_index)| {
+                Heading::new(&pt.dimensions[dim_index], axis_index, &column_enumeration)
+            })
+            .collect::<Vec<_>>();
+
+        let row_label_position = if h == Axis2::Y
+            && pt.look.row_label_position == LabelPosition::Corner
+            && !headings.is_empty()
+            && headings[0].move_dimension_labels_to_corner()
+        {
+            LabelPosition::Corner
+        } else {
+            LabelPosition::Nested
+        };
+
         Self {
-            headings: pt.axes[h.into()]
-                .dimensions
-                .iter()
-                .copied()
-                .enumerate()
-                .rev()
-                .filter_map(|(axis_index, dim_index)| {
-                    Heading::new(&pt.dimensions[dim_index], axis_index, &column_enumeration)
-                })
-                .collect(),
+            headings,
+            row_label_position,
             h,
             values: column_enumeration,
         }
@@ -530,8 +577,18 @@ impl<'a> Headings<'a> {
         vrules[0] = true;
         vrules[n_columns] = true;
 
+        // The first heading takes the axis's row label position, the remainder
+        // are all nested.
+        let dimension_label_positions = std::iter::once(self.row_label_position)
+            .chain(std::iter::repeat(LabelPosition::Nested));
+
         let mut v_ofs = 0;
-        for (index, heading) in self.headings.iter().enumerate() {
+        for ((index, heading), dimension_label_position) in self
+            .headings
+            .iter()
+            .enumerate()
+            .zip(dimension_label_positions)
+        {
             let inner = index == self.headings.len() - 1;
             heading.render(
                 table,
@@ -543,6 +600,7 @@ impl<'a> Headings<'a> {
                 rotate_inner_labels,
                 rotate_outer_labels,
                 inner,
+                dimension_label_position,
             );
             v_ofs += heading.height;
             if !inner {