1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
//! Grid layout - a geometry manager for arranging widgets.
//!
//! * also see the Tk [manual](https://www.tcl-lang.org/man/tcl8.6/TkCmd/grid.htm)
//!
//! The grid-layout is used in a "builder" style to layout a single widget:
//!
//! ```ignore
//! widget.grid()
//! .OPTION(VALUE) // 0 or more
//! .layout();
//! ```
//!
//! 1. `grid` is called first, to get the GridLayout instance.
//! 2. `layout` must be called last, to perform the layout.
//! 3. zero or more options are added to the GridLayout, to control the position
//! and layout of the widget.
//!
//! ## Example
//!
//! The following example places a label:
//!
//! ```ignore
//! label.grid() // starts layout definition
//! .row(1) // at row 1
//! .column(2) // at column 2
//! .column_span(3) // spanning three columns (i.e. 2,3,4)
//! .padx(5) // with 5 pixels horizontal spacing
//! .sticky(rstk::Sticky::E) // "attached" to the right-hand side
//! .layout(); // completes the layout
//! ```
//!
use super::widget;
use super::wish;
/// Refers to the settings for a GridLayout.
///
/// Apart from `layout`, the methods on this struct set the values of different
/// options in a builder style: call `layout` to finish the layout.
///
#[derive(Clone, Debug)]
pub struct GridLayout {
id: String,
column: Option<u64>,
column_span: Option<u64>,
ipadx: Option<u64>,
ipady: Option<u64>,
padx: Option<u64>,
pady: Option<u64>,
row: Option<u64>,
row_span: Option<u64>,
sticky: widget::Sticky,
}
impl GridLayout {
pub(super) fn new(wid: &str) -> GridLayout {
GridLayout {
id: String::from(wid),
column: None,
column_span: None,
ipadx: None,
ipady: None,
padx: None,
pady: None,
row: None,
row_span: None,
sticky: widget::Sticky::None,
}
}
/// Specifies the (0-indexed) column in which to place this widget.
pub fn column(&mut self, column: u64) -> &mut Self {
self.column = Some(column);
self
}
/// The number of columns this widget should span.
pub fn column_span(&mut self, span: u64) -> &mut Self {
self.column_span = Some(span);
self
}
/// Horizontal padding (inside content border).
pub fn ipadx(&mut self, pad: u64) -> &mut Self {
self.ipadx = Some(pad);
self
}
/// Vertical padding (inside content border).
pub fn ipady(&mut self, pad: u64) -> &mut Self {
self.ipady = Some(pad);
self
}
/// Horizontal padding (outside content border).
pub fn padx(&mut self, pad: u64) -> &mut Self {
self.padx = Some(pad);
self
}
/// Vertical padding (outside content border).
pub fn pady(&mut self, pad: u64) -> &mut Self {
self.pady = Some(pad);
self
}
/// Specifies the (0-indexed) row in which to place this widget.
pub fn row(&mut self, row: u64) -> &mut Self {
self.row = Some(row);
self
}
/// Number of rows this widget should span.
pub fn row_span(&mut self, span: u64) -> &mut Self {
self.row_span = Some(span);
self
}
/// When a widget is smaller than its containing space, this
/// setting controls how the widget is expanded or positioned
/// within that space.
pub fn sticky(&mut self, sticky: widget::Sticky) -> &mut Self {
self.sticky = sticky;
self
}
/// Called last to finally create the layout with the parameter values
/// set up by the builder.
pub fn layout(&self) {
let mut msg = format!("grid {} ", self.id);
if let Some(column) = self.column {
msg.push_str(&format!("-column {} ", column));
}
if let Some(span) = self.column_span {
msg.push_str(&format!("-columnspan {} ", span));
}
if let Some(pad) = self.ipadx {
msg.push_str(&format!("-ipadx {} ", pad));
}
if let Some(pad) = self.ipady {
msg.push_str(&format!("-ipady {} ", pad));
}
if let Some(pad) = self.padx {
msg.push_str(&format!("-padx {} ", pad));
}
if let Some(pad) = self.pady {
msg.push_str(&format!("-pady {} ", pad));
}
if let Some(row) = self.row {
msg.push_str(&format!("-row {} ", row));
}
if let Some(span) = self.row_span {
msg.push_str(&format!("-rowspan {} ", span));
}
if self.sticky != widget::Sticky::None {
msg.push_str(&format!("-sticky {} ", self.sticky));
}
wish::tell_wish(&msg);
}
}
/// Common functions for widgets that can be arranged using GridLayouts
pub trait TkGridLayout: widget::TkWidget {
/// Creates a GridLayout instance for placing this widget within its parent.
fn grid(&self) -> GridLayout {
GridLayout::new(self.id())
}
/// Sets properties for widget layout directly through Tk: see Tk
/// [manual](https://www.tcl-lang.org/man/tcl8.6/TkCmd/grid.htm#M9) for
/// options.
///
/// e.g. to set the "padx" value to "5" on a label:
///
/// ```ignore
/// label.grid_configure("padx", "5");
/// ```
///
fn grid_configure(&self, option: &str, value: &str) {
let msg = format!("grid configure {} -{} {{{}}}", self.id(), option, value);
wish::tell_wish(&msg);
}
/// Removes this widget from layout.
fn grid_forget(&self) {
let msg = format!("grid forget {}", self.id());
wish::tell_wish(&msg);
}
}