protected override void DoSync() { if (!AllowPlaceholders) { return; } using (UndoManager.AtomicChange) { uint left, right, top, bottom; uint row, col; Gtk.Widget w; Gtk.Widget[,] grid; Gtk.Table.TableChild tc; Gtk.Widget[] children; bool addedPlaceholders = false; children = table.Children; grid = new Gtk.Widget[NRows, NColumns]; // First fill in the placeholders in the grid. If we find any // placeholders covering more than one grid square, remove them. // (New ones will be created below.) foreach (Gtk.Widget child in children) { if (!(child is Placeholder)) { continue; } tc = table[child] as Gtk.Table.TableChild; left = tc.LeftAttach; right = tc.RightAttach; top = tc.TopAttach; bottom = tc.BottomAttach; if (right == left + 1 && bottom == top + 1) { grid[top, left] = child; } else { table.Remove(child); child.Destroy(); } } // Now fill in the real widgets, knocking out any placeholders // they overlap. (If there are real widgets that overlap // placeholders, neither will be knocked out, and the layout // will probably end up wrong as well. But this situation // happens at least temporarily during glade import.) foreach (Gtk.Widget child in children) { if (child is Placeholder) { continue; } tc = table[child] as Gtk.Table.TableChild; left = tc.LeftAttach; right = tc.RightAttach; top = tc.TopAttach; bottom = tc.BottomAttach; for (row = top; row < bottom; row++) { for (col = left; col < right; col++) { w = grid[row, col]; if (w is Placeholder) { table.Remove(w); w.Destroy(); } grid[row, col] = child; } } } // Scan each row; if there are any empty cells, fill them in // with placeholders. If a row contains only placeholders, then // set them all to expand vertically so the row won't collapse. // OTOH, if the row contains any real widget, set any placeholders // in that row to not expand vertically, so they don't force the // real widgets to expand further than they should. If any row // is vertically expandable, then the table as a whole is. vexpandable = false; for (row = 0; row < NRows; row++) { bool allPlaceholders = true; for (col = 0; col < NColumns; col++) { w = grid[row, col]; if (w == null) { w = CreatePlaceholder(); table.Attach(w, col, col + 1, row, row + 1); NotifyChildAdded(w); grid[row, col] = w; addedPlaceholders = true; } else if (!ChildVExpandable(w) || !AutoSize[w]) { allPlaceholders = false; } } for (col = 0; col < NColumns; col++) { w = grid[row, col]; if (!AutoSize[w]) { continue; } tc = table[w] as Gtk.Table.TableChild; // We can't play with the vertical expansion property of // widgets which span more than one row if (tc.BottomAttach != tc.TopAttach + 1) { continue; } Gtk.AttachOptions opts = allPlaceholders ? expandOpts : fillOpts; if (tc.YOptions != opts) { tc.YOptions = opts; } } if (allPlaceholders) { vexpandable = true; } } // Now do the same for columns and horizontal expansion (but we // don't have to worry about empty cells this time). hexpandable = false; for (col = 0; col < NColumns; col++) { bool allPlaceholders = true; for (row = 0; row < NRows; row++) { w = grid[row, col]; if (!ChildHExpandable(w) || !AutoSize[w]) { allPlaceholders = false; break; } } for (row = 0; row < NRows; row++) { w = grid[row, col]; if (!AutoSize[w]) { continue; } tc = table[w] as Gtk.Table.TableChild; // We can't play with the horizontal expansion property of // widgets which span more than one column if (tc.RightAttach != tc.LeftAttach + 1) { continue; } Gtk.AttachOptions opts = allPlaceholders ? expandOpts : fillOpts; if (tc.XOptions != opts) { tc.XOptions = opts; } } if (allPlaceholders) { hexpandable = true; } } if (addedPlaceholders) { EmitContentsChanged(); } } }
public void Attach(Gtk.Widget child, uint left_attach, uint right_attach, uint top_attach, uint bottom_attach, Gtk.AttachOptions xoptions, Gtk.AttachOptions yoptions, uint xpadding, uint ypadding) { gtk_table_attach(Handle, child == null ? IntPtr.Zero : child.Handle, left_attach, right_attach, top_attach, bottom_attach, (int)xoptions, (int)yoptions, xpadding, ypadding); }